Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 1 addition & 39 deletions Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -724,57 +724,19 @@ struct StackCodegen {
switch type {
case .string, .int, .uint, .bool, .float, .double,
.jsObject(nil), .jsValue, .swiftStruct, .swiftHeapObject, .unsafePointer,
.swiftProtocol, .caseEnum, .associatedValueEnum, .rawValueEnum, .array:
.swiftProtocol, .caseEnum, .associatedValueEnum, .rawValueEnum, .array, .dictionary:
return "\(raw: type.swiftType).bridgeJSStackPop()"
case .jsObject(let className?):
return "\(raw: className)(unsafelyWrapping: JSObject.bridgeJSStackPop())"
case .nullable(let wrappedType, let kind):
return liftNullableExpression(wrappedType: wrappedType, kind: kind)
case .dictionary(let valueType):
return liftDictionaryExpression(valueType: valueType)
case .closure:
return "JSObject.bridgeJSStackPop()"
case .void, .namespaceEnum:
return "()"
}
}

func liftDictionaryExpression(valueType: BridgeType) -> ExprSyntax {
switch valueType {
case .jsObject(let className?) where className != "JSObject":
return """
{
let __dict = [String: JSObject].bridgeJSStackPop()
return __dict.mapValues { \(raw: className)(unsafelyWrapping: $0) }
}()
"""
case .nullable, .closure:
return liftDictionaryExpressionInline(valueType: valueType)
case .void, .namespaceEnum:
fatalError("Invalid dictionary value type: \(valueType)")
default:
return "[String: \(raw: valueType.swiftType)].bridgeJSStackPop()"
}
}

private func liftDictionaryExpressionInline(valueType: BridgeType) -> ExprSyntax {
let valueLift = liftExpression(for: valueType)
let swiftTypeName = valueType.swiftType
return """
{
let __count = Int(_swift_js_pop_i32())
var __result: [String: \(raw: swiftTypeName)] = [:]
__result.reserveCapacity(__count)
for _ in 0..<__count {
let __value = \(valueLift)
let __key = String.bridgeJSStackPop()
__result[__key] = __value
}
return __result
}()
"""
}

private func liftNullableExpression(wrappedType: BridgeType, kind: JSOptionalKind) -> ExprSyntax {
let typeName = kind == .null ? "Optional" : "JSUndefinedOr"
switch wrappedType {
Expand Down
54 changes: 54 additions & 0 deletions Tests/BridgeJSRuntimeTests/DictionarySupportTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@_spi(BridgeJS) import JavaScriptKit
import XCTest

@JSClass struct DictionarySupportImports {
@JSFunction static func jsRoundTripDictionaryInt(_ values: [String: Int]) throws(JSException) -> [String: Int]
@JSFunction static func jsRoundTripDictionaryBool(_ values: [String: Bool]) throws(JSException) -> [String: Bool]
@JSFunction static func jsRoundTripDictionaryDouble(
_ values: [String: Double]
) throws(JSException) -> [String: Double]
@JSFunction static func jsRoundTripDictionaryJSObject(
_ values: [String: JSObject]
) throws(JSException) -> [String: JSObject]
@JSFunction static func jsRoundTripDictionaryJSValue(
_ values: [String: JSValue]
) throws(JSException) -> [String: JSValue]
@JSFunction static func jsRoundTripDictionaryDoubleArray(
_ values: [String: [Double]]
) throws(JSException) -> [String: [Double]]
}

final class DictionarySupportTests: XCTestCase {

private func roundTripTest<T: Equatable>(_ fn: ([String: T]) throws -> [String: T], _ input: [String: T]) throws {
let result = try fn(input)
XCTAssertEqual(result, input)
}

func testRoundTripDictionaryInt() throws {
try roundTripTest(DictionarySupportImports.jsRoundTripDictionaryInt, ["a": 1, "b": 2])
}

func testRoundTripDictionaryBool() throws {
try roundTripTest(DictionarySupportImports.jsRoundTripDictionaryBool, ["yes": true, "no": false])
}

func testRoundTripDictionaryDouble() throws {
try roundTripTest(DictionarySupportImports.jsRoundTripDictionaryDouble, ["pi": 3.14, "tau": 6.28])
}

func testRoundTripDictionaryJSObject() throws {
try roundTripTest(DictionarySupportImports.jsRoundTripDictionaryJSObject, ["global": JSObject.global])
}

func testRoundTripDictionaryJSValue() throws {
try roundTripTest(
DictionarySupportImports.jsRoundTripDictionaryJSValue,
["number": .number(123.5), "boolean": .boolean(true), "string": .string("hello"), "null": .null]
)
}

func testRoundTripDictionaryDoubleArray() throws {
try roundTripTest(DictionarySupportImports.jsRoundTripDictionaryDoubleArray, ["xs": [1.0, 2.5], "ys": []])
}
}
96 changes: 0 additions & 96 deletions Tests/BridgeJSRuntimeTests/DictionaryTests.swift

This file was deleted.

Loading