From bcdc44dc76ac668166050ffdc154d9950cc3df85 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 10 Aug 2026 15:32:57 +0200 Subject: [PATCH 1/6] BridgeJS: Support generic functions on imported JS APIs --- Benchmarks/Sources/Generated/BridgeJS.swift | 66 +- Examples/Embedded/Package.swift | 3 + .../Embedded/Sources/EmbeddedApp/main.swift | 18 + Examples/Embedded/index.html | 8 +- .../PlayBridgeJS/Generated/BridgeJS.swift | 46 +- Plugins/BridgeJS/README.md | 2 +- .../Sources/BridgeJSCore/ExportSwift.swift | 109 +- .../Sources/BridgeJSCore/ImportTS.swift | 79 +- .../BridgeJSCore/SwiftToSkeleton.swift | 256 +++- .../Sources/BridgeJSLink/BridgeJSLink.swift | 239 ++- .../Sources/BridgeJSLink/JSGlueGen.swift | 577 +++++--- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 171 ++- .../Sources/BridgeJSTool/BridgeJSTool.swift | 5 +- .../BridgeJSToolInternal.swift | 3 +- .../BridgeJSCodegenTests/Alias.json | 2 + .../BridgeJSCodegenTests/Alias.swift | 12 + .../BridgeJSCodegenTests/AliasInClosure.json | 1 + .../BridgeJSCodegenTests/AliasInClosure.swift | 4 + .../BridgeJSCodegenTests/ArrayTypes.swift | 12 + .../BridgeJSCodegenTests/Async.swift | 12 + .../AsyncAssociatedValueEnum.swift | 4 + .../ClassWithNestedTypes.swift | 8 + .../DefaultParameters.swift | 12 + .../DictionaryTypes.swift | 4 + .../BridgeJSCodegenTests/DocComments.swift | 8 + .../BridgeJSCodegenTests/EnumAlias.json | 1 + .../BridgeJSCodegenTests/EnumAlias.swift | 4 + .../EnumAssociatedValue.swift | 44 + .../EnumAssociatedValueImport.swift | 4 + .../BridgeJSCodegenTests/EnumCase.swift | 16 + .../BridgeJSCodegenTests/EnumCaseImport.swift | 4 + .../EnumNamespace.Global.swift | 16 + .../BridgeJSCodegenTests/EnumNamespace.swift | 16 + .../BridgeJSCodegenTests/EnumRawType.swift | 48 + .../ImportedTypeInExportedInterface.swift | 4 + .../BridgeJSCodegenTests/JSNameOverride.swift | 8 + .../BridgeJSCodegenTests/NestedType.swift | 8 + .../BridgeJSCodegenTests/Protocol.swift | 16 + .../StaticFunctions.Global.swift | 8 + .../StaticFunctions.swift | 8 + .../StaticProperties.Global.swift | 4 + .../StaticProperties.swift | 4 + .../StructWithNestedTypes.swift | 28 + .../BridgeJSCodegenTests/SwiftClosure.swift | 20 + .../BridgeJSCodegenTests/SwiftStruct.swift | 36 + .../SwiftStructImports.swift | 4 + .../BridgeJSCodegenTests/UnsafePointer.swift | 4 + .../BridgeJSLinkTests/Alias.d.ts | 1 + .../__Snapshots__/BridgeJSLinkTests/Alias.js | 395 ++++- .../BridgeJSLinkTests/AliasInClosure.d.ts | 1 + .../BridgeJSLinkTests/AliasInClosure.js | 1 + .../BridgeJSLinkTests/ArrayTypes.d.ts | 1 + .../BridgeJSLinkTests/ArrayTypes.js | 1290 ++++++++--------- .../BridgeJSLinkTests/Async.d.ts | 1 + .../__Snapshots__/BridgeJSLinkTests/Async.js | 336 ++++- .../AsyncAssociatedValueEnum.d.ts | 1 + .../AsyncAssociatedValueEnum.js | 1 + .../BridgeJSLinkTests/AsyncImport.d.ts | 1 + .../BridgeJSLinkTests/AsyncStaticImport.d.ts | 1 + .../ClassWithNestedTypes.d.ts | 1 + .../BridgeJSLinkTests/ClassWithNestedTypes.js | 1 + .../BridgeJSLinkTests/DefaultParameters.d.ts | 1 + .../BridgeJSLinkTests/DefaultParameters.js | 431 ++++-- .../BridgeJSLinkTests/DictionaryTypes.d.ts | 1 + .../BridgeJSLinkTests/DictionaryTypes.js | 538 ++++--- .../BridgeJSLinkTests/DocComments.d.ts | 1 + .../BridgeJSLinkTests/DocComments.js | 1 + .../BridgeJSLinkTests/EnumAlias.d.ts | 1 + .../BridgeJSLinkTests/EnumAlias.js | 1 + .../EnumAssociatedValue.d.ts | 1 + .../BridgeJSLinkTests/EnumAssociatedValue.js | 629 +++++--- .../EnumAssociatedValueImport.d.ts | 1 + .../EnumAssociatedValueImport.js | 1 + .../BridgeJSLinkTests/EnumCase.d.ts | 1 + .../BridgeJSLinkTests/EnumCase.js | 1 + .../BridgeJSLinkTests/EnumCaseImport.d.ts | 1 + .../BridgeJSLinkTests/EnumCaseImport.js | 1 + .../EnumNamespace.Global.d.ts | 1 + .../BridgeJSLinkTests/EnumNamespace.Global.js | 1 + .../BridgeJSLinkTests/EnumNamespace.d.ts | 1 + .../BridgeJSLinkTests/EnumNamespace.js | 1 + .../BridgeJSLinkTests/EnumRawType.d.ts | 1 + .../BridgeJSLinkTests/EnumRawType.js | 351 ++++- .../BridgeJSLinkTests/FixedWidthIntegers.d.ts | 1 + .../BridgeJSLinkTests/GlobalGetter.d.ts | 1 + .../BridgeJSLinkTests/GlobalThisImports.d.ts | 1 + .../IdentityModeClass.ConfigPointer.d.ts | 1 + .../IdentityModeClass.PerClass.d.ts | 1 + .../BridgeJSLinkTests/IdentityModeClass.d.ts | 1 + .../BridgeJSLinkTests/ImportArray.d.ts | 1 + .../BridgeJSLinkTests/ImportArray.js | 393 ++++- .../ImportedTypeInExportedInterface.d.ts | 1 + .../ImportedTypeInExportedInterface.js | 452 +++++- .../InvalidPropertyNames.d.ts | 1 + .../BridgeJSLinkTests/JSClass.d.ts | 1 + .../JSClassStaticFunctions.d.ts | 1 + .../BridgeJSLinkTests/JSImportBareModule.d.ts | 1 + .../JSImportBareModuleFallback.d.ts | 1 + .../BridgeJSLinkTests/JSImportModule.d.ts | 1 + .../BridgeJSLinkTests/JSNameOverride.d.ts | 1 + .../BridgeJSLinkTests/JSNameOverride.js | 1 + .../BridgeJSLinkTests/JSTypedArrayTypes.d.ts | 1 + .../BridgeJSLinkTests/JSValue.d.ts | 1 + .../BridgeJSLinkTests/JSValue.js | 306 +++- .../BridgeJSLinkTests/MixedGlobal.d.ts | 1 + .../BridgeJSLinkTests/MixedModules.d.ts | 1 + .../BridgeJSLinkTests/MixedPrivate.d.ts | 1 + .../BridgeJSLinkTests/Namespaces.Global.d.ts | 1 + .../BridgeJSLinkTests/Namespaces.Global.js | 330 ++++- .../BridgeJSLinkTests/Namespaces.d.ts | 1 + .../BridgeJSLinkTests/Namespaces.js | 330 ++++- .../BridgeJSLinkTests/NestedType.d.ts | 1 + .../BridgeJSLinkTests/NestedType.js | 1 + .../BridgeJSLinkTests/Optionals.d.ts | 1 + .../BridgeJSLinkTests/Optionals.js | 398 ++++- .../PrimitiveParameters.d.ts | 1 + .../BridgeJSLinkTests/PrimitiveReturn.d.ts | 1 + .../BridgeJSLinkTests/PropertyTypes.d.ts | 1 + .../BridgeJSLinkTests/Protocol.d.ts | 1 + .../BridgeJSLinkTests/Protocol.js | 505 ++++++- .../BridgeJSLinkTests/ProtocolInClosure.d.ts | 1 + .../StaticFunctions.Global.d.ts | 1 + .../StaticFunctions.Global.js | 1 + .../BridgeJSLinkTests/StaticFunctions.d.ts | 1 + .../BridgeJSLinkTests/StaticFunctions.js | 1 + .../StaticProperties.Global.d.ts | 1 + .../StaticProperties.Global.js | 1 + .../BridgeJSLinkTests/StaticProperties.d.ts | 1 + .../BridgeJSLinkTests/StaticProperties.js | 1 + .../BridgeJSLinkTests/StringParameter.d.ts | 1 + .../BridgeJSLinkTests/StringReturn.d.ts | 1 + .../StructWithNestedTypes.d.ts | 1 + .../StructWithNestedTypes.js | 1 + .../BridgeJSLinkTests/SwiftClass.d.ts | 1 + .../BridgeJSLinkTests/SwiftClosure.d.ts | 1 + .../BridgeJSLinkTests/SwiftClosure.js | 239 ++- .../SwiftClosureImports.d.ts | 1 + .../BridgeJSLinkTests/SwiftStruct.d.ts | 1 + .../BridgeJSLinkTests/SwiftStruct.js | 457 ++++-- .../BridgeJSLinkTests/SwiftStructImports.d.ts | 1 + .../BridgeJSLinkTests/SwiftStructImports.js | 317 +++- .../SwiftTypedClosureAccess.d.ts | 1 + .../BridgeJSLinkTests/Throws.d.ts | 1 + .../BridgeJSLinkTests/UnsafePointer.d.ts | 1 + .../BridgeJSLinkTests/UnsafePointer.js | 1 + .../VoidParameterVoidReturn.d.ts | 1 + Plugins/PackageToJS/Templates/instantiate.js | 10 +- .../JavaScriptKit/BridgeJSIntrinsics.swift | 99 ++ .../BridgeJS/Generating-from-TypeScript.md | 2 +- .../Importing-JS-Function.md | 14 +- .../Articles/BridgeJS/Supported-Types.md | 4 + .../Generated/BridgeJS.swift | 51 +- .../Generated/BridgeJS.swift | 331 ++++- .../Generated/JavaScript/BridgeJS.json | 4 + .../javascriptkit-508-counterproposal.html | 413 ++++++ .../2026-06-17-bridgejs-phase1-early-dts.md | 374 +++++ .../2026-06-17-bridgejs-phase2-js-snippets.md | 593 ++++++++ ...026-06-17-bridgejs-phase3-cross-package.md | 353 +++++ ...6-17-bridgejs-phase4-per-target-modules.md | 188 +++ 159 files changed, 10111 insertions(+), 2070 deletions(-) create mode 100644 docs/superpowers/javascriptkit-508-counterproposal.html create mode 100644 docs/superpowers/plans/2026-06-17-bridgejs-phase1-early-dts.md create mode 100644 docs/superpowers/plans/2026-06-17-bridgejs-phase2-js-snippets.md create mode 100644 docs/superpowers/plans/2026-06-17-bridgejs-phase3-cross-package.md create mode 100644 docs/superpowers/plans/2026-06-17-bridgejs-phase4-per-target-modules.md diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index 384ca35a2..81888845b 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -2179,6 +2179,34 @@ fileprivate func _bjs_ArrayRoundtrip_wrap_extern(_ pointer: UnsafeMutableRawPoin return _bjs_ArrayRoundtrip_wrap_extern(pointer) } +extension SimpleStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SimpleStruct.bridgeJSMakeTypeHandle() +} + +extension Address: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Address.bridgeJSMakeTypeHandle() +} + +extension Person: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Person.bridgeJSMakeTypeHandle() +} + +extension ComplexStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexStruct.bridgeJSMakeTypeHandle() +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +extension ComplexResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexResult.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "Benchmarks", name: "bjs_benchmarkHelperNoop") fileprivate func bjs_benchmarkHelperNoop_extern() -> Void @@ -2238,4 +2266,40 @@ func _$benchmarkRunner(_ name: String, _ body: JSObject) throws(JSException) -> if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_Benchmarks_register_type_handles") +fileprivate func _bjs_Benchmarks_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_Benchmarks_register_type_handles") +public func _bjs_Benchmarks_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + SimpleStruct.bridgeJSTypeID, + Address.bridgeJSTypeID, + Person.bridgeJSTypeID, + ComplexStruct.bridgeJSTypeID, + Point.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ComplexResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_Benchmarks_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Examples/Embedded/Package.swift b/Examples/Embedded/Package.swift index 42702394a..1f88a8947 100644 --- a/Examples/Embedded/Package.swift +++ b/Examples/Embedded/Package.swift @@ -16,6 +16,9 @@ let package = Package( swiftSettings: [ .enableExperimentalFeature("Extern") ], + plugins: [ + .plugin(name: "BridgeJS", package: "JavaScriptKit") + ] ) ], swiftLanguageModes: [.v5] diff --git a/Examples/Embedded/Sources/EmbeddedApp/main.swift b/Examples/Embedded/Sources/EmbeddedApp/main.swift index 5e7f01a3c..c3e0dd3cd 100644 --- a/Examples/Embedded/Sources/EmbeddedApp/main.swift +++ b/Examples/Embedded/Sources/EmbeddedApp/main.swift @@ -1,5 +1,12 @@ import JavaScriptKit +@JS struct CounterLabel { + var count: Int + var text: String +} + +@JSFunction func echoValue(_ value: T) throws(JSException) -> T + let alert = JSObject.global.alert.object! let document = JSObject.global.document @@ -46,6 +53,17 @@ _ = encoderContainer.appendChild(textInputElement) _ = encoderContainer.appendChild(encodeResultElement) _ = document.body.appendChild(encoderContainer) +let genericResultElement = document.createElement("pre") +do { + let number = try echoValue(42) + let text = try echoValue("hello") + let label = try echoValue(CounterLabel(count: number, text: text)) + genericResultElement.innerText = .string("Generic import round-trip: \(label.text) \(label.count)") +} catch { + genericResultElement.innerText = "Generic import round-trip failed" +} +_ = document.body.appendChild(genericResultElement) + func print(_ message: String) { _ = JSObject.global.console.log(message) } diff --git a/Examples/Embedded/index.html b/Examples/Embedded/index.html index 93868214d..d280d7067 100644 --- a/Examples/Embedded/index.html +++ b/Examples/Embedded/index.html @@ -8,7 +8,13 @@ diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index 10976f793..dff715c64 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift @@ -231,6 +231,18 @@ fileprivate func _bjs_PlayBridgeJS_wrap_extern(_ pointer: UnsafeMutableRawPointe return _bjs_PlayBridgeJS_wrap_extern(pointer) } +extension PlayBridgeJSOutput: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PlayBridgeJSOutput.bridgeJSMakeTypeHandle() +} + +extension PlayBridgeJSDiagnostic: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PlayBridgeJSDiagnostic.bridgeJSMakeTypeHandle() +} + +extension PlayBridgeJSResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PlayBridgeJSResult.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "PlayBridgeJS", name: "bjs_createTS2Swift") fileprivate func bjs_createTS2Swift_extern() -> Int32 @@ -274,4 +286,36 @@ func _$TS2Swift_convert(_ self: JSObject, _ ts: String) throws(JSException) -> S throw error } return String.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_PlayBridgeJS_register_type_handles") +fileprivate func _bjs_PlayBridgeJS_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_PlayBridgeJS_register_type_handles") +public func _bjs_PlayBridgeJS_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PlayBridgeJSOutput.bridgeJSTypeID, + PlayBridgeJSDiagnostic.bridgeJSTypeID, + PlayBridgeJSResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_PlayBridgeJS_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/README.md b/Plugins/BridgeJS/README.md index 9e1e0aa08..0905695c5 100644 --- a/Plugins/BridgeJS/README.md +++ b/Plugins/BridgeJS/README.md @@ -98,7 +98,7 @@ graph LR | `Dictionary` | `Record` | - | [#495](https://github.com/swiftwasm/JavaScriptKit/issues/495) | | `Set` | `Set` | - | [#397](https://github.com/swiftwasm/JavaScriptKit/issues/397) | | `Foundation.URL` | `string` | - | [#496](https://github.com/swiftwasm/JavaScriptKit/issues/496) | -| Generics | - | - | [#398](https://github.com/swiftwasm/JavaScriptKit/issues/398) | +| Generic function or method (`T`, `[T]`, `T?`, `[String: T]`) | `(value: T): T` | Depends on `T` | ✅ imports only ([#398](https://github.com/swiftwasm/JavaScriptKit/issues/398) for exports) | ### Import-specific (TypeScript -> Swift) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 2cc551857..e4d0f5b02 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -91,6 +91,15 @@ public class ExportSwift { } } + withSpan("Render Generic Bridgeable Conformances") { [self] in + // Emitted unconditionally: a module cannot know whether a dependent + // module passes its types to a generic imported function. + let genericConformanceCodegen = GenericConformanceCodegen() + for entry in skeleton.genericBridgeableTypeEntries { + decls.append(contentsOf: genericConformanceCodegen.renderConformance(typeName: entry.swiftName)) + } + } + try withSpan("Render Async Promise Helpers") { [self] in let asyncResolveTypes = skeleton.asyncPromiseResolveReturnTypes if !asyncResolveTypes.isEmpty { @@ -875,6 +884,63 @@ public class ExportSwift { } } +// MARK: - GenericConformanceCodegen + +/// Renders `BridgedSwiftGenericBridgeable` conformances for `@JS` types so they +/// can be used as the generic argument of a generic imported `@JSFunction`. +struct GenericConformanceCodegen { + func renderConformance(typeName: String) -> [DeclSyntax] { + let printer = CodeFragmentPrinter() + printer.write("extension \(typeName): BridgedSwiftGenericBridgeable {") + printer.indent { + printer.write( + "@_spi(BridgeJS) public static let bridgeJSTypeHandle = \(typeName).bridgeJSMakeTypeHandle()" + ) + } + printer.write("}") + return ["\(raw: printer.lines.joined(separator: "\n"))"] + } +} + +// MARK: - GenericTypeRegistrationCodegen + +/// Renders the `bjs__register_type_handles` wasm export: it lowers each +/// registered type's `bridgeJSTypeID` into a buffer, in the canonical order of +/// `BridgeJSSkeleton.typeRegistrationEntries`, and passes it to the JS import +/// hook of the same name, which pairs the IDs with its codec array by index. +public struct GenericTypeRegistrationCodegen { + public init() {} + + public func render(for skeleton: BridgeJSSkeleton) -> String? { + guard let entries = skeleton.typeRegistrationEntries else { return nil } + let abiName = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) + let printer = CodeFragmentPrinter() + printer.write("#if arch(wasm32)") + printer.write("@_extern(wasm, module: \"bjs\", name: \"\(abiName)\")") + printer.write("fileprivate func _\(abiName)_extern(_ base: UnsafePointer?, _ count: Int32)") + printer.nextLine() + printer.write("@_expose(wasm, \"\(abiName)\")") + printer.write("public func _\(abiName)() {") + printer.indent { + printer.write("let typeIds: [Int32] = [") + printer.indent { + for entry in entries { + printer.write("\(entry.swiftName).bridgeJSTypeID,") + } + } + printer.write("]") + printer.write("typeIds.withUnsafeBufferPointer { buffer in") + printer.indent { + printer.write("_\(abiName)_extern(buffer.baseAddress, Int32(buffer.count))") + } + printer.write("}") + } + printer.write("}") + printer.write("#endif") + return printer.lines.joined(separator: "\n") + } +} + // MARK: - StackCodegen /// Helper for stack-based lifting and lowering operations. @@ -896,6 +962,10 @@ struct StackCodegen { return "JSObject.bridgeJSStackPop()" case .void, .namespaceEnum: return "()" + case .generic: + fatalError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } @@ -908,7 +978,7 @@ struct StackCodegen { return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSStackPop()" case .jsObject(let className?): return "\(raw: typeName).bridgeJSStackPop().map { \(raw: className)(unsafelyWrapping: $0) }" - case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol: + case .nullable, .void, .namespaceEnum, .closure, .unsafePointer, .swiftProtocol, .generic: fatalError("Invalid nullable wrapped type: \(wrappedType)") } } @@ -941,6 +1011,10 @@ struct StackCodegen { return lowerArrayStatements(elementType: elementType, accessor: accessor, varPrefix: varPrefix) case .dictionary(let valueType): return lowerDictionaryStatements(valueType: valueType, accessor: accessor, varPrefix: varPrefix) + case .generic: + fatalError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } @@ -1596,12 +1670,34 @@ extension BridgeType { case .associatedValueEnum: return ["_BridgedSwiftAssociatedValueEnum"] case .rawValueEnum, .void, .unsafePointer, .namespaceEnum, - .swiftProtocol, .closure, .nullable, .array, .dictionary, .alias: + .swiftProtocol, .closure, .nullable, .array, .dictionary, .alias, .generic: // Not supported yet. return nil } } + /// Stack expressions for bare `T` and `T?`, the only generic shapes that + /// cannot reuse the concrete emission: `bridgeJSLowerParameter()` names + /// per-type members that the generic constraint erases to the stack, so + /// `bridgeJSStackPush()`/`bridgeJSStackPop()` is the shared spelling. + /// `[T]` and `[String: T]` go through the ordinary paths via the `Array` + /// and `Dictionary` stack conformances. + var genericStackPopExpression: String? { + switch self { + case .generic(let name): return "\(name).bridgeJSStackPop()" + case .nullable(.generic(let name), _): return "Optional<\(name)>.bridgeJSStackPop()" + default: return nil + } + } + + func genericStackPushStatement(value: String) -> String? { + switch self { + case .generic, .nullable(.generic, _): + return "\(value).bridgeJSStackPush()" + default: return nil + } + } + var swiftType: String { switch self { case .bool: return "Bool" @@ -1631,6 +1727,7 @@ extension BridgeType { let closureType = "(\(paramTypes))\(effectsStr) -> \(signature.returnType.swiftType)" return useJSTypedClosure ? "JSTypedClosure<\(closureType)>" : closureType case .alias(let name, _): return name + case .generic(let name): return name } } @@ -1717,6 +1814,10 @@ extension BridgeType { return LiftingIntrinsicInfo(parameters: []) case .alias(_, let underlying): return try underlying.liftParameterInfo() + case .generic: + throw BridgeJSCoreError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } @@ -1770,6 +1871,10 @@ extension BridgeType { return .array case .alias(_, let underlying): return try underlying.loweringReturnInfo() + case .generic: + throw BridgeJSCoreError( + "Generic parameters are only supported on imported declarations, not exported concrete-type codegen" + ) } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 286352915..cb5a88e93 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -143,6 +143,11 @@ public struct ImportTS { } func lowerParameter(param: Parameter) throws { + if let genericPush = param.type.genericStackPushStatement(value: param.name) { + stackLoweringStmts.insert(genericPush, at: 0) + return + } + let loweringInfo = try param.type.loweringParameterInfo(context: context) switch param.type { @@ -237,6 +242,18 @@ public struct ImportTS { abiParameterForwardings.insert(contentsOf: ["resolveRef", "rejectRef"], at: 0) } + private func appendTypeIDParameter(index: Int, genericParameterName: String) { + let abiParamName = ABINameGenerator.genericTypeIdParameterName(index: index) + abiParameterSignatures.append((abiParamName, .i32)) + abiParameterForwardings.append("\(genericParameterName).bridgeJSTypeID") + } + + func appendTypeIDParameters(_ genericParameterNames: [String]) { + for (index, name) in genericParameterNames.enumerated() { + appendTypeIDParameter(index: index, genericParameterName: name) + } + } + func call() throws { for stmt in stackLoweringStmts { body.write(stmt.description) @@ -293,14 +310,18 @@ public struct ImportTS { body.write("return \(returnType.swiftType).bridgeJSLiftReturnFromSideChannel()") } else { let liftExpr: String - switch returnType { - case .closure(let signature, _): - liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)" - default: - if liftingInfo.valueToLift != nil { - liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)" - } else { - liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()" + if let genericPop = returnType.genericStackPopExpression { + liftExpr = genericPop + } else { + switch returnType { + case .closure(let signature, _): + liftExpr = "_BJS_Closure_\(signature.mangleName).bridgeJSLift(ret)" + default: + if liftingInfo.valueToLift != nil { + liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn(ret)" + } else { + liftExpr = "\(returnType.swiftType).bridgeJSLiftReturn()" + } } } body.write("return \(liftExpr)") @@ -359,7 +380,8 @@ public struct ImportTS { name: String, parameters: [Parameter], returnType: BridgeType, - effects: Effects + effects: Effects, + genericParameters: [String] = [] ) -> DeclSyntax { let printer = CodeFragmentPrinter() let signature = SwiftSignatureBuilder.buildFunctionSignature( @@ -368,7 +390,12 @@ public struct ImportTS { effects: effects, useWildcardLabels: true ) - printer.write("func \(name.backtickIfNeeded())\(signature) {") + let genericClause = + genericParameters.isEmpty + ? "" + : "<" + genericParameters.map { "\($0): BridgedSwiftGenericBridgeable" }.joined(separator: ", ") + + ">" + printer.write("func \(name.backtickIfNeeded())\(genericClause)\(signature) {") printer.indent { printer.write(lines: body.lines) } @@ -428,6 +455,7 @@ public struct ImportTS { for param in function.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(function.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -436,7 +464,8 @@ public struct ImportTS { name: Self.thunkName(function: function), parameters: function.parameters, returnType: function.returnType, - effects: function.effects + effects: function.effects, + genericParameters: function.genericParameterNames ) .with(\.leadingTrivia, Self.renderDocumentation(documentation: function.documentation)) ] @@ -457,6 +486,7 @@ public struct ImportTS { for param in method.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(method.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -465,7 +495,8 @@ public struct ImportTS { name: Self.thunkName(type: type, method: method), parameters: [selfParameter] + method.parameters, returnType: method.returnType, - effects: method.effects + effects: method.effects, + genericParameters: method.genericParameterNames ) ] } @@ -481,6 +512,7 @@ public struct ImportTS { for param in method.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(method.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -489,7 +521,8 @@ public struct ImportTS { name: Self.thunkName(type: type, method: method), parameters: method.parameters, returnType: method.returnType, - effects: method.effects + effects: method.effects, + genericParameters: method.genericParameterNames ) ] } @@ -505,6 +538,7 @@ public struct ImportTS { for param in constructor.parameters { try builder.lowerParameter(param: param) } + builder.appendTypeIDParameters(constructor.genericParameterNames) try builder.call() try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) @@ -513,7 +547,8 @@ public struct ImportTS { name: Self.thunkName(type: type), parameters: constructor.parameters, returnType: .jsObject(nil), - effects: effects + effects: effects, + genericParameters: constructor.genericParameterNames ) ] } @@ -932,9 +967,6 @@ extension BridgeType { return LoweringParameterInfo(loweredParameters: [("value", wasmType)]) case .associatedValueEnum: return LoweringParameterInfo(loweredParameters: [("caseId", .i32)]) - case .swiftStruct: - // `@JS struct` parameters always use the stack ABI (same as arrays/dictionaries). - return LoweringParameterInfo(loweredParameters: []) case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as parameters") case .nullable(let wrappedType, _): @@ -942,7 +974,10 @@ extension BridgeType { var params = [("isSome", WasmCoreType.i32)] params.append(contentsOf: wrappedInfo.loweredParameters) return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing) - case .array, .dictionary: + case .swiftStruct: + // `@JS struct` parameters always use the stack ABI (same as arrays/dictionaries). + return LoweringParameterInfo(loweredParameters: []) + case .array, .dictionary, .generic: return LoweringParameterInfo(loweredParameters: []) case .alias: preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching loweringParameterInfo") @@ -995,9 +1030,6 @@ extension BridgeType { return LiftingReturnInfo(valueToLift: wasmType) case .associatedValueEnum: return LiftingReturnInfo(valueToLift: .i32) - case .swiftStruct: - // `@JS struct` returns always use the stack ABI (same as arrays/dictionaries). - return LiftingReturnInfo(valueToLift: nil) case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as return values") case .nullable(let wrappedType, _): @@ -1008,7 +1040,10 @@ extension BridgeType { } let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) - case .array, .dictionary: + case .swiftStruct: + // `@JS struct` returns always use the stack ABI (same as arrays/dictionaries). + return LiftingReturnInfo(valueToLift: nil) + case .array, .dictionary, .generic: return LiftingReturnInfo(valueToLift: nil) case .alias: preconditionFailure("`.alias` must be resolved by `.unaliased` before reaching liftingReturnInfo") diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index bfd639ee6..f37bfb822 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -7,6 +7,79 @@ import BridgeJSUtilities import BridgeJSSkeleton #endif +/// Outcome of attempting to resolve a type as a reference to a generic parameter. +enum GenericParameterResolution { + case resolved(BridgeType) + /// A non-nil message is a hard diagnostic; `nil` means the type isn't generic + /// and the caller should fall back to normal type resolution. + case rejected(String?) +} + +func resolveGenericTypeReference( + for type: TypeSyntax, + genericParameterNames: [String] +) -> GenericParameterResolution { + if let identifier = type.as(IdentifierTypeSyntax.self), + identifier.genericArgumentClause == nil, + genericParameterNames.contains(identifier.name.text) + { + return .resolved(.generic(identifier.name.text)) + } + if let wrapped = wrappedGenericBridgeType(for: type, genericParameterNames: genericParameterNames) { + return .resolved(wrapped) + } + if !genericParameterNames.isEmpty, + let wrapped = wrappedGenericParameter(in: type, genericParameterNames: genericParameterNames) + { + return .rejected( + "Generic parameter '\(wrapped)' may only be used as a bare type; wrapping it beyond 'T?', '[T]' and '[String: T]' is not supported." + ) + } + return .rejected(nil) +} + +private func wrappedGenericParameter( + in type: TypeSyntax, + genericParameterNames: [String] +) -> String? { + for token in type.tokens(viewMode: .sourceAccurate) { + if case .identifier(let text) = token.tokenKind, genericParameterNames.contains(text) { + return text + } + } + return nil +} + +private func wrappedGenericBridgeType( + for type: TypeSyntax, + genericParameterNames: [String] +) -> BridgeType? { + func bareGenericName(_ inner: TypeSyntax) -> String? { + guard let identifier = inner.as(IdentifierTypeSyntax.self), + identifier.genericArgumentClause == nil, + genericParameterNames.contains(identifier.name.text) + else { + return nil + } + return identifier.name.text + } + if let arrayType = type.as(ArrayTypeSyntax.self), let name = bareGenericName(arrayType.element) { + return .array(.generic(name)) + } + if let optionalType = type.as(OptionalTypeSyntax.self), let name = bareGenericName(optionalType.wrappedType) { + return .nullable(.generic(name), .null) + } + if let dictType = type.as(DictionaryTypeSyntax.self), + let keyIdentifier = dictType.key.as(IdentifierTypeSyntax.self), + keyIdentifier.genericArgumentClause == nil, + keyIdentifier.name.text == "String", + let name = bareGenericName(dictType.value) + { + return .dictionary(.generic(name)) + } + return nil +} + /// Builds BridgeJS skeletons from Swift source files using SwiftSyntax walk for API collection. /// /// This is a shared entry point for producing: @@ -748,6 +821,11 @@ public final class SwiftToSkeleton { return name.unicodeScalars.dropFirst().allSatisfy { isIdentifierPart($0, isStart: false) } } + fileprivate static func isBridgeableGenericConstraint(_ constraint: String?) -> Bool { + constraint == "BridgedSwiftGenericBridgeable" + || constraint == "JavaScriptKit.BridgedSwiftGenericBridgeable" + } + } private enum ExportSwiftConstants { @@ -1219,10 +1297,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) continue } - if case .nullable(let wrappedType, _) = type, wrappedType.isOptional { - diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) - continue - } let name = param.secondName?.text ?? param.firstName.text let label = param.firstName.text @@ -1307,6 +1381,15 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return nil } + if let genericClause = node.genericParameterClause, let firstGenericParam = genericClause.parameters.first { + diagnose( + node: firstGenericParam, + message: + "Generic parameters on exported @JS functions are not supported yet. Generic functions are currently only supported on imported @JSFunction declarations." + ) + return nil + } + let name = node.name.text let jsName = extractValidatedJSName(from: jsAttribute) @@ -1784,6 +1867,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { message: "Class visibility must be at least internal" ) let classIdentityMode = extractIdentityMode(from: jsAttribute) + let isFinal = node.modifiers.contains { $0.name.tokenKind == .keyword(.final) } ? true : nil let exportedClass = ExportedClass( name: name, swiftCallName: swiftCallName, @@ -1793,7 +1877,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { properties: [], namespace: effectiveNamespace, identityMode: classIdentityMode, - documentation: extractDocumentation(from: node) + documentation: extractDocumentation(from: node), + isFinal: isFinal ) let uniqueKey = makeKey(name: name, namespace: effectiveNamespace) @@ -3204,24 +3289,101 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { // MARK: - Parsing Methods + /// Validates and collects the generic parameter names of an imported + /// `@JSFunction` declaration (function, method or initializer). + /// + /// Returns `nil` when a diagnostic was emitted; an empty array when the + /// declaration is not generic. + private func parseGenericParameterNames( + genericParameterClause: GenericParameterClauseSyntax?, + genericWhereClause: GenericWhereClauseSyntax?, + node: Syntax + ) -> [String]? { + var genericParameterNames: [String] = [] + if let genericParameterClause { + for genericParam in genericParameterClause.parameters { + let paramName = genericParam.name.text + let constraintText = genericParam.inheritedType?.trimmedDescription + guard SwiftToSkeleton.isBridgeableGenericConstraint(constraintText) else { + errors.append( + DiagnosticError( + node: Syntax(genericParam), + message: + "Generic parameter '\(paramName)' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with @JSFunction." + ) + ) + return nil + } + genericParameterNames.append(paramName) + } + } + if genericWhereClause != nil { + errors.append( + DiagnosticError( + node: node, + message: "'where' clauses are not supported on @JSFunction declarations." + ) + ) + return nil + } + return genericParameterNames + } + private func parseConstructor( _ initializer: InitializerDeclSyntax, typeName: String ) -> ImportedConstructorSkeleton? { guard - validateEffects(initializer.signature.effectSpecifiers, node: initializer, attributeName: "JSFunction") - != nil + let effects = validateEffects( + initializer.signature.effectSpecifiers, + node: initializer, + attributeName: "JSFunction" + ) + else { + return nil + } + guard + let genericParameterNames = parseGenericParameterNames( + genericParameterClause: initializer.genericParameterClause, + genericWhereClause: initializer.genericWhereClause, + node: Syntax(initializer) + ) else { return nil } + if !genericParameterNames.isEmpty && effects.isAsync { + errors.append( + DiagnosticError( + node: Syntax(initializer), + message: "Generic @JSFunction declarations cannot be 'async' yet." + ) + ) + return nil + } + let parameters = parseParameters( + from: initializer.signature.parameterClause, + genericParameterNames: genericParameterNames + ) + for genericName in genericParameterNames + where !parameters.contains(where: { $0.type.referencedGenericName == genericName }) { + errors.append( + DiagnosticError( + node: Syntax(initializer), + message: + "The generic parameter '\(genericName)' must be used in a parameter of a generic @JSFunction initializer." + ) + ) + return nil + } // Initializers without an explicit modifier inherit access from the // enclosing `@JSClass` (the user's example pattern: `public init(...)` // inside `public struct JSDocument`). let parentLevel = currentType?.accessLevel ?? .internal let accessLevel = Self.bridgeAccessLevel(from: initializer.modifiers, default: parentLevel) return ImportedConstructorSkeleton( - parameters: parseParameters(from: initializer.signature.parameterClause), - accessLevel: accessLevel + parameters: parameters, + accessLevel: accessLevel, + genericParameters: genericParameterNames.isEmpty ? nil : genericParameterNames ) } @@ -3239,6 +3401,16 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { return nil } + guard + let genericParameterNames = parseGenericParameterNames( + genericParameterClause: node.genericParameterClause, + genericWhereClause: node.genericWhereClause, + node: Syntax(node) + ) + else { + return nil + } + let baseName = SwiftToSkeleton.normalizeIdentifier(node.name.text) let extractedJSName = extractJSName(from: jsFunction) let from = extractJSImportFrom(from: jsFunction) @@ -3246,16 +3418,51 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { let jsName = extractedJSName?.memberName let name = baseName - let parameters = parseParameters(from: node.signature.parameterClause) + let parameters = parseParameters( + from: node.signature.parameterClause, + genericParameterNames: genericParameterNames + ) let returnType: BridgeType if let returnTypeSyntax = node.signature.returnClause?.type { - guard let resolved = withLookupErrors({ parent.lookupType(for: returnTypeSyntax, errors: &$0) }) else { + guard + let resolved = lookupTypeWithGenerics( + for: returnTypeSyntax, + genericParameterNames: genericParameterNames + ) + else { return nil } returnType = resolved } else { returnType = .void } + + if !genericParameterNames.isEmpty { + if effects.isAsync { + errors.append( + DiagnosticError( + node: node, + message: "Generic @JSFunction declarations cannot be 'async' yet." + ) + ) + return nil + } + for genericName in genericParameterNames { + let usedInParameter = parameters.contains { $0.type.referencedGenericName == genericName } + let usedInReturn = returnType.referencedGenericName == genericName + if !usedInParameter && !usedInReturn { + errors.append( + DiagnosticError( + node: node, + message: + "The generic parameter '\(genericName)' must be used in a parameter or return type of a generic @JSFunction declaration." + ) + ) + return nil + } + } + } + let accessLevel = Self.bridgeAccessLevel(from: node.modifiers) return ImportedFunctionSkeleton( name: name, @@ -3265,7 +3472,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { returnType: returnType, effects: effects, documentation: nil, - accessLevel: accessLevel + accessLevel: accessLevel, + genericParameters: genericParameterNames.isEmpty ? nil : genericParameterNames ) } @@ -3342,7 +3550,26 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { // MARK: - Type and Parameter Parsing - private func parseParameters(from clause: FunctionParameterClauseSyntax) -> [Parameter] { + private func lookupTypeWithGenerics( + for type: TypeSyntax, + genericParameterNames: [String] + ) -> BridgeType? { + switch resolveGenericTypeReference(for: type, genericParameterNames: genericParameterNames) { + case .resolved(let bridgeType): + return bridgeType + case .rejected(let message): + if let message { + errors.append(DiagnosticError(node: Syntax(type), message: message)) + return nil + } + return withLookupErrors { parent.lookupType(for: type, errors: &$0) } + } + } + + private func parseParameters( + from clause: FunctionParameterClauseSyntax, + genericParameterNames: [String] = [] + ) -> [Parameter] { clause.parameters.compactMap { param in let type = param.type if type.is(MissingTypeSyntax.self) { @@ -3354,7 +3581,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { ) return nil } - guard let bridgeType = withLookupErrors({ parent.lookupType(for: type, errors: &$0) }) else { + guard let bridgeType = lookupTypeWithGenerics(for: type, genericParameterNames: genericParameterNames) + else { return nil } let nameToken = param.secondName ?? param.firstName diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 6043f3cd1..13c323f2c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -31,6 +31,10 @@ public struct BridgeJSLink { skeletons.compactMap(\.exported).compactMap(\.identityMode).first ?? "none" } + var hasGenerics: Bool { + skeletons.contains { $0.imported?.hasGenericDeclarations ?? false } + } + /// Whether a class should use identity caching based on its annotation and the config default. private func shouldUseIdentityCache(for klass: ExportedClass) -> Bool { // Per-class annotation takes priority @@ -311,7 +315,7 @@ public struct BridgeJSLink { } private func generateVariableDeclarations() -> [String] { - return [ + var declarations: [String] = [ "let \(JSGlueVariableScope.reservedInstance);", "let \(JSGlueVariableScope.reservedMemory);", "let \(JSGlueVariableScope.reservedSetException);", @@ -335,10 +339,36 @@ public struct BridgeJSLink { "let \(JSGlueVariableScope.reservedTaStack) = [];", "const \(JSGlueVariableScope.reservedEnumHelpers) = {};", "const \(JSGlueVariableScope.reservedStructHelpers) = {};", + ] + if hasGenerics { + declarations.append("const \(JSGlueVariableScope.reservedCodecByTypeId) = new Map();") + declarations.append("let __bjs_typeHandlesRegistered = false;") + // Registration is hybrid eager+lazy. The registration exports + // execute Swift code, which must not happen before WASI + // initialization (setInstance runs earlier than that), so the + // instantiator exposes an `afterInitialize` hook that hosts call + // once the instance is initialized (the `instantiate.js` template + // does). The guard below keeps the lazy path — first generic call + // — as a fallback for instantiation paths that skip the hook. + declarations.append("function __bjs_registerTypeHandles() {") + declarations.append(" if (__bjs_typeHandlesRegistered) {") + declarations.append(" return;") + declarations.append(" }") + declarations.append(" __bjs_typeHandlesRegistered = true;") + for skeleton in skeletons { + guard skeleton.typeRegistrationEntries != nil else { continue } + let name = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) + declarations.append(" \(JSGlueVariableScope.reservedInstance).exports[\"\(name)\"]();") + } + declarations.append("}") + declarations.append(contentsOf: GenericJSCodegen.runtimeHelperDeclarations()) + } + declarations.append(contentsOf: [ "", "let _exports = null;", "let bjs = null;", - ] + ]) + return declarations } /// JS const (in the import glue scope) holding the `Symbol` under which a promise's @@ -375,6 +405,86 @@ public struct BridgeJSLink { printer.write(lines: lines) } + /// A print context detached from any thunk, used for codec literal emission. + private func makeCodecPrintContext(printer: CodeFragmentPrinter) -> IntrinsicJSFragment.PrintCodeContext { + IntrinsicJSFragment.PrintCodeContext( + scope: JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry), + printer: printer, + hasDirectAccessToSwiftClass: false, + classNamespaces: intrinsicRegistry.classNamespaces + ) + } + + /// Emits a `{ lower, lift }` codec literal for one bridgeable type. + /// `prefix` is prepended to the opening brace (e.g. an assignment) and + /// `suffix` is appended to the closing brace (e.g. `","` in an array). + private func appendGenericCodecLiteral( + type: BridgeType, + into printer: CodeFragmentPrinter, + prefix: String = "", + suffix: String = "," + ) throws { + try ContainerCodecJS.writeCodecLiteral( + type: type, + into: printer, + context: makeCodecPrintContext(printer: printer), + prefix: prefix, + suffix: suffix + ) + } + + /// Installs the per-module `bjs__register_type_handles` import + /// hooks. A module with a registration function always carries the wasm + /// import, so a hook is always installed; without generics anywhere in the + /// build it is a no-op and the registration export is never called. + private func generateTypeRegistrationHooks(into printer: CodeFragmentPrinter) throws { + for skeleton in skeletons { + guard skeleton.typeRegistrationEntries != nil else { continue } + let hookName = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) + guard hasGenerics else { + printer.write("bjs[\"\(hookName)\"] = function() {};") + continue + } + // The hooks resolve type IDs against the shared primitive codec table. + try ContainerCodecJS.registerPrimitiveCodecs(context: makeCodecPrintContext(printer: printer)) + let moduleEntries = skeleton.exported?.genericBridgeableTypeEntries ?? [] + printer.write("bjs[\"\(hookName)\"] = function(base, count) {") + try printer.indent { + // Same canonical order as the Swift registration function: + // primitives first, then the module's own types. + printer.write("const codecs = [") + printer.indent { + for primitive in BridgeType.genericBridgeablePrimitives { + printer.write("\(JSGlueVariableScope.reservedPrimitiveCodecs).\(primitive.token),") + } + } + printer.write("].concat([") + try printer.indent { + for entry in moduleEntries { + try appendGenericCodecLiteral(type: entry.bridgeType, into: printer) + } + } + printer.write("]);") + printer.write("if (count !== codecs.length) {") + printer.indent { + printer.write( + "throw new Error(\"BridgeJS: type handle registration mismatch for module '\(skeleton.moduleName)'\");" + ) + } + printer.write("}") + printer.write( + "const typeIds = new Int32Array(\(JSGlueVariableScope.reservedMemory).buffer, base >>> 0, count >>> 0);" + ) + printer.write("for (let i = 0; i < count; i++) {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedCodecByTypeId).set(typeIds[i], codecs[i]);") + } + printer.write("}") + } + printer.write("}") + } + } + private func generateAddImports(needsImportsObject: Bool) throws -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() let allStructs = skeletons.compactMap { $0.exported?.structs }.flatMap { $0 } @@ -544,6 +654,7 @@ public struct BridgeJSLink { printer.write("}") } } + try generateTypeRegistrationHooks(into: printer) // Always provided: the runtime's `_bjs_makePromise` imports it unconditionally. // The settlers are stored under a Symbol to avoid clashing with promise fields. @@ -1025,7 +1136,7 @@ public struct BridgeJSLink { self.renderExportedStructExportEntry(structDef) }, renderFunctionEntry: { function in - self.renderJSDoc(documentation: function.documentation, parameters: function.parameters) + return self.renderJSDoc(documentation: function.documentation, parameters: function.parameters) + [ "\(function.resolvedJSName)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ] @@ -1062,6 +1173,7 @@ public struct BridgeJSLink { printer.write(lines: [ "addImports: (importObject: WebAssembly.Imports) => void;", "setInstance: (instance: WebAssembly.Instance) => void;", + "afterInitialize?: () => void;", "createExports: (instance: WebAssembly.Instance) => Exports;", ]) } @@ -1200,6 +1312,19 @@ public struct BridgeJSLink { printer.write("},") } + // afterInitialize method: eager type-handle registration. Only emitted + // when the generic runtime exists; otherwise the hook is absent and + // callers use optional chaining. + if hasGenerics { + printer.indent { + printer.write("afterInitialize: () => {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedRegisterTypeHandles)();") + } + printer.write("},") + } + } + // createExports method printer.indent { printer.write(lines: [ @@ -1373,8 +1498,9 @@ public struct BridgeJSLink { // Add methods for method in type.methods { let methodName = method.resolvedJSName + let genericClause = renderGenericClause(method.genericParameterNames) let methodSignature = - "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(renderTSPropertyName(methodName))\(genericClause)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" printer.write(methodSignature) } @@ -1589,6 +1715,10 @@ public struct BridgeJSLink { return "(\(parameterSignatures.joined(separator: ", "))): \(returnTypeWithEffect)" } + private func renderGenericClause(_ genericParameterNames: [String]) -> String { + genericParameterNames.isEmpty ? "" : "<\(genericParameterNames.joined(separator: ", "))>" + } + private func renderTSPropertyName(_ name: String) -> String { // TypeScript allows quoted property names for keys that aren't valid identifiers. if name.range(of: #"^[$A-Z_][0-9A-Z_$]*$"#, options: [.regularExpression, .caseInsensitive]) != nil { @@ -2385,6 +2515,8 @@ extension BridgeJSLink { var parameterNames: [String] = [] var parameterForwardings: [String] = [] var returnExpr: String? + var genericCodecVariables: [String: String] = [:] + var genericTypeIdParameters: [String: String] = [:] let printContext: IntrinsicJSFragment.PrintCodeContext init( @@ -2410,7 +2542,36 @@ extension BridgeJSLink { parameterNames.append("self") } + func declareGenericCodecs(genericParameters: [String]) { + if !genericParameters.isEmpty { + // Generic call sites instantiate the shared container codec + // combinators with the codecs resolved from type IDs. + ContainerCodecJS.registerCombinators(scope: scope) + } + for genericParam in genericParameters { + let typeIdParam = scope.variable("\(genericParam.lowercased())TypeId") + let codecVar = scope.variable("codec\(genericParam)") + body.write("const \(codecVar) = __bjs_codecForTypeId(\(typeIdParam));") + genericCodecVariables[genericParam] = codecVar + genericTypeIdParameters[genericParam] = typeIdParam + } + } + func liftParameter(param: Parameter) throws { + if let name = param.type.referencedGenericName { + guard let codecVar = genericCodecVariables[name] else { + throw BridgeJSLinkError( + message: "Generic codec for '\(name)' was not declared before lifting parameter '\(param.name)'" + ) + } + let valueVar = scope.variable(param.name) + let liftExpr = + GenericJSCodegen.genericCodecLiftExpression(type: param.type, codec: codecVar) + ?? "\(codecVar).lift()" + body.write("const \(valueVar) = \(liftExpr);") + parameterForwardings.append(valueVar) + return + } let liftingFragment = try IntrinsicJSFragment.liftParameter(type: param.type, context: context) let valuesToLift: [String] if liftingFragment.parameters.count == 0 { @@ -2427,6 +2588,16 @@ extension BridgeJSLink { parameterForwardings.append(contentsOf: liftedValues) } + func liftParametersAndGenericTypeIds(_ parameters: [Parameter], genericParameters: [String]) throws { + declareGenericCodecs(genericParameters: genericParameters) + for param in parameters { + try liftParameter(param: param) + } + for genericParam in genericParameters { + parameterNames.append(genericTypeIdParameters[genericParam] ?? genericParam) + } + } + func renderFunction(name: String?) -> [String] { if effects.isAsync { return renderAsyncFunction(name: name) @@ -2503,6 +2674,25 @@ extension BridgeJSLink { body.write("\(callExpr).then(resolve, reject);") return } + if let name = returnType.referencedGenericName { + guard let codecVar = genericCodecVariables[name] else { + throw BridgeJSLinkError( + message: "Generic codec for return type '\(name)' was not declared before the call" + ) + } + let resultVariable = scope.variable("ret") + body.write("let \(resultVariable) = \(callExpr);") + let lowerStmt = + GenericJSCodegen.genericCodecLowerStatement( + type: returnType, + codec: codecVar, + value: resultVariable + ) + ?? "\(codecVar).lower(\(resultVariable));" + body.write(lowerStmt) + self.returnExpr = nil + return + } let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: returnType, context: context) let returnExpr: String? if loweringFragment.parameters.count == 0 { @@ -3488,9 +3678,11 @@ extension BridgeJSLink { returnType: function.returnType, intrinsicRegistry: intrinsicRegistry ) - for param in function.parameters { - try thunkBuilder.liftParameter(param: param) - } + let genericParameters = function.genericParameterNames + try thunkBuilder.liftParametersAndGenericTypeIds( + function.parameters, + genericParameters: genericParameters + ) let jsName = function.resolvedJSName let calleeExpr = try importedModuleRegistry.memberExpression( swiftModuleName: importObjectBuilder.moduleName, @@ -3501,9 +3693,10 @@ extension BridgeJSLink { try thunkBuilder.call(calleeExpr: calleeExpr) let funcLines = thunkBuilder.renderFunction(name: function.abiName(context: nil)) if function.from == nil { + let genericClause = renderGenericClause(genericParameters) importObjectBuilder.appendDts( [ - "\(renderTSPropertyName(jsName))\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + "\(renderTSPropertyName(jsName))\(genericClause)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ] ) } @@ -3592,14 +3785,16 @@ extension BridgeJSLink { dtsPrinter.indent { if let constructor = type.constructor { let returnType = BridgeType.jsObject(type.name) + let genericClause = renderGenericClause(constructor.genericParameterNames) dtsPrinter.write( - "new\(renderTSSignature(parameters: constructor.parameters, returnType: returnType, effects: Effects(isAsync: false, isThrows: false)));" + "new\(genericClause)\(renderTSSignature(parameters: constructor.parameters, returnType: returnType, effects: Effects(isAsync: false, isThrows: false)));" ) } for method in type.staticMethods { let methodName = method.resolvedJSName + let genericClause = renderGenericClause(method.genericParameterNames) let signature = - "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(renderTSPropertyName(methodName))\(genericClause)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" dtsPrinter.write(signature) } } @@ -3623,9 +3818,10 @@ extension BridgeJSLink { returnType: BridgeType.jsObject(type.name), intrinsicRegistry: intrinsicRegistry ) - for param in constructor.parameters { - try thunkBuilder.liftParameter(param: param) - } + try thunkBuilder.liftParametersAndGenericTypeIds( + constructor.parameters, + genericParameters: constructor.genericParameterNames + ) let ctorExpr = try importedModuleRegistry.memberExpression( swiftModuleName: importObjectBuilder.moduleName, from: type.from, @@ -3682,9 +3878,10 @@ extension BridgeJSLink { returnType: method.returnType, intrinsicRegistry: intrinsicRegistry ) - for param in method.parameters { - try thunkBuilder.liftParameter(param: param) - } + try thunkBuilder.liftParametersAndGenericTypeIds( + method.parameters, + genericParameters: method.genericParameterNames + ) let constructorExpr = try importedModuleRegistry.memberExpression( swiftModuleName: swiftModuleName, from: context.from, @@ -3706,9 +3903,11 @@ extension BridgeJSLink { intrinsicRegistry: intrinsicRegistry ) thunkBuilder.liftSelf() - for param in method.parameters { - try thunkBuilder.liftParameter(param: param) - } + let genericParameters = method.genericParameterNames + try thunkBuilder.liftParametersAndGenericTypeIds( + method.parameters, + genericParameters: genericParameters + ) try thunkBuilder.callMethod(name: method.resolvedJSName) let funcLines = thunkBuilder.renderFunction(name: method.abiName(context: context)) @@ -4052,6 +4251,8 @@ extension BridgeType { return "Record" case .alias(_, let underlying): return underlying.tsType + case .generic(let name): + return name } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 2bf656708..8da83fa18 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -35,6 +35,11 @@ final class JSGlueVariableScope { static let reservedSwiftClosureRegistry = "swiftClosureRegistry" static let reservedMakeSwiftClosure = "makeClosure" static let reservedTaStack = "taStack" + static let reservedCodecByTypeId = "__bjs_codecByTypeId" + static let reservedPrimitiveCodecs = "__bjs_primitiveCodecs" + static let reservedStringCodec = "__bjs_stringCodec" + static let reservedTypeHandlesRegistered = "__bjs_typeHandlesRegistered" + static let reservedRegisterTypeHandles = "__bjs_registerTypeHandles" private let intrinsicRegistry: JSIntrinsicRegistry @@ -65,6 +70,11 @@ final class JSGlueVariableScope { reservedSwiftClosureRegistry, reservedMakeSwiftClosure, reservedTaStack, + reservedCodecByTypeId, + reservedPrimitiveCodecs, + reservedStringCodec, + reservedTypeHandlesRegistered, + reservedRegisterTypeHandles, ] init(intrinsicRegistry: JSIntrinsicRegistry) { @@ -138,6 +148,271 @@ extension JSGlueVariableScope { } } +enum GenericJSCodegen { + /// Wraps a bare element codec into the codec for the wrapped form (`[T]`, + /// `T?`, `[String: T]`) used at a generic call site, or `nil` when the type + /// is not a generic reference. + static func genericCodecExpression(type: BridgeType, codec: String) -> String? { + switch type { + case .generic: return codec + case .array(.generic): return "\(ContainerCodecJS.arrayCodec)(\(codec))" + case .nullable(.generic, let kind): + return ContainerCodecJS.optionalCodecExpression(elementCodec: codec, kind: kind) + case .dictionary(.generic): return "\(ContainerCodecJS.dictCodec)(\(codec))" + default: return nil + } + } + + static func genericCodecLowerStatement(type: BridgeType, codec: String, value: String) -> String? { + genericCodecExpression(type: type, codec: codec).map { "\($0).lower(\(value));" } + } + + static func genericCodecLiftExpression(type: BridgeType, codec: String) -> String? { + genericCodecExpression(type: type, codec: codec).map { "\($0).lift()" } + } + + /// Generic-only runtime: resolves a wasm-side type ID to the codec + /// registered for it. The container codec combinators themselves live in + /// `ContainerCodecJS` and are shared with the non-generic bridging paths. + static func runtimeHelperDeclarations() -> [String] { + let codecByTypeId = JSGlueVariableScope.reservedCodecByTypeId + return [ + "function __bjs_codecForTypeId(typeId) {", + " __bjs_registerTypeHandles();", + " const codec = \(codecByTypeId).get(typeId);", + " if (!codec) {", + " throw new Error(\"BridgeJS: no codec registered for type ID \" + typeId);", + " }", + " return codec;", + "}", + ] + } +} + +/// Shared `{ lower, lift }` codec codegen: each container's stack ABI is +/// described once by a combinator and instantiated with an element codec by +/// both the generic and non-generic paths. Emitted lazily via the intrinsic +/// registry, so builds that bridge no containers pay nothing. +enum ContainerCodecJS { + static let arrayCodec = "__bjs_arrayCodec" + static let optionalCodec = "__bjs_optionalCodec" + static let dictCodec = "__bjs_dictCodec" + static let enumCodec = "__bjs_enumCodec" + + private static let combinatorIntrinsicName = "containerCodecCombinators" + private static let primitiveCodecIntrinsicName = "containerPrimitiveCodecs" + + /// The single description of each container shape's stack ABI. + static func combinatorDeclarations() -> [String] { + let i32 = JSGlueVariableScope.reservedI32Stack + let stringCodec = JSGlueVariableScope.reservedStringCodec + return [ + "function \(arrayCodec)(elementCodec) {", + " return {", + " lower(value) {", + " for (let i = 0; i < value.length; i++) {", + " elementCodec.lower(value[i]);", + " }", + " \(i32).push(value.length);", + " },", + " lift() {", + " const count = \(i32).pop();", + " if (count === -1) {", + " return \(JSGlueVariableScope.reservedTaStack).pop();", + " }", + " const result = new Array(count);", + " for (let i = count - 1; i >= 0; i--) {", + " result[i] = elementCodec.lift();", + " }", + " return result;", + " },", + " };", + "}", + // `isUndefinedOr` selects the `JSUndefinedOr` flavor: `null` is then a + // present value and absence surfaces as `undefined` instead of `null`. + "function \(optionalCodec)(elementCodec, isUndefinedOr = false) {", + " return {", + " lower(value) {", + " const isSome = isUndefinedOr ? value !== undefined : value != null;", + " if (isSome) {", + " elementCodec.lower(value);", + " \(i32).push(1);", + " } else {", + " \(i32).push(0);", + " }", + " },", + " lift() {", + " if (\(i32).pop() === 0) {", + " return isUndefinedOr ? undefined : null;", + " }", + " return elementCodec.lift();", + " },", + " };", + "}", + "function \(dictCodec)(valueCodec) {", + " return {", + " lower(value) {", + " const keys = Object.keys(value);", + " for (let i = 0; i < keys.length; i++) {", + " \(stringCodec).lower(keys[i]);", + " valueCodec.lower(value[keys[i]]);", + " }", + " \(i32).push(keys.length);", + " },", + " lift() {", + " const count = \(i32).pop();", + " const result = {};", + " for (let i = 0; i < count; i++) {", + " const value = valueCodec.lift();", + " const key = \(stringCodec).lift();", + " result[key] = value;", + " }", + " return result;", + " },", + " };", + "}", + // Adapts an associated-value enum helper (whose lower returns the case + // tag and whose lift takes it) to the plain stack codec protocol. + "function \(enumCodec)(helper) {", + " return {", + " lower(value) {", + " \(i32).push(helper.lower(value));", + " },", + " lift() {", + " return helper.lift(\(i32).pop());", + " },", + " };", + "}", + ] + } + + static func optionalCodecExpression(elementCodec: String, kind: JSOptionalKind) -> String { + switch kind { + case .null: return "\(optionalCodec)(\(elementCodec))" + case .undefined: return "\(optionalCodec)(\(elementCodec), true)" + } + } + + static func registerCombinators(scope: JSGlueVariableScope) { + scope.registerIntrinsic(combinatorIntrinsicName) { printer in + printer.write(lines: combinatorDeclarations()) + } + } + + /// Emits `__bjs_stringCodec` and the `__bjs_primitiveCodecs` table shared + /// by combinator instantiations and the generic type-handle registration. + static func registerPrimitiveCodecs(context: IntrinsicJSFragment.PrintCodeContext) throws { + try context.scope.registerIntrinsic(primitiveCodecIntrinsicName) { printer in + let stringCodec = JSGlueVariableScope.reservedStringCodec + // The String codec is named so the dictionary codec combinator can + // lower/lift keys through it. + try writeCodecLiteral( + type: .string, + into: printer, + context: context, + prefix: "const \(stringCodec) = ", + suffix: ";" + ) + printer.write("const \(JSGlueVariableScope.reservedPrimitiveCodecs) = {") + try printer.indent { + for primitive in BridgeType.genericBridgeablePrimitives { + if case .string = primitive.type { + printer.write("\(primitive.token): \(stringCodec),") + } else { + try writeCodecLiteral( + type: primitive.type, + into: printer, + context: context, + prefix: "\(primitive.token): ", + suffix: "," + ) + } + } + } + printer.write("};") + } + } + + /// Emits a `{ lower, lift }` codec literal for one bridgeable type. + /// `prefix` is prepended to the opening brace (e.g. an assignment) and + /// `suffix` is appended to the closing brace (e.g. `","` in an object). + static func writeCodecLiteral( + type: BridgeType, + into printer: CodeFragmentPrinter, + context: IntrinsicJSFragment.PrintCodeContext, + prefix: String = "", + suffix: String = "," + ) throws { + func literalContext() -> IntrinsicJSFragment.PrintCodeContext { + context.with(\.printer, printer).with(\.scope, context.scope.makeChildScope()) + } + let lowerFragment = try IntrinsicJSFragment.stackLowerFragment(elementType: type) + let liftFragment = try IntrinsicJSFragment.stackLiftFragment(elementType: type) + printer.write("\(prefix){") + try printer.indent { + printer.write("lower: (v) => {") + try printer.indent { + _ = try lowerFragment.printCode(["v"], literalContext()) + } + printer.write("},") + printer.write("lift: () => {") + try printer.indent { + let results = try liftFragment.printCode([], literalContext()) + printer.write("return \(results[0]);") + } + printer.write("},") + } + printer.write("}\(suffix)") + } + + /// Returns a JS expression evaluating to the `{ lower, lift }` codec for + /// one element type, registering the shared codec runtime as needed. May + /// write supporting statements (a local codec literal) to the context's + /// printer for element shapes without a named shared codec. + static func codecExpression( + for elementType: BridgeType, + context: IntrinsicJSFragment.PrintCodeContext + ) throws -> String { + registerCombinators(scope: context.scope) + try registerPrimitiveCodecs(context: context) + let type = elementType.unaliased + switch type { + case .array(let element): + return "\(arrayCodec)(\(try codecExpression(for: element, context: context)))" + case .dictionary(let value): + return "\(dictCodec)(\(try codecExpression(for: value, context: context)))" + case .nullable(let wrapped, let kind): + let element = try codecExpression(for: wrapped, context: context) + return optionalCodecExpression(elementCodec: element, kind: kind) + case .string, .rawValueEnum(_, .string): + return JSGlueVariableScope.reservedStringCodec + case .swiftStruct(let fullName): + // `@JS` struct helpers already expose the codec protocol. + let base = fullName.replacingOccurrences(of: ".", with: "_") + return "\(JSGlueVariableScope.reservedStructHelpers).\(base)" + case .associatedValueEnum(let fullName): + let base = fullName.components(separatedBy: ".").last ?? fullName + return "\(enumCodec)(\(JSGlueVariableScope.reservedEnumHelpers).\(base))" + default: + if let token = BridgeType.genericBridgeablePrimitives.first(where: { $0.type == type })?.token { + return "\(JSGlueVariableScope.reservedPrimitiveCodecs).\(token)" + } + // Element shapes without a named shared codec (case enums, non-string + // raw-value enums, JSObject, Swift heap objects, ...) get a local + // codec literal built from the same element stack fragments. + let codecVar = context.scope.variable("elemCodec") + try writeCodecLiteral( + type: type, + into: context.printer, + context: context, + prefix: "const \(codecVar) = ", + suffix: ";" + ) + return codecVar + } + } +} + /// A fragment of JS code used to convert a value between Swift and JS. /// /// See `BridgeJSIntrinsics.swift` in the main JavaScriptKit module for Swift side lowering/lifting implementation. @@ -681,6 +956,12 @@ struct IntrinsicJSFragment: Sendable { ) } + /// Lift an optional parameter whose presence flag arrives as a wasm + /// parameter (not on the i32 stack), with the payload either in further + /// wasm parameters or on the stacks. The shared optional codec combinator + /// pops its flag from the i32 stack, so this ABI cannot go through it; + /// stack-convention payloads still lift through the shared container + /// codecs via `stackLiftFragment`. private static func compositeOptionalLiftParameter( wrappedType: BridgeType, kind: JSOptionalKind, @@ -761,26 +1042,26 @@ struct IntrinsicJSFragment: Sendable { ) } - let innerFragment = - if wrappedType.optionalParameterUsesStackABI { - try stackLowerFragment(elementType: wrappedType) - } else { - try lowerParameter(type: wrappedType) - } + if wrappedType.optionalParameterUsesStackABI { + // Stack convention: the conditional flag-plus-payload protocol is + // the shared optional codec's stack ABI. + return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) + } return try compositeOptionalLowerParameter( wrappedType: wrappedType, kind: kind, - innerFragment: innerFragment + innerFragment: try lowerParameter(type: wrappedType) ) } + /// Lower an optional parameter using the direct `(isSome, ...payload)` wasm + /// parameter ABI with zero placeholders for nil. This is not the container + /// stack ABI, so it cannot go through the shared optional codec combinator. private static func compositeOptionalLowerParameter( wrappedType: BridgeType, kind: JSOptionalKind, innerFragment: IntrinsicJSFragment ) throws -> IntrinsicJSFragment { - let isStackConvention = wrappedType.optionalParameterUsesStackABI - return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in @@ -797,7 +1078,7 @@ struct IntrinsicJSFragment: Sendable { let resultVars = innerResults.map { _ in scope.variable("result") } assert( - isStackConvention || resultVars.count == wrappedType.wasmParams.count, + resultVars.count == wrappedType.wasmParams.count, "Inner fragment result count (\(resultVars.count)) must match wasmParams count (\(wrappedType.wasmParams.count)) for \(wrappedType)" ) if !resultVars.isEmpty { @@ -814,8 +1095,7 @@ struct IntrinsicJSFragment: Sendable { } } - let hasPlaceholders = !isStackConvention && !wrappedType.wasmParams.isEmpty - if hasPlaceholders { + if !wrappedType.wasmParams.isEmpty { printer.write("} else {") printer.indent { for (resultVar, param) in zip(resultVars, wrappedType.wasmParams) { @@ -825,12 +1105,7 @@ struct IntrinsicJSFragment: Sendable { } printer.write("}") - if isStackConvention { - scope.emitPushI32Parameter("+\(isSomeVar)", printer: printer) - return [] - } else { - return ["+\(isSomeVar)"] + resultVars - } + return ["+\(isSomeVar)"] + resultVars } ) } @@ -848,6 +1123,9 @@ struct IntrinsicJSFragment: Sendable { ) } + /// Lift an optional return whose presence flag travels on the i32 stack but + /// whose payload uses the wrapped type's regular (non-stack) return ABI, so + /// it cannot go through the shared optional codec combinator. private static func optionalLiftReturnWithPresenceFlag( wrappedType: BridgeType, kind: JSOptionalKind @@ -860,12 +1138,7 @@ struct IntrinsicJSFragment: Sendable { let isSomeVar = scope.variable("isSome") printer.write("const \(isSomeVar) = \(scope.popI32());") - let innerFragment = - if wrappedType.optionalConvention == .stackABI { - try stackLiftFragment(elementType: wrappedType) - } else { - try liftReturn(type: wrappedType) - } + let innerFragment = try liftReturn(type: wrappedType) let innerPrinter = CodeFragmentPrinter() let innerResults = try innerFragment.printCode([], context.with(\.printer, innerPrinter)) @@ -942,31 +1215,13 @@ struct IntrinsicJSFragment: Sendable { ) } - private static func optionalLiftReturnStruct( - fullName: String, - kind: JSOptionalKind - ) -> IntrinsicJSFragment { - let base = fullName.replacingOccurrences(of: ".", with: "_") - let absenceLiteral = kind.absenceLiteral - return IntrinsicJSFragment( - parameters: [], - printCode: { _, context in - let (scope, printer) = (context.scope, context.printer) - let isSomeVar = scope.variable("isSome") - let resultVar = scope.variable("optResult") - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write( - "const \(resultVar) = \(isSomeVar) ? \(JSGlueVariableScope.reservedStructHelpers).\(base).lift() : \(absenceLiteral);" - ) - return [resultVar] - } - ) - } - static func optionalLiftReturn( wrappedType: BridgeType, kind: JSOptionalKind - ) -> IntrinsicJSFragment { + ) throws -> IntrinsicJSFragment { + // Side-channel optionals deliver their payload through dedicated + // storage/imports instead of the bridge stacks, so they cannot go + // through the shared optional codec combinator. if let scalarKind = wrappedType.optionalScalarKind { return optionalLiftReturnFromStorage(storage: scalarKind.storageName) } @@ -974,18 +1229,21 @@ struct IntrinsicJSFragment: Sendable { return optionalLiftReturnFromStorage(storage: JSGlueVariableScope.reservedStorageToReturnString) } + // Heap object optionals use the tmpRetOptionalHeapObject side channel. if case .swiftHeapObject(let className) = wrappedType { return optionalLiftReturnHeapObject(className: className, kind: kind) } - if case .swiftStruct(let fullName) = wrappedType { - return optionalLiftReturnStruct(fullName: fullName, kind: kind) - } - + // Sentinel optionals encode nil in-band (tag -1), with no presence flag. if wrappedType.nilSentinel.hasSentinel, case .associatedValueEnum(let fullName) = wrappedType { return optionalLiftReturnAssociatedEnum(fullName: fullName, kind: kind) } + if wrappedType.optionalConvention == .stackABI { + // Stack convention: route through the shared optional codec combinator. + return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) + } + return optionalLiftReturnWithPresenceFlag(wrappedType: wrappedType, kind: kind) } @@ -1111,12 +1369,8 @@ struct IntrinsicJSFragment: Sendable { } if wrappedType.optionalConvention == .stackABI { - let innerFragment = try stackLowerFragment(elementType: wrappedType) - return stackOptionalLower( - wrappedType: wrappedType, - kind: kind, - innerFragment: innerFragment - ) + // Stack convention: route through the shared optional codec combinator. + return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) } if wrappedType.nilSentinel.hasSentinel { @@ -1248,39 +1502,6 @@ struct IntrinsicJSFragment: Sendable { } } - /// Lower an optional value to the stack using the **conditional** protocol: - /// push isSome flag, then conditionally push the payload (no placeholders for nil). - private static func stackOptionalLower( - wrappedType: BridgeType, - kind: JSOptionalKind, - innerFragment: IntrinsicJSFragment - ) -> IntrinsicJSFragment { - IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(kind.presenceCheck(value: value));") - - let ifBodyPrinter = CodeFragmentPrinter() - try ifBodyPrinter.indent { - let _ = try innerFragment.printCode( - [value], - context.with(\.printer, ifBodyPrinter) - ) - } - printer.write("if (\(isSomeVar)) {") - for line in ifBodyPrinter.lines { - printer.write(line) - } - printer.write("}") - scope.emitPushI32Parameter("\(isSomeVar) ? 1 : 0", printer: printer) - return [] - } - ) - } - // MARK: - ExportSwift /// Returns a fragment that lowers a JS value to Wasm core values for parameters @@ -1357,7 +1578,7 @@ struct IntrinsicJSFragment: Sendable { case .swiftProtocol: return .jsObjectLiftReturn case .void: return .void case .nullable(let wrappedType, let kind): - return .optionalLiftReturn(wrappedType: wrappedType, kind: kind) + return try .optionalLiftReturn(wrappedType: wrappedType, kind: kind) case .rawValueEnum(_, .string): return .stringLiftReturn case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName @@ -1807,133 +2028,61 @@ struct IntrinsicJSFragment: Sendable { // MARK: - Array Helpers - /// Lowers an array from JS to Swift by iterating elements and pushing to stacks + /// Lowers an array from JS to Swift through the shared array codec combinator static func arrayLower(elementType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["arr"], printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let arr = arguments[0] - - let elemVar = scope.variable("elem") - printer.write("for (const \(elemVar) of \(arr)) {") - try printer.indent { - let elementFragment = try stackLowerFragment(elementType: elementType) - let _ = try elementFragment.printCode( - [elemVar], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(arr).length", printer: printer) + let element = try ContainerCodecJS.codecExpression(for: elementType, context: context) + context.printer.write("\(ContainerCodecJS.arrayCodec)(\(element)).lower(\(arguments[0]));") return [] } ) } - /// Lowers a dictionary from JS to Swift by iterating entries and pushing to stacks + /// Lowers a dictionary from JS to Swift through the shared dictionary codec combinator static func dictionaryLower(valueType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["dict"], printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let dict = arguments[0] - - let entriesVar = scope.variable("entries") - let entryVar = scope.variable("entry") - printer.write("const \(entriesVar) = Object.entries(\(dict));") - printer.write("for (const \(entryVar) of \(entriesVar)) {") - try printer.indent { - let keyVar = scope.variable("key") - let valueVar = scope.variable("value") - printer.write("const [\(keyVar), \(valueVar)] = \(entryVar);") - - let keyFragment = try stackLowerFragment(elementType: .string) - let _ = try keyFragment.printCode( - [keyVar], - context - ) - - let valueFragment = try stackLowerFragment(elementType: valueType) - let _ = try valueFragment.printCode( - [valueVar], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter("\(entriesVar).length", printer: printer) + let value = try ContainerCodecJS.codecExpression(for: valueType, context: context) + context.printer.write("\(ContainerCodecJS.dictCodec)(\(value)).lower(\(arguments[0]));") return [] } ) } - /// Lifts an array from Swift to JS by popping elements from stacks + /// Lifts an array from Swift to JS through the shared array codec combinator static func arrayLift(elementType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let resultVar = scope.variable("arrayResult") - let lenVar = scope.variable("arrayLen") - - printer.write("const \(lenVar) = \(scope.popI32());") - printer.write("let \(resultVar);") - printer.write("if (\(lenVar) === -1) {") - printer.indent { - // Bulk path: Swift pushed a typed array onto the typed-array stack - printer.write("\(resultVar) = \(JSGlueVariableScope.reservedTaStack).pop();") - } - printer.write("} else {") - try printer.indent { - // Element-by-element path (original behavior) - let iVar = scope.variable("i") - printer.write("\(resultVar) = [];") - printer.write("for (let \(iVar) = 0; \(iVar) < \(lenVar); \(iVar)++) {") - try printer.indent { - let elementFragment = try stackLiftFragment(elementType: elementType) - let elementResults = try elementFragment.printCode([], context) - if let elementExpr = elementResults.first { - printer.write("\(resultVar).push(\(elementExpr));") - } - } - printer.write("}") - printer.write("\(resultVar).reverse();") - } - printer.write("}") + printCode: { _, context in + let element = try ContainerCodecJS.codecExpression(for: elementType, context: context) + let resultVar = context.scope.variable("arrayResult") + context.printer.write( + "const \(resultVar) = \(ContainerCodecJS.arrayCodec)(\(element)).lift();" + ) return [resultVar] } ) } - /// Lifts a dictionary from Swift to JS by popping key/value pairs from stacks + /// Lifts a dictionary from Swift to JS through the shared dictionary codec combinator static func dictionaryLift(valueType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let resultVar = scope.variable("dictResult") - let lenVar = scope.variable("dictLen") - let iVar = scope.variable("i") - - printer.write("const \(lenVar) = \(scope.popI32());") - printer.write("const \(resultVar) = {};") - printer.write("for (let \(iVar) = 0; \(iVar) < \(lenVar); \(iVar)++) {") - try printer.indent { - let valueFragment = try stackLiftFragment(elementType: valueType) - let valueResults = try valueFragment.printCode([], context) - let keyFragment = try stackLiftFragment(elementType: .string) - let keyResults = try keyFragment.printCode([], context) - if let keyExpr = keyResults.first, let valueExpr = valueResults.first { - printer.write("\(resultVar)[\(keyExpr)] = \(valueExpr);") - } - } - printer.write("}") + printCode: { _, context in + let value = try ContainerCodecJS.codecExpression(for: valueType, context: context) + let resultVar = context.scope.variable("dictResult") + context.printer.write( + "const \(resultVar) = \(ContainerCodecJS.dictCodec)(\(value)).lift();" + ) return [resultVar] } ) } - private static func stackLiftFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { + static func stackLiftFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { if case .nullable(let wrappedType, let kind) = elementType { return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) } @@ -2060,7 +2209,7 @@ struct IntrinsicJSFragment: Sendable { } } - private static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { + static func stackLowerFragment(elementType: BridgeType) throws -> IntrinsicJSFragment { if case .nullable(let wrappedType, let kind) = elementType { return try optionalElementLowerFragment(wrappedType: wrappedType, kind: kind) } @@ -2181,43 +2330,27 @@ struct IntrinsicJSFragment: Sendable { } } + /// Lift an optional from the stack (isSome flag, then conditional payload) + /// through the shared optional codec combinator. private static func optionalElementRaiseFragment( wrappedType: BridgeType, kind: JSOptionalKind ) throws -> IntrinsicJSFragment { - let absenceLiteral = kind.absenceLiteral return IntrinsicJSFragment( parameters: [], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let isSomeVar = scope.variable("isSome") - let resultVar = scope.variable("optValue") - - printer.write("const \(isSomeVar) = \(scope.popI32());") - printer.write("let \(resultVar);") - printer.write("if (\(isSomeVar) === 0) {") - printer.indent { - printer.write("\(resultVar) = \(absenceLiteral);") - } - printer.write("} else {") - try printer.indent { - let innerFragment = try stackLiftFragment(elementType: wrappedType) - let innerResults = try innerFragment.printCode([], context) - if let innerResult = innerResults.first { - printer.write("\(resultVar) = \(innerResult);") - } else { - printer.write("\(resultVar) = undefined;") - } - } - printer.write("}") - + printCode: { _, context in + let element = try ContainerCodecJS.codecExpression(for: wrappedType, context: context) + let resultVar = context.scope.variable("optValue") + let codec = ContainerCodecJS.optionalCodecExpression(elementCodec: element, kind: kind) + context.printer.write("const \(resultVar) = \(codec).lift();") return [resultVar] } ) } - /// Lower an optional element to the stack using the **conditional** protocol: - /// push isSome flag, then conditionally push the payload (no placeholders for nil). + /// Lower an optional value to the stack using the **conditional** protocol + /// (push isSome flag, then conditionally push the payload) through the + /// shared optional codec combinator. private static func optionalElementLowerFragment( wrappedType: BridgeType, kind: JSOptionalKind @@ -2225,23 +2358,9 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let value = arguments[0] - let isSomeVar = scope.variable("isSome") - - let presenceExpr = kind.presenceCheck(value: value) - printer.write("const \(isSomeVar) = \(presenceExpr) ? 1 : 0;") - printer.write("if (\(isSomeVar)) {") - try printer.indent { - let innerFragment = try stackLowerFragment(elementType: wrappedType) - let _ = try innerFragment.printCode( - [value], - context - ) - } - printer.write("}") - scope.emitPushI32Parameter(isSomeVar, printer: printer) - + let element = try ContainerCodecJS.codecExpression(for: wrappedType, context: context) + let codec = ContainerCodecJS.optionalCodecExpression(elementCodec: element, kind: kind) + context.printer.write("\(codec).lower(\(arguments[0]));") return [] } ) @@ -2608,7 +2727,7 @@ private extension BridgeType { return .inlineFlag case .closure: return .inlineFlag - case .swiftStruct, .array, .dictionary, .void, .namespaceEnum: + case .swiftStruct, .array, .dictionary, .void, .namespaceEnum, .generic: return .stackABI case .nullable(let wrapped, _): return wrapped.optionalConvention @@ -2706,7 +2825,7 @@ private extension BridgeType { return [("caseId", .i32)] case .closure: return [("funcRef", .i32)] - case .void, .namespaceEnum, .swiftStruct, .array, .dictionary: + case .void, .namespaceEnum, .swiftStruct, .array, .dictionary, .generic: return [] case .nullable(let wrapped, _): return wrapped.wasmParams diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 21704d1c9..2cea16fb4 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -22,6 +22,16 @@ extension NamespacedExportedType { public struct ABINameGenerator { static let prefixComponent = "bjs" + /// ABI parameter name carrying the runtime type ID for the generic parameter at `index`. + public static func genericTypeIdParameterName(index: Int) -> String { "_generic\(index)TypeId" } + + /// Name of the per-module type-handle registration function. The wasm module + /// exports it under this name, and it calls back into a JS import hook of the + /// same name (in the `bjs` import namespace) with a buffer of type IDs. + public static func typeRegistrationFunctionName(moduleName: String) -> String { + "bjs_\(moduleName)_register_type_handles" + } + /// Generates ABI name using standardized namespace + context pattern public static func generateABIName( baseName: String, @@ -273,10 +283,120 @@ public enum BridgeType: Codable, Equatable, Hashable, Sendable { case namespaceEnum(String) case swiftProtocol(String) case swiftStruct(String) + case generic(String) indirect case closure(ClosureSignature, useJSTypedClosure: Bool) indirect case alias(name: String, underlying: BridgeType) } +extension BridgeType { + public var referencedGenericName: String? { + switch self { + case .generic(let name): return name + case .array(.generic(let name)): return name + case .nullable(.generic(let name), _): return name + case .dictionary(.generic(let name)): return name + default: return nil + } + } + + public static let genericBridgeablePrimitives: [(token: String, type: BridgeType)] = [ + ("Bool", .bool), + ("Int", .integer(.int)), + ("Int8", .integer(.int8)), + ("UInt8", .integer(.uint8)), + ("Int16", .integer(.int16)), + ("UInt16", .integer(.uint16)), + ("Int32", .integer(.int32)), + ("UInt32", .integer(.uint32)), + ("UInt", .integer(.uint)), + ("Int64", .integer(.int64)), + ("UInt64", .integer(.uint64)), + ("Float", .float), + ("Double", .double), + ("String", .string), + ("JSValue", .jsValue), + ] + +} + +// MARK: - Generic type registration + +/// One `BridgedSwiftGenericBridgeable` type participating in generic bridging. +/// +/// `swiftName` is the Swift expression naming the type (used by Swift codegen to +/// read `.bridgeJSTypeID`); `bridgeType` describes the stack ABI (used +/// by the JS link layer to emit the matching codec). +public struct GenericBridgeableTypeEntry: Sendable { + public let swiftName: String + public let bridgeType: BridgeType + + public init(swiftName: String, bridgeType: BridgeType) { + self.swiftName = swiftName + self.bridgeType = bridgeType + } +} + +extension ExportedEnum { + /// The `BridgeType` an enum bridges as when used as a generic argument, or + /// `nil` when it can't be one (namespace enums). + public var genericBridgeType: BridgeType? { + switch enumType { + case .simple: + return .caseEnum(name) + case .rawValue: + guard let rawType = rawType else { return nil } + return .rawValueEnum(name, rawType) + case .associatedValue: + return .associatedValueEnum(name) + case .namespace: + return nil + } + } +} + +extension ExportedSkeleton { + /// The module's `@JS` types that conform to `BridgedSwiftGenericBridgeable`. + /// The order is the contract between the Swift registration function and the + /// JS codec array; both derive it from this skeleton, so they line up. + public var genericBridgeableTypeEntries: [GenericBridgeableTypeEntry] { + var entries: [GenericBridgeableTypeEntry] = [] + for structDef in structs { + entries.append( + GenericBridgeableTypeEntry( + swiftName: structDef.swiftCallName, + bridgeType: .swiftStruct(structDef.abiName) + ) + ) + } + for klass in classes where klass.isFinal == true { + entries.append( + GenericBridgeableTypeEntry(swiftName: klass.swiftCallName, bridgeType: .swiftHeapObject(klass.name)) + ) + } + for enumDef in enums { + guard let bridgeType = enumDef.genericBridgeType else { continue } + entries.append(GenericBridgeableTypeEntry(swiftName: enumDef.swiftCallName, bridgeType: bridgeType)) + } + return entries + } +} + +extension BridgeJSSkeleton { + /// The ordered list of types this module registers type handles for, or + /// `nil` when it emits no registration function. Primitive handles are + /// library singletons, so every module re-registering them writes the same + /// ID-to-codec pair, and a pure-import build still gets a populated table. + public var typeRegistrationEntries: [GenericBridgeableTypeEntry]? { + let exportedEntries = exported?.genericBridgeableTypeEntries ?? [] + let hasGenericImports = imported?.hasGenericDeclarations ?? false + guard !exportedEntries.isEmpty || hasGenericImports else { return nil } + let primitives = BridgeType.genericBridgeablePrimitives.map { + GenericBridgeableTypeEntry(swiftName: $0.token, bridgeType: $0.type) + } + return primitives + exportedEntries + } +} + public enum WasmCoreType: String, Codable, Sendable { case i32, i64, f32, f64, pointer } @@ -905,6 +1025,7 @@ public struct ExportedClass: Codable, NamespacedExportedType { public var namespace: [String]? public var identityMode: Bool? // nil = use config default, true/false = override public var documentation: String? + public var isFinal: Bool? public init( name: String, @@ -915,7 +1036,8 @@ public struct ExportedClass: Codable, NamespacedExportedType { properties: [ExportedProperty] = [], namespace: [String]? = nil, identityMode: Bool? = nil, - documentation: String? = nil + documentation: String? = nil, + isFinal: Bool? = nil ) { self.name = name self.swiftCallName = swiftCallName @@ -926,6 +1048,7 @@ public struct ExportedClass: Codable, NamespacedExportedType { self.namespace = namespace self.identityMode = identityMode self.documentation = documentation + self.isFinal = isFinal } } @@ -1254,6 +1377,9 @@ public struct ImportedFunctionSkeleton: Codable { /// determine the access level of bridge-generated helpers (e.g. typed /// closure inits) that surface through this function's signature. public let accessLevel: BridgeJSAccessLevel + public let genericParameters: [String]? + public var genericParameterNames: [String] { genericParameters ?? [] } + public var isGeneric: Bool { !genericParameterNames.isEmpty } public var resolvedJSName: String { jsName ?? name } @@ -1265,7 +1391,8 @@ public struct ImportedFunctionSkeleton: Codable { returnType: BridgeType, effects: Effects = Effects(isAsync: false, isThrows: true), documentation: String? = nil, - accessLevel: BridgeJSAccessLevel = .internal + accessLevel: BridgeJSAccessLevel = .internal, + genericParameters: [String]? = nil ) { self.name = name self.jsName = jsName @@ -1275,10 +1402,11 @@ public struct ImportedFunctionSkeleton: Codable { self.effects = effects self.documentation = documentation self.accessLevel = accessLevel + self.genericParameters = genericParameters } private enum CodingKeys: String, CodingKey { - case name, jsName, from, parameters, returnType, effects, documentation, accessLevel + case name, jsName, from, parameters, returnType, effects, documentation, accessLevel, genericParameters } public init(from decoder: any Decoder) throws { @@ -1291,6 +1419,7 @@ public struct ImportedFunctionSkeleton: Codable { self.effects = try container.decode(Effects.self, forKey: .effects) self.documentation = try container.decodeIfPresent(String.self, forKey: .documentation) self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal + self.genericParameters = try container.decodeIfPresent([String].self, forKey: .genericParameters) } public func abiName(context: ImportedTypeSkeleton?) -> String { @@ -1311,20 +1440,29 @@ public struct ImportedConstructorSkeleton: Codable { /// Source access level of the originating Swift `init`. Inherits from the /// enclosing `@JSClass` type when not annotated explicitly. public let accessLevel: BridgeJSAccessLevel + public let genericParameters: [String]? + public var genericParameterNames: [String] { genericParameters ?? [] } + public var isGeneric: Bool { !genericParameterNames.isEmpty } - public init(parameters: [Parameter], accessLevel: BridgeJSAccessLevel = .internal) { + public init( + parameters: [Parameter], + accessLevel: BridgeJSAccessLevel = .internal, + genericParameters: [String]? = nil + ) { self.parameters = parameters self.accessLevel = accessLevel + self.genericParameters = genericParameters } private enum CodingKeys: String, CodingKey { - case parameters, accessLevel + case parameters, accessLevel, genericParameters } public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.parameters = try container.decode([Parameter].self, forKey: .parameters) self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal + self.genericParameters = try container.decodeIfPresent([String].self, forKey: .genericParameters) } public func abiName(context: ImportedTypeSkeleton) -> String { @@ -1571,6 +1709,17 @@ public struct ImportedFileSkeleton: Codable { } } +extension ImportedFileSkeleton { + public var hasGenericDeclarations: Bool { + functions.contains(where: \.isGeneric) + || types.contains { + $0.methods.contains(where: \.isGeneric) + || $0.staticMethods.contains(where: \.isGeneric) + || ($0.constructor?.isGeneric ?? false) + } + } +} + public struct ImportedModuleSkeleton: Codable { public var children: [ImportedFileSkeleton] @@ -1579,6 +1728,12 @@ public struct ImportedModuleSkeleton: Codable { } } +extension ImportedModuleSkeleton { + public var hasGenericDeclarations: Bool { + children.contains { $0.hasGenericDeclarations } + } +} + // MARK: - Closure signature collection visitor public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { @@ -1753,7 +1908,7 @@ extension BridgeType { case .bool, .integer, .float, .double, .string, .jsValue, .jsObject, .swiftHeapObject, .unsafePointer, .swiftProtocol, .void, .caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct, - .namespaceEnum, .closure: + .namespaceEnum, .closure, .generic: return self } } @@ -1800,6 +1955,8 @@ extension BridgeType { return nil case .alias(_, let underlying): return underlying.abiReturnType + case .generic: + return nil } } @@ -1891,6 +2048,8 @@ extension BridgeType { // `name` is the namespace-qualified swiftCallName (unique), so the underlying // representation isn't mangled in - aliases bridge via their JS type's ABI. return "Al\(name.count)\(name)" + case .generic(let name): + return "\(name.count)\(name)T" } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift index 140ebda63..96d9c4705 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift @@ -240,9 +240,12 @@ import BridgeJSUtilities return try exporter?.finalize() } + // Type-handle registration is shared by exported types and generic imports. + let typeRegistration = GenericTypeRegistrationCodegen().render(for: skeleton) + // Combine and write unified Swift output let outputSwiftURL = outputDirectory.appending(path: "BridgeJS.swift") - let combinedSwift = [closureSupport, exportResult, importResult].compactMap { $0 } + let combinedSwift = [closureSupport, exportResult, importResult, typeRegistration].compactMap { $0 } let outputSwift = combineGeneratedSwift( combinedSwift, importingExternalModules: skeleton.usedExternalModules diff --git a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift index cb6a5481c..971c9608e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift @@ -98,7 +98,8 @@ import ArgumentParser skeleton: $0 ).finalize() } - let combinedSwift = [exported, imported].compactMap { $0 } + let typeRegistration = GenericTypeRegistrationCodegen().render(for: skeleton) + let combinedSwift = [exported, imported, typeRegistration].compactMap { $0 } print(combinedSwift.joined(separator: "\n\n")) } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json index bcdc43375..b47afb905 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.json @@ -79,6 +79,7 @@ } ] }, + "isFinal" : true, "methods" : [ { "abiName" : "bjs_PolygonReference_snapshot", @@ -196,6 +197,7 @@ } ] }, + "isFinal" : true, "methods" : [ ], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift index a9252e57f..42b97761c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift @@ -257,6 +257,18 @@ fileprivate func _bjs_TagReference_wrap_extern(_ pointer: UnsafeMutableRawPointe return _bjs_TagReference_wrap_extern(pointer) } +extension PolygonReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PolygonReference.bridgeJSMakeTypeHandle() +} + +extension TagReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TagReference.bridgeJSMakeTypeHandle() +} + +extension InnerTag: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = InnerTag.bridgeJSMakeTypeHandle() +} + extension Polygon: _BridgedSwiftAlias, _BridgedSwiftStackType {} extension Tag: _BridgedSwiftAlias, _BridgedSwiftStackType {} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json index d76761e0b..c9107133d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.json @@ -34,6 +34,7 @@ } ] }, + "isFinal" : true, "methods" : [ ], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift index 3c87bcdcc..b91db4857 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift @@ -187,4 +187,8 @@ fileprivate func _bjs_PolygonReference_wrap_extern(_ pointer: UnsafeMutableRawPo return _bjs_PolygonReference_wrap_extern(pointer) } +extension PolygonReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PolygonReference.bridgeJSMakeTypeHandle() +} + extension Polygon: _BridgedSwiftAlias, _BridgedSwiftStackType {} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift index 51c6911bd..cf5208f5d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift @@ -501,6 +501,18 @@ fileprivate func _bjs_MultiArrayContainer_wrap_extern(_ pointer: UnsafeMutableRa return _bjs_MultiArrayContainer_wrap_extern(pointer) } +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_checkArray") fileprivate func bjs_checkArray_extern(_ a: Int32) -> Void diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift index f2223ee7c..e4efe4596 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift @@ -335,6 +335,18 @@ public func _bjs_asyncRoundTripEnumDictionary() -> Int32 { #endif } +extension AsyncPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncPoint.bridgeJSMakeTypeHandle() +} + +extension AsyncDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncDirection.bridgeJSMakeTypeHandle() +} + +extension AsyncTheme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncTheme.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift index 3208eda33..5e56f12ad 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift @@ -52,6 +52,10 @@ public func _bjs_asyncRoundTripOptionalAssociatedValueEnum(_ valueIsSome: Int32, #endif } +extension AsyncPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncPayloadResult.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift index 52c633045..62511b41c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift @@ -174,4 +174,12 @@ fileprivate func _bjs_Account_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Account_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Account_wrap_extern(pointer) +} + +extension Account.Credentials: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Account.Credentials.bridgeJSMakeTypeHandle() +} + +extension Account.Role: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Account.Role.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift index 507827646..cca403b68 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift @@ -636,4 +636,16 @@ fileprivate func _bjs_ConstructorDefaults_wrap_extern(_ pointer: UnsafeMutableRa #endif @inline(never) fileprivate func _bjs_ConstructorDefaults_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_ConstructorDefaults_wrap_extern(pointer) +} + +extension Config: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Config.bridgeJSMakeTypeHandle() +} + +extension MathOperations: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = MathOperations.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift index 26a4c087e..d57ec170c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift @@ -149,6 +149,10 @@ fileprivate func _bjs_Box_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int return _bjs_Box_wrap_extern(pointer) } +extension Counters: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Counters.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_importMirrorDictionary") fileprivate func bjs_importMirrorDictionary_extern() -> Void diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift index f91df6c26..042771659 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift @@ -314,4 +314,12 @@ fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Greeter_wrap_extern(pointer) +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension Color: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Color.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json index 0d63db899..c876db410 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.json @@ -31,6 +31,7 @@ } ] }, + "isFinal" : true, "methods" : [ ], diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift index 1e74a127b..6db98303e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift @@ -51,4 +51,8 @@ fileprivate func _bjs_ColorBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) - return _bjs_ColorBox_wrap_extern(pointer) } +extension ColorBox: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ColorBox.bridgeJSMakeTypeHandle() +} + extension Color: _BridgedSwiftAlias, _BridgedSwiftStackType {} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift index 6d5549699..0fa414bfe 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift @@ -631,4 +631,48 @@ fileprivate func _bjs_User_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> In #endif @inline(never) fileprivate func _bjs_User_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_User_wrap_extern(pointer) +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +extension ComplexResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexResult.bridgeJSMakeTypeHandle() +} + +extension Utilities.Result: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Utilities.Result.bridgeJSMakeTypeHandle() +} + +extension NetworkingResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NetworkingResult.bridgeJSMakeTypeHandle() +} + +extension APIOptionalResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIOptionalResult.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() +} + +extension CardinalDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CardinalDirection.bridgeJSMakeTypeHandle() +} + +extension TypedPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TypedPayloadResult.bridgeJSMakeTypeHandle() +} + +extension AllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AllTypesResult.bridgeJSMakeTypeHandle() +} + +extension OptionalAllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = OptionalAllTypesResult.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift index 55d1992a3..fcf201eb8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift @@ -26,6 +26,10 @@ extension PayloadSignal: _BridgedSwiftAssociatedValueEnum { } } +extension PayloadSignal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PayloadSignal.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_PayloadSignalControls_roundTrip_static") fileprivate func bjs_PayloadSignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift index 66692ee14..a3f1f62dd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift @@ -227,4 +227,20 @@ public func _bjs_roundTripOptionalTSDirection(_ inputIsSome: Int32, _ inputValue #else fatalError("Only available on WebAssembly") #endif +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() +} + +extension TSDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSDirection.bridgeJSMakeTypeHandle() +} + +extension PublicStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PublicStatus.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift index f297e1620..adef86c78 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift @@ -33,6 +33,10 @@ extension Signal: _BridgedSwiftCaseEnum { } } +extension Signal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Signal.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_SignalControls_roundTrip_static") fileprivate func bjs_SignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift index 4f588f6c7..9b2fda572 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift @@ -358,4 +358,20 @@ fileprivate func _bjs_Formatting_Converter_wrap_extern(_ pointer: UnsafeMutableR #endif @inline(never) fileprivate func _bjs_Formatting_Converter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Formatting_Converter_wrap_extern(pointer) +} + +extension Networking.API.Method: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Networking.API.Method.bridgeJSMakeTypeHandle() +} + +extension Configuration.LogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.LogLevel.bridgeJSMakeTypeHandle() +} + +extension Configuration.Port: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.Port.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift index 4f588f6c7..9b2fda572 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift @@ -358,4 +358,20 @@ fileprivate func _bjs_Formatting_Converter_wrap_extern(_ pointer: UnsafeMutableR #endif @inline(never) fileprivate func _bjs_Formatting_Converter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Formatting_Converter_wrap_extern(pointer) +} + +extension Networking.API.Method: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Networking.API.Method.bridgeJSMakeTypeHandle() +} + +extension Configuration.LogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.LogLevel.bridgeJSMakeTypeHandle() +} + +extension Configuration.Port: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.Port.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift index e70a6b0aa..72f481c2d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift @@ -451,6 +451,54 @@ public func _bjs_validateSession(_ session: Int64) -> Void { #endif } +extension Theme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Theme.bridgeJSMakeTypeHandle() +} + +extension TSTheme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSTheme.bridgeJSMakeTypeHandle() +} + +extension FeatureFlag: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FeatureFlag.bridgeJSMakeTypeHandle() +} + +extension HttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = HttpStatus.bridgeJSMakeTypeHandle() +} + +extension TSHttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSHttpStatus.bridgeJSMakeTypeHandle() +} + +extension Priority: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Priority.bridgeJSMakeTypeHandle() +} + +extension FileSize: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FileSize.bridgeJSMakeTypeHandle() +} + +extension UserId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UserId.bridgeJSMakeTypeHandle() +} + +extension TokenId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TokenId.bridgeJSMakeTypeHandle() +} + +extension SessionId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SessionId.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() +} + +extension Ratio: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Ratio.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_takesFeatureFlag") fileprivate func bjs_takesFeatureFlag_extern(_ flagBytes: Int32, _ flagLength: Int32) -> Void diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift index 62f9a3b68..0e36253b7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift @@ -104,6 +104,10 @@ public func _bjs_roundtripFooContainer() -> Void { #endif } +extension FooContainer: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FooContainer.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_Foo_init") fileprivate func bjs_Foo_init_extern() -> Int32 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift index b525b5152..745843e34 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift @@ -348,4 +348,12 @@ fileprivate func _bjs_RenamedMembers_wrap_extern(_ pointer: UnsafeMutableRawPoin #endif @inline(never) fileprivate func _bjs_RenamedMembers_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_RenamedMembers_wrap_extern(pointer) +} + +extension RenamedVector: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = RenamedVector.bridgeJSMakeTypeHandle() +} + +extension RenamedEnumMembers: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = RenamedEnumMembers.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift index ed1a080e9..bc910951f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift @@ -176,4 +176,12 @@ fileprivate func _bjs_Player_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Player_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Player_wrap_extern(pointer) +} + +extension User.Stats: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = User.Stats.bridgeJSMakeTypeHandle() +} + +extension Player.Stats: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Player.Stats.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index cfda92ac0..a92716d44 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -1043,4 +1043,20 @@ fileprivate func _bjs_DelegateManager_wrap_extern(_ pointer: UnsafeMutableRawPoi #endif @inline(never) fileprivate func _bjs_DelegateManager_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_DelegateManager_wrap_extern(pointer) +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension ExampleEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ExampleEnum.bridgeJSMakeTypeHandle() +} + +extension Result: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Result.bridgeJSMakeTypeHandle() +} + +extension Priority: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Priority.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index 896258915..1f33a0b1d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -207,4 +207,12 @@ fileprivate func _bjs_MathUtils_wrap_extern(_ pointer: UnsafeMutableRawPointer) #endif @inline(never) fileprivate func _bjs_MathUtils_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_MathUtils_wrap_extern(pointer) +} + +extension Calculator: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Calculator.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index 896258915..1f33a0b1d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -207,4 +207,12 @@ fileprivate func _bjs_MathUtils_wrap_extern(_ pointer: UnsafeMutableRawPointer) #endif @inline(never) fileprivate func _bjs_MathUtils_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_MathUtils_wrap_extern(pointer) +} + +extension Calculator: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Calculator.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift index ded55dbd4..2c6aa9add 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift @@ -338,4 +338,8 @@ fileprivate func _bjs_PropertyClass_wrap_extern(_ pointer: UnsafeMutableRawPoint #endif @inline(never) fileprivate func _bjs_PropertyClass_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_PropertyClass_wrap_extern(pointer) +} + +extension PropertyEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PropertyEnum.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift index ded55dbd4..2c6aa9add 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift @@ -338,4 +338,8 @@ fileprivate func _bjs_PropertyClass_wrap_extern(_ pointer: UnsafeMutableRawPoint #endif @inline(never) fileprivate func _bjs_PropertyClass_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_PropertyClass_wrap_extern(pointer) +} + +extension PropertyEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PropertyEnum.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift index ad99f0a03..b557b423f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift @@ -246,4 +246,32 @@ public func _bjs_Widget_Bounds_static_zero() -> Void { #else fatalError("Only available on WebAssembly") #endif +} + +extension Shape: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Shape.bridgeJSMakeTypeHandle() +} + +extension Widget: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.bridgeJSMakeTypeHandle() +} + +extension Widget.Layout: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Layout.bridgeJSMakeTypeHandle() +} + +extension Widget.Bounds: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Bounds.bridgeJSMakeTypeHandle() +} + +extension Shape.Kind: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Shape.Kind.bridgeJSMakeTypeHandle() +} + +extension Widget.Variant: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Variant.bridgeJSMakeTypeHandle() +} + +extension Widget.Layout.Alignment: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Layout.Alignment.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index c7ac02fb1..cde864d3c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -2637,6 +2637,26 @@ fileprivate func _bjs_TestProcessor_wrap_extern(_ pointer: UnsafeMutableRawPoint return _bjs_TestProcessor_wrap_extern(pointer) } +extension Animal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Animal.bridgeJSMakeTypeHandle() +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Theme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Theme.bridgeJSMakeTypeHandle() +} + +extension HttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = HttpStatus.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index f98038b45..3414b158d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -630,4 +630,40 @@ fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> #endif @inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_Greeter_wrap_extern(pointer) +} + +extension DataPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = DataPoint.bridgeJSMakeTypeHandle() +} + +extension Address: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Address.bridgeJSMakeTypeHandle() +} + +extension Person: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Person.bridgeJSMakeTypeHandle() +} + +extension Session: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Session.bridgeJSMakeTypeHandle() +} + +extension Measurement: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Measurement.bridgeJSMakeTypeHandle() +} + +extension ConfigStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ConfigStruct.bridgeJSMakeTypeHandle() +} + +extension Container: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Container.bridgeJSMakeTypeHandle() +} + +extension Vector2D: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Vector2D.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift index 38ec94c0d..2eb0e70b7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift @@ -46,6 +46,10 @@ fileprivate func _bjs_struct_lift_Point_extern() -> Int32 { return _bjs_struct_lift_Point_extern() } +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_translate") fileprivate func bjs_translate_extern(_ dx: Int32, _ dy: Int32) -> Void diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift index b97729084..93abd19e8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift @@ -177,4 +177,8 @@ public func _bjs_roundTripPointerFields() -> Void { #else fatalError("Only available on WebAssembly") #endif +} + +extension PointerFields: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PointerFields.bridgeJSMakeTypeHandle() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts index e3092afb3..9815b6514 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.d.ts @@ -67,5 +67,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js index 92fb5a109..d8a23090a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js @@ -37,6 +37,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createInnerTagValuesHelpers = () => ({ lower: (value) => { const enumTag = value.tag; @@ -139,6 +449,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -284,12 +595,19 @@ export async function createInstantiator(options, swift) { TestModule["bjs_produceOptionalCanvas"] = function bjs_produceOptionalCanvas() { try { let ret = imports.produceOptionalCanvas(); - const isSome = ret != null; - if (isSome) { - const objId = swift.memory.retain(ret); - i32Stack.push(objId); - } - i32Stack.push(isSome ? 1 : 0); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(ret); } catch (error) { setException(error); } @@ -440,24 +758,29 @@ export async function createInstantiator(options, swift) { return optResult; }, polygonArray: function bjs_polygonArray(polygons) { - for (const elem of polygons) { - ptrStack.push(elem.pointer); - } - i32Stack.push(polygons.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = PolygonReference.__construct(ptr); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(polygons); instance.exports.bjs_polygonArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = PolygonReference.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, validatePolygon: function bjs_validatePolygon(polygon) { @@ -477,35 +800,9 @@ export async function createInstantiator(options, swift) { return TagReference.__construct(ret); }, roundtripTags: function bjs_roundtripTags(xs) { - for (const elem of xs) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const caseId = enumHelpers.InnerTag.lower(elem); - i32Stack.push(caseId); - } - i32Stack.push(isSome); - } - i32Stack.push(xs.length); + __bjs_arrayCodec(__bjs_optionalCodec(__bjs_enumCodec(enumHelpers.InnerTag))).lower(xs); instance.exports.bjs_roundtripTags(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const enumValue = enumHelpers.InnerTag.lift(i32Stack.pop()); - optValue = enumValue; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_enumCodec(enumHelpers.InnerTag))).lift(); return arrayResult; }, describeUser: function bjs_describeUser(owner) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts index 73ea3b570..4d2bab311 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.d.ts @@ -27,5 +27,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js index a38fa118e..cb130421b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts index f48189956..529b16095 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.d.ts @@ -91,5 +91,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index 419cf15d5..39c0507c1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -44,6 +44,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -138,6 +448,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -264,18 +575,7 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_importProcessNumbers"] = function bjs_importProcessNumbers() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); imports.importProcessNumbers(arrayResult); } catch (error) { setException(error); @@ -284,82 +584,34 @@ export async function createInstantiator(options, swift) { TestModule["bjs_importGetNumbers"] = function bjs_importGetNumbers() { try { let ret = imports.importGetNumbers(); - for (const elem of ret) { - f64Stack.push(elem); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importTransformNumbers"] = function bjs_importTransformNumbers() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); let ret = imports.importTransformNumbers(arrayResult); - for (const elem of ret) { - f64Stack.push(elem); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importProcessStrings"] = function bjs_importProcessStrings() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); let ret = imports.importProcessStrings(arrayResult); - for (const elem of ret) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_stringCodec).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importProcessBooleans"] = function bjs_importProcessBooleans() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); let ret = imports.importProcessBooleans(arrayResult); - for (const elem of ret) { - i32Stack.push(elem ? 1 : 0); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(ret); } catch (error) { setException(error); } @@ -442,50 +694,19 @@ export async function createInstantiator(options, swift) { } constructor(nums, strs) { - for (const elem of nums) { - i32Stack.push((elem | 0)); - } - i32Stack.push(nums.length); - for (const elem1 of strs) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(strs.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(nums); + __bjs_arrayCodec(__bjs_stringCodec).lower(strs); const ret = instance.exports.bjs_MultiArrayContainer_init(); return MultiArrayContainer.__construct(ret); } get numbers() { instance.exports.bjs_MultiArrayContainer_numbers_get(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; } get strings() { instance.exports.bjs_MultiArrayContainer_strings_get(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); return arrayResult; } } @@ -494,161 +715,90 @@ export async function createInstantiator(options, swift) { const exports = { processIntArray: function bjs_processIntArray(values) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_processIntArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; }, processStringArray: function bjs_processStringArray(values) { - for (const elem of values) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_stringCodec).lower(values); instance.exports.bjs_processStringArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); return arrayResult; }, processDoubleArray: function bjs_processDoubleArray(values) { - for (const elem of values) { - f64Stack.push(elem); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(values); instance.exports.bjs_processDoubleArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); return arrayResult; }, processBoolArray: function bjs_processBoolArray(values) { - for (const elem of values) { - i32Stack.push(elem ? 1 : 0); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(values); instance.exports.bjs_processBoolArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); return arrayResult; }, processPointArray: function bjs_processPointArray(points) { - for (const elem of points) { - structHelpers.Point.lower(elem); - } - i32Stack.push(points.length); + __bjs_arrayCodec(structHelpers.Point).lower(points); instance.exports.bjs_processPointArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const struct = structHelpers.Point.lift(); - arrayResult.push(struct); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(structHelpers.Point).lift(); return arrayResult; }, processDirectionArray: function bjs_processDirectionArray(directions) { - for (const elem of directions) { - i32Stack.push((elem | 0)); - } - i32Stack.push(directions.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_arrayCodec(elemCodec).lower(directions); instance.exports.bjs_processDirectionArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { const caseId = i32Stack.pop(); - arrayResult.push(caseId); - } - arrayResult.reverse(); - } + return caseId; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processStatusArray: function bjs_processStatusArray(statuses) { - for (const elem of statuses) { - i32Stack.push((elem | 0)); - } - i32Stack.push(statuses.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const rawValue = i32Stack.pop(); + return rawValue; + }, + }; + __bjs_arrayCodec(elemCodec).lower(statuses); instance.exports.bjs_processStatusArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { const rawValue = i32Stack.pop(); - arrayResult.push(rawValue); - } - arrayResult.reverse(); - } + return rawValue; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, sumIntArray: function bjs_sumIntArray(values) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); const ret = instance.exports.bjs_sumIntArray(); return ret; }, findFirstPoint: function bjs_findFirstPoint(points, matching) { - for (const elem of points) { - structHelpers.Point.lower(elem); - } - i32Stack.push(points.length); + __bjs_arrayCodec(structHelpers.Point).lower(points); const matchingBytes = textEncoder.encode(matching); const matchingId = swift.memory.retain(matchingBytes); instance.exports.bjs_findFirstPoint(matchingId, matchingBytes.length); @@ -656,544 +806,318 @@ export async function createInstantiator(options, swift) { return structValue; }, processUnsafeRawPointerArray: function bjs_processUnsafeRawPointerArray(values) { - for (const elem of values) { - ptrStack.push((elem | 0)); - } - i32Stack.push(values.length); + const elemCodec = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + __bjs_arrayCodec(elemCodec).lower(values); instance.exports.bjs_processUnsafeRawPointerArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { const pointer = ptrStack.pop(); - arrayResult.push(pointer); - } - arrayResult.reverse(); - } + return pointer; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processUnsafeMutableRawPointerArray: function bjs_processUnsafeMutableRawPointerArray(values) { - for (const elem of values) { - ptrStack.push((elem | 0)); - } - i32Stack.push(values.length); + const elemCodec = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + __bjs_arrayCodec(elemCodec).lower(values); instance.exports.bjs_processUnsafeMutableRawPointerArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { const pointer = ptrStack.pop(); - arrayResult.push(pointer); - } - arrayResult.reverse(); - } + return pointer; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOpaquePointerArray: function bjs_processOpaquePointerArray(values) { - for (const elem of values) { - ptrStack.push((elem | 0)); - } - i32Stack.push(values.length); + const elemCodec = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + __bjs_arrayCodec(elemCodec).lower(values); instance.exports.bjs_processOpaquePointerArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { const pointer = ptrStack.pop(); - arrayResult.push(pointer); - } - arrayResult.reverse(); - } + return pointer; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOptionalIntArray: function bjs_processOptionalIntArray(values) { - for (const elem of values) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - i32Stack.push((elem | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_processOptionalIntArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const int = i32Stack.pop(); - optValue = int; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lift(); return arrayResult; }, processOptionalStringArray: function bjs_processOptionalStringArray(values) { - for (const elem of values) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(isSome); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_optionalCodec(__bjs_stringCodec)).lower(values); instance.exports.bjs_processOptionalStringArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_stringCodec)).lift(); return arrayResult; }, processOptionalArray: function bjs_processOptionalArray(values) { - const isSome = values != null; - if (isSome) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_processOptionalArray(); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } - optResult = arrayResult; - } else { - optResult = null; - } - return optResult; + const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); + return optValue; }, processOptionalPointArray: function bjs_processOptionalPointArray(points) { - for (const elem of points) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - structHelpers.Point.lower(elem); - } - i32Stack.push(isSome); - } - i32Stack.push(points.length); + __bjs_arrayCodec(__bjs_optionalCodec(structHelpers.Point)).lower(points); instance.exports.bjs_processOptionalPointArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const struct = structHelpers.Point.lift(); - optValue = struct; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(structHelpers.Point)).lift(); return arrayResult; }, processOptionalDirectionArray: function bjs_processOptionalDirectionArray(directions) { - for (const elem of directions) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - i32Stack.push((elem | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(directions.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(directions); instance.exports.bjs_processOptionalDirectionArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const caseId = i32Stack.pop(); - optValue = caseId; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, processOptionalStatusArray: function bjs_processOptionalStatusArray(statuses) { - for (const elem of statuses) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - i32Stack.push((elem | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(statuses.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const rawValue = i32Stack.pop(); + return rawValue; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(statuses); instance.exports.bjs_processOptionalStatusArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const rawValue = i32Stack.pop(); - optValue = rawValue; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const rawValue = i32Stack.pop(); + return rawValue; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, processNestedIntArray: function bjs_processNestedIntArray(values) { - for (const elem of values) { - for (const elem1 of elem) { - i32Stack.push((elem1 | 0)); - } - i32Stack.push(elem.length); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_processNestedIntArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const int = i32Stack.pop(); - arrayResult1.push(int); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); return arrayResult; }, processNestedStringArray: function bjs_processNestedStringArray(values) { - for (const elem of values) { - for (const elem1 of elem) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(elem.length); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_arrayCodec(__bjs_stringCodec)).lower(values); instance.exports.bjs_processNestedStringArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const string = strStack.pop(); - arrayResult1.push(string); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(__bjs_stringCodec)).lift(); return arrayResult; }, processNestedPointArray: function bjs_processNestedPointArray(points) { - for (const elem of points) { - for (const elem1 of elem) { - structHelpers.Point.lower(elem1); - } - i32Stack.push(elem.length); - } - i32Stack.push(points.length); + __bjs_arrayCodec(__bjs_arrayCodec(structHelpers.Point)).lower(points); instance.exports.bjs_processNestedPointArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const struct = structHelpers.Point.lift(); - arrayResult1.push(struct); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(structHelpers.Point)).lift(); return arrayResult; }, processItemArray: function bjs_processItemArray(items) { - for (const elem of items) { - ptrStack.push(elem.pointer); - } - i32Stack.push(items.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Item.__construct(ptr); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(items); instance.exports.bjs_processItemArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Item.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processNestedItemArray: function bjs_processNestedItemArray(items) { - for (const elem of items) { - for (const elem1 of elem) { - ptrStack.push(elem1.pointer); - } - i32Stack.push(elem.length); - } - i32Stack.push(items.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Item.__construct(ptr); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_arrayCodec(elemCodec)).lower(items); instance.exports.bjs_processNestedItemArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - arrayResult1.push(obj); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Item.__construct(ptr); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(elemCodec1)).lift(); return arrayResult; }, processJSObjectArray: function bjs_processJSObjectArray(objects) { - for (const elem of objects) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(objects.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(objects); instance.exports.bjs_processJSObjectArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOptionalJSObjectArray: function bjs_processOptionalJSObjectArray(objects) { - for (const elem of objects) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(elem); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); i32Stack.push(objId); - } - i32Stack.push(isSome); - } - i32Stack.push(objects.length); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(objects); instance.exports.bjs_processOptionalJSObjectArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - optValue = obj; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, processNestedJSObjectArray: function bjs_processNestedJSObjectArray(objects) { - for (const elem of objects) { - for (const elem1 of elem) { - const objId = swift.memory.retain(elem1); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); i32Stack.push(objId); - } - i32Stack.push(elem.length); - } - i32Stack.push(objects.length); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_arrayCodec(elemCodec)).lower(objects); instance.exports.bjs_processNestedJSObjectArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult1.push(obj); - } - arrayResult1.reverse(); - } - arrayResult.push(arrayResult1); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(elemCodec1)).lift(); return arrayResult; }, multiArrayParams: function bjs_multiArrayParams(nums, strs) { - for (const elem of nums) { - i32Stack.push((elem | 0)); - } - i32Stack.push(nums.length); - for (const elem1 of strs) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(strs.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(nums); + __bjs_arrayCodec(__bjs_stringCodec).lower(strs); const ret = instance.exports.bjs_multiArrayParams(); return ret; }, multiOptionalArrayParams: function bjs_multiOptionalArrayParams(a, b) { - const isSome = a != null; - if (isSome) { - for (const elem of a) { - i32Stack.push((elem | 0)); - } - i32Stack.push(a.length); - } - i32Stack.push(+isSome); - const isSome1 = b != null; - if (isSome1) { - for (const elem1 of b) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(b.length); - } - i32Stack.push(+isSome1); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(a); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_stringCodec)).lower(b); const ret = instance.exports.bjs_multiOptionalArrayParams(); return ret; }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts index 507a96d4a..fefbf0039 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts @@ -55,5 +55,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 9f2faf589..497c71bf8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -41,6 +41,227 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + function __bjs_jsValueLower(value) { let kind; let payload1; @@ -223,6 +444,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.AsyncPoint.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -340,18 +562,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_Sa10AsyncPointV"] = function(promise) { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const struct = structHelpers.AsyncPoint.lift(); - arrayResult.push(struct); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(structHelpers.AsyncPoint).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); } catch (error) { setException(error); @@ -359,18 +570,16 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_Sa14AsyncDirectionO"] = function(promise) { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { const caseId = i32Stack.pop(); - arrayResult.push(caseId); - } - arrayResult.reverse(); - } + return caseId; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); } catch (error) { setException(error); @@ -378,13 +587,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_SD10AsyncPointV"] = function(promise) { try { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const struct = structHelpers.AsyncPoint.lift(); - const string = strStack.pop(); - dictResult[string] = struct; - } + const dictResult = __bjs_dictCodec(structHelpers.AsyncPoint).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); } catch (error) { setException(error); @@ -392,13 +595,16 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_SD14AsyncDirectionO"] = function(promise) { try { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const caseId = i32Stack.pop(); - const string = strStack.pop(); - dictResult[string] = caseId; - } + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec).lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); } catch (error) { setException(error); @@ -643,63 +849,53 @@ export async function createInstantiator(options, swift) { return ret1; }, asyncRoundTripOptionalStruct: function bjs_asyncRoundTripOptionalStruct(v) { - const isSome = v != null; - if (isSome) { - structHelpers.AsyncPoint.lower(v); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.AsyncPoint).lower(v); const ret = instance.exports.bjs_asyncRoundTripOptionalStruct(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripStructArray: function bjs_asyncRoundTripStructArray(v) { - for (const elem of v) { - structHelpers.AsyncPoint.lower(elem); - } - i32Stack.push(v.length); + __bjs_arrayCodec(structHelpers.AsyncPoint).lower(v); const ret = instance.exports.bjs_asyncRoundTripStructArray(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripEnumArray: function bjs_asyncRoundTripEnumArray(v) { - for (const elem of v) { - i32Stack.push((elem | 0)); - } - i32Stack.push(v.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_arrayCodec(elemCodec).lower(v); const ret = instance.exports.bjs_asyncRoundTripEnumArray(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripStructDictionary: function bjs_asyncRoundTripStructDictionary(v) { - const entries = Object.entries(v); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - structHelpers.AsyncPoint.lower(value); - } - i32Stack.push(entries.length); + __bjs_dictCodec(structHelpers.AsyncPoint).lower(v); const ret = instance.exports.bjs_asyncRoundTripStructDictionary(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripEnumDictionary: function bjs_asyncRoundTripEnumDictionary(v) { - const entries = Object.entries(v); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - i32Stack.push((value | 0)); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_dictCodec(elemCodec).lower(v); const ret = instance.exports.bjs_asyncRoundTripEnumDictionary(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts index d25336ef7..c0c8900d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js index 98c0aff46..8e09e38d9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js @@ -239,6 +239,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts index e612ae1e1..f1bf7e0c6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts index 491a66795..97a9c23ad 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts index 5537696c4..a2bd7b41b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.d.ts @@ -47,5 +47,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js index 272bb8c49..db3288037 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Account_Credentials.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts index 961b9fa5b..7cec6e66b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.d.ts @@ -161,5 +161,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index ba2b7cc77..16505d112 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -37,6 +37,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createConfigHelpers = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); @@ -162,6 +472,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.MathOperations.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -535,137 +846,51 @@ export async function createInstantiator(options, swift) { return EmptyGreeter.__construct(ret); }, testOptionalStructDefault: function bjs_testOptionalStructDefault(point = null) { - const isSome = point != null; - if (isSome) { - structHelpers.Config.lower(point); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.Config).lower(point); instance.exports.bjs_testOptionalStructDefault(); - const isSome1 = i32Stack.pop(); - const optResult = isSome1 ? structHelpers.Config.lift() : null; - return optResult; + const optValue = __bjs_optionalCodec(structHelpers.Config).lift(); + return optValue; }, testOptionalStructWithValueDefault: function bjs_testOptionalStructWithValueDefault(point = { name: "default", value: 42, enabled: true }) { - const isSome = point != null; - if (isSome) { - structHelpers.Config.lower(point); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.Config).lower(point); instance.exports.bjs_testOptionalStructWithValueDefault(); - const isSome1 = i32Stack.pop(); - const optResult = isSome1 ? structHelpers.Config.lift() : null; - return optResult; + const optValue = __bjs_optionalCodec(structHelpers.Config).lift(); + return optValue; }, testIntArrayDefault: function bjs_testIntArrayDefault(values = [1, 2, 3]) { - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_testIntArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; }, testStringArrayDefault: function bjs_testStringArrayDefault(names = ["a", "b", "c"]) { - for (const elem of names) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(names.length); + __bjs_arrayCodec(__bjs_stringCodec).lower(names); instance.exports.bjs_testStringArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); return arrayResult; }, testDoubleArrayDefault: function bjs_testDoubleArrayDefault(values = [1.5, 2.5, 3.5]) { - for (const elem of values) { - f64Stack.push(elem); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(values); instance.exports.bjs_testDoubleArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); return arrayResult; }, testBoolArrayDefault: function bjs_testBoolArrayDefault(flags = [true, false, true]) { - for (const elem of flags) { - i32Stack.push(elem ? 1 : 0); - } - i32Stack.push(flags.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(flags); instance.exports.bjs_testBoolArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); return arrayResult; }, testEmptyArrayDefault: function bjs_testEmptyArrayDefault(items = []) { - for (const elem of items) { - i32Stack.push((elem | 0)); - } - i32Stack.push(items.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(items); instance.exports.bjs_testEmptyArrayDefault(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return arrayResult; }, testMixedWithArrayDefault: function bjs_testMixedWithArrayDefault(name = "test", values = [10, 20, 30], enabled = true) { const nameBytes = textEncoder.encode(name); const nameId = swift.memory.retain(nameBytes); - for (const elem of values) { - i32Stack.push((elem | 0)); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_testMixedWithArrayDefault(nameId, nameBytes.length, enabled); const ret = tmpRetString; tmpRetString = undefined; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts index 652177cd8..2479e3f25 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts @@ -35,5 +35,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index d0ac5307f..78e1d4c54 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -31,44 +31,328 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createCountersHelpers = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - const entries = Object.entries(value.counts); - for (const entry of entries) { - const [key, value] = entry; - const bytes1 = textEncoder.encode(key); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - const isSome = value != null ? 1 : 0; - if (isSome) { - i32Stack.push((value | 0)); - } - i32Stack.push(isSome); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lower(value.counts); }, lift: () => { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const int = i32Stack.pop(); - optValue = int; - } - const string = strStack.pop(); - dictResult[string] = optValue; - } - const string1 = strStack.pop(); - return { name: string1, counts: dictResult }; + const dictResult = __bjs_dictCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lift(); + const string = strStack.pop(); + return { name: string, counts: dictResult }; } }); @@ -154,6 +438,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Counters.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -262,24 +547,9 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_importMirrorDictionary"] = function bjs_importMirrorDictionary() { try { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const f64 = f64Stack.pop(); - const string = strStack.pop(); - dictResult[string] = f64; - } + const dictResult = __bjs_dictCodec(__bjs_primitiveCodecs.Double).lift(); let ret = imports.importMirrorDictionary(dictResult); - const entries = Object.entries(ret); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - f64Stack.push(value); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_primitiveCodecs.Double).lower(ret); } catch (error) { setException(error); } @@ -361,149 +631,73 @@ export async function createInstantiator(options, swift) { const exports = { mirrorDictionary: function bjs_mirrorDictionary(values) { - const entries = Object.entries(values); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - i32Stack.push((value | 0)); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_primitiveCodecs.Int).lower(values); instance.exports.bjs_mirrorDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const int = i32Stack.pop(); - const string = strStack.pop(); - dictResult[string] = int; - } + const dictResult = __bjs_dictCodec(__bjs_primitiveCodecs.Int).lift(); return dictResult; }, optionalDictionary: function bjs_optionalDictionary(values) { - const isSome = values != null; - if (isSome) { - const entries = Object.entries(values); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const bytes1 = textEncoder.encode(value); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - } - i32Stack.push(entries.length); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(__bjs_dictCodec(__bjs_stringCodec)).lower(values); instance.exports.bjs_optionalDictionary(); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const string = strStack.pop(); - const string1 = strStack.pop(); - dictResult[string1] = string; - } - optResult = dictResult; - } else { - optResult = null; - } - return optResult; + const optValue = __bjs_optionalCodec(__bjs_dictCodec(__bjs_stringCodec)).lift(); + return optValue; }, nestedDictionary: function bjs_nestedDictionary(values) { - const entries = Object.entries(values); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - for (const elem of value) { - i32Stack.push((elem | 0)); - } - i32Stack.push(value.length); - } - i32Stack.push(entries.length); + __bjs_dictCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); instance.exports.bjs_nestedDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i1 = 0; i1 < arrayLen; i1++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } - const string = strStack.pop(); - dictResult[string] = arrayResult; - } + const dictResult = __bjs_dictCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); return dictResult; }, boxDictionary: function bjs_boxDictionary(boxes) { - const entries = Object.entries(boxes); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - ptrStack.push(value.pointer); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Box.__construct(ptr); + return obj; + }, + }; + __bjs_dictCodec(elemCodec).lower(boxes); instance.exports.bjs_boxDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const ptr = ptrStack.pop(); - const obj = Box.__construct(ptr); - const string = strStack.pop(); - dictResult[string] = obj; - } + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Box.__construct(ptr); + return obj; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec1).lift(); return dictResult; }, optionalBoxDictionary: function bjs_optionalBoxDictionary(boxes) { - const entries = Object.entries(boxes); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const isSome = value != null ? 1 : 0; - if (isSome) { - ptrStack.push(value.pointer); - } - i32Stack.push(isSome); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = Box.__construct(ptr); + return obj; + }, + }; + __bjs_dictCodec(__bjs_optionalCodec(elemCodec)).lower(boxes); instance.exports.bjs_optionalBoxDictionary(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { + const elemCodec1 = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Box.__construct(ptr); - optValue = obj; - } - const string = strStack.pop(); - dictResult[string] = optValue; - } + return obj; + }, + }; + const dictResult = __bjs_dictCodec(__bjs_optionalCodec(elemCodec1)).lift(); return dictResult; }, roundtripCounters: function bjs_roundtripCounters(counters) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts index 196ef73fe..f37d8945d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.d.ts @@ -136,5 +136,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js index f29814675..53cd64917 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts index d2772fa8b..4921cd937 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.d.ts @@ -26,5 +26,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js index 42f3fd958..43ff590b4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts index 36fc92474..9e6d967ff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.d.ts @@ -195,5 +195,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 36683fd58..814736050 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -112,6 +112,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -382,48 +692,18 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIOptionalResultValues.Tag.Success: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_stringCodec).lower(value.param0); return APIOptionalResultValues.Tag.Success; } case APIOptionalResultValues.Tag.Failure: { - const isSome = value.param1 != null ? 1 : 0; - if (isSome) { - i32Stack.push(value.param1 ? 1 : 0); - } - i32Stack.push(isSome); - const isSome1 = value.param0 != null ? 1 : 0; - if (isSome1) { - i32Stack.push((value.param0 | 0)); - } - i32Stack.push(isSome1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.param1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.param0); return APIOptionalResultValues.Tag.Failure; } case APIOptionalResultValues.Tag.Status: { - const isSome = value.param2 != null ? 1 : 0; - if (isSome) { - const bytes = textEncoder.encode(value.param2); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - } - i32Stack.push(isSome); - const isSome1 = value.param1 != null ? 1 : 0; - if (isSome1) { - i32Stack.push((value.param1 | 0)); - } - i32Stack.push(isSome1); - const isSome2 = value.param0 != null ? 1 : 0; - if (isSome2) { - i32Stack.push(value.param0 ? 1 : 0); - } - i32Stack.push(isSome2); + __bjs_optionalCodec(__bjs_stringCodec).lower(value.param2); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.param1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.param0); return APIOptionalResultValues.Tag.Status; } default: throw new Error("Unknown APIOptionalResultValues tag: " + String(enumTag)); @@ -433,60 +713,18 @@ export async function createInstantiator(options, swift) { tag = tag | 0; switch (tag) { case APIOptionalResultValues.Tag.Success: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } + const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); return { tag: APIOptionalResultValues.Tag.Success, param0: optValue }; } case APIOptionalResultValues.Tag.Failure: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const bool = i32Stack.pop() !== 0; - optValue = bool; - } - const isSome1 = i32Stack.pop(); - let optValue1; - if (isSome1 === 0) { - optValue1 = null; - } else { - const int = i32Stack.pop(); - optValue1 = int; - } + const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); + const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); return { tag: APIOptionalResultValues.Tag.Failure, param0: optValue1, param1: optValue }; } case APIOptionalResultValues.Tag.Status: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } - const isSome1 = i32Stack.pop(); - let optValue1; - if (isSome1 === 0) { - optValue1 = null; - } else { - const int = i32Stack.pop(); - optValue1 = int; - } - const isSome2 = i32Stack.pop(); - let optValue2; - if (isSome2 === 0) { - optValue2 = null; - } else { - const bool = i32Stack.pop() !== 0; - optValue2 = bool; - } + const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); + const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); + const optValue2 = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); return { tag: APIOptionalResultValues.Tag.Status, param0: optValue2, param1: optValue1, param2: optValue }; } default: throw new Error("Unknown APIOptionalResultValues tag returned from Swift: " + String(tag)); @@ -506,19 +744,29 @@ export async function createInstantiator(options, swift) { return TypedPayloadResultValues.Tag.Direction; } case TypedPayloadResultValues.Tag.OptPrecision: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - f32Stack.push(Math.fround(value.param0)); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return TypedPayloadResultValues.Tag.OptPrecision; } case TypedPayloadResultValues.Tag.OptDirection: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - i32Stack.push((value.param0 | 0)); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return TypedPayloadResultValues.Tag.OptDirection; } case TypedPayloadResultValues.Tag.Empty: { @@ -539,25 +787,29 @@ export async function createInstantiator(options, swift) { return { tag: TypedPayloadResultValues.Tag.Direction, param0: caseId }; } case TypedPayloadResultValues.Tag.OptPrecision: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const rawValue = f32Stack.pop(); - optValue = rawValue; - } + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: TypedPayloadResultValues.Tag.OptPrecision, param0: optValue }; } case TypedPayloadResultValues.Tag.OptDirection: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const caseId = i32Stack.pop(); - optValue = caseId; - } + const elemCodec = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: TypedPayloadResultValues.Tag.OptDirection, param0: optValue }; } case TypedPayloadResultValues.Tag.Empty: return { tag: TypedPayloadResultValues.Tag.Empty }; @@ -588,10 +840,7 @@ export async function createInstantiator(options, swift) { return AllTypesResultValues.Tag.NestedEnum; } case AllTypesResultValues.Tag.ArrayPayload: { - for (const elem of value.param0) { - i32Stack.push((elem | 0)); - } - i32Stack.push(value.param0.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(value.param0); return AllTypesResultValues.Tag.ArrayPayload; } case AllTypesResultValues.Tag.Empty: { @@ -623,18 +872,7 @@ export async function createInstantiator(options, swift) { return { tag: AllTypesResultValues.Tag.NestedEnum, param0: enumValue }; } case AllTypesResultValues.Tag.ArrayPayload: { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); return { tag: AllTypesResultValues.Tag.ArrayPayload, param0: arrayResult }; } case AllTypesResultValues.Tag.Empty: return { tag: AllTypesResultValues.Tag.Empty }; @@ -647,48 +885,45 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case OptionalAllTypesResultValues.Tag.OptStruct: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - structHelpers.Point.lower(value.param0); - } - i32Stack.push(isSome); + __bjs_optionalCodec(structHelpers.Point).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptStruct; } case OptionalAllTypesResultValues.Tag.OptClass: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - ptrStack.push(value.param0.pointer); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['User'].__construct(ptr); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptClass; } case OptionalAllTypesResultValues.Tag.OptJSObject: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(value.param0); - i32Stack.push(objId); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptJSObject; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - const caseId = enumHelpers.APIResult.lower(value.param0); - i32Stack.push(caseId); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_enumCodec(enumHelpers.APIResult)).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptNestedEnum; } case OptionalAllTypesResultValues.Tag.OptArray: { - const isSome = value.param0 != null ? 1 : 0; - if (isSome) { - for (const elem of value.param0) { - i32Stack.push((elem | 0)); - } - i32Stack.push(value.param0.length); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(value.param0); return OptionalAllTypesResultValues.Tag.OptArray; } case OptionalAllTypesResultValues.Tag.Empty: { @@ -701,72 +936,45 @@ export async function createInstantiator(options, swift) { tag = tag | 0; switch (tag) { case OptionalAllTypesResultValues.Tag.OptStruct: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const struct = structHelpers.Point.lift(); - optValue = struct; - } + const optValue = __bjs_optionalCodec(structHelpers.Point).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptStruct, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptClass: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const ptr = ptrStack.pop(); - const obj = _exports['User'].__construct(ptr); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['User'].__construct(ptr); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptClass, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptJSObject: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptJSObject, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const enumValue = enumHelpers.APIResult.lift(i32Stack.pop()); - optValue = enumValue; - } + const optValue = __bjs_optionalCodec(__bjs_enumCodec(enumHelpers.APIResult)).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptNestedEnum, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptArray: { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } - optValue = arrayResult; - } + const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optValue }; } case OptionalAllTypesResultValues.Tag.Empty: return { tag: OptionalAllTypesResultValues.Tag.Empty }; @@ -856,6 +1064,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts index d29256af4..c980b7dbf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts @@ -35,5 +35,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js index de374bd70..a31c96450 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts index 5581df31e..8ea0aa79b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.d.ts @@ -56,5 +56,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index c2ae031bb..169ade160 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts index fe48c9174..03e210f3c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js index f2d6b8750..fa128130a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts index 0ca8b16b9..403ef2149 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts @@ -154,5 +154,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index 6c45f0333..859703175 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts index b5a85a082..f5d357a64 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.d.ts @@ -115,5 +115,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index 2a9e7948a..81c1eacd9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts index fbd5ad637..e43673e7a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts @@ -169,5 +169,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 9e18a8d80..ac8dc0ff5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -106,6 +106,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -182,6 +492,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -448,15 +759,17 @@ export async function createInstantiator(options, swift) { roundTripOptionalFileSize: function bjs_roundTripOptionalFileSize(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalFileSize(+isSome, isSome ? input : 0n); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const rawValue = i64Stack.pop(); - optResult = rawValue; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const rawValue = i64Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, setUserId: function bjs_setUserId(id) { instance.exports.bjs_setUserId(id); @@ -496,15 +809,17 @@ export async function createInstantiator(options, swift) { roundTripOptionalSessionId: function bjs_roundTripOptionalSessionId(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalSessionId(+isSome, isSome ? input : 0n); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const rawValue = i64Stack.pop(); - optResult = rawValue; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const rawValue = i64Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, setPrecision: function bjs_setPrecision(precision) { instance.exports.bjs_setPrecision(precision); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts index d6ab5aa8f..3eea52594 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts index 312f56786..e4754d8e0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts index ae1152016..0dbdafe7b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts index 02d17c011..64acfac35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts @@ -38,5 +38,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts index 02d17c011..64acfac35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts @@ -38,5 +38,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts index 02d17c011..64acfac35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts @@ -38,5 +38,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts index cd4f822e2..e0da68c50 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 07341894e..bf1707b56 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -207,41 +517,16 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_roundtrip"] = function bjs_roundtrip() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); let ret = imports.roundtrip(arrayResult); - for (const elem of ret) { - i32Stack.push((elem | 0)); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(ret); } catch (error) { setException(error); } } TestModule["bjs_logStrings"] = function bjs_logStrings() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); imports.logStrings(arrayResult); } catch (error) { setException(error); @@ -251,34 +536,12 @@ export async function createInstantiator(options, swift) { try { let optResult; if (a) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); optResult = arrayResult; } else { optResult = null; } - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const int1 = i32Stack.pop(); - arrayResult1.push(int1); - } - arrayResult1.reverse(); - } + const arrayResult1 = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); let ret = imports.optionalArrayThenArray(optResult, arrayResult1); return ret; } catch (error) { @@ -291,34 +554,12 @@ export async function createInstantiator(options, swift) { const string = decodeString(sBytes, sCount); let optResult; if (a) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); optResult = arrayResult; } else { optResult = null; } - const arrayLen1 = i32Stack.pop(); - let arrayResult1; - if (arrayLen1 === -1) { - arrayResult1 = taStack.pop(); - } else { - arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const int1 = i32Stack.pop(); - arrayResult1.push(int1); - } - arrayResult1.reverse(); - } + const arrayResult1 = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); let ret = imports.borrowedStringAroundStackParams(string, optResult, arrayResult1); return ret; } catch (error) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts index 22b4e6a1c..1d5f31efd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.d.ts @@ -26,5 +26,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 4328e4d4e..8974e3722 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createFooContainerHelpers = () => ({ lower: (value) => { let id; @@ -40,24 +350,34 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalFoo != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(value.optionalFoo); - i32Stack.push(objId); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.optionalFoo); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); const objectId = i32Stack.pop(); let value; if (objectId !== 0) { @@ -152,6 +472,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.FooContainer.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -289,60 +610,63 @@ export async function createInstantiator(options, swift) { return ret1; }, processFooArray: function bjs_processFooArray(foos) { - for (const elem of foos) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(foos.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(foos); instance.exports.bjs_processFooArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processOptionalFooArray: function bjs_processOptionalFooArray(foos) { - for (const elem of foos) { - const isSome = elem != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(elem); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); i32Stack.push(objId); - } - i32Stack.push(isSome); - } - i32Stack.push(foos.length); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(foos); instance.exports.bjs_processOptionalFooArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const isSome1 = i32Stack.pop(); - let optValue; - if (isSome1 === 0) { - optValue = null; - } else { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - optValue = obj; - } - arrayResult.push(optValue); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); return arrayResult; }, roundtripFooContainer: function bjs_roundtripFooContainer(container) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts index ac0e05a91..edc243baa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.d.ts @@ -33,5 +33,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts index aaf227cf7..e6dfad7fa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.d.ts @@ -27,5 +27,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts index 3b2b5de99..3cb232260 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.d.ts @@ -28,5 +28,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts index a6267bd31..b0c2eff74 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts index 818d57a9d..e9f73cfae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.d.ts @@ -13,5 +13,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts index 624691d83..9afd16f74 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts index d31aeebe3..d6cbf725c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts @@ -64,5 +64,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js index 543ae05f0..026acf3f4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js @@ -135,6 +135,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.RenamedVector.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts index b842e7d7d..c77ca0828 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts index 85109479e..951f1e7aa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.d.ts @@ -36,5 +36,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index ae59008ba..f39091a1f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -31,6 +31,227 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + function __bjs_jsValueLower(value) { let kind; let payload1; @@ -316,29 +537,9 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_jsEchoJSValueArray"] = function bjs_jsEchoJSValueArray() { try { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const jsValuePayload2 = f64Stack.pop(); - const jsValuePayload1 = i32Stack.pop(); - const jsValueKind = i32Stack.pop(); - const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); - arrayResult.push(jsValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lift(); let ret = imports.jsEchoJSValueArray(arrayResult); - for (const elem of ret) { - const [elemKind, elemPayload1, elemPayload2] = __bjs_jsValueLower(elem); - i32Stack.push(elemKind); - i32Stack.push(elemPayload1); - f64Stack.push(elemPayload2); - } - i32Stack.push(ret.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lower(ret); } catch (error) { setException(error); } @@ -564,67 +765,16 @@ export async function createInstantiator(options, swift) { return optResult; }, roundTripJSValueArray: function bjs_roundTripJSValueArray(values) { - for (const elem of values) { - const [elemKind, elemPayload1, elemPayload2] = __bjs_jsValueLower(elem); - i32Stack.push(elemKind); - i32Stack.push(elemPayload1); - f64Stack.push(elemPayload2); - } - i32Stack.push(values.length); + __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lower(values); instance.exports.bjs_roundTripJSValueArray(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const jsValuePayload2 = f64Stack.pop(); - const jsValuePayload1 = i32Stack.pop(); - const jsValueKind = i32Stack.pop(); - const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); - arrayResult.push(jsValue); - } - arrayResult.reverse(); - } + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lift(); return arrayResult; }, roundTripOptionalJSValueArray: function bjs_roundTripOptionalJSValueArray(values) { - const isSome = values != null; - if (isSome) { - for (const elem of values) { - const [elemKind, elemPayload1, elemPayload2] = __bjs_jsValueLower(elem); - i32Stack.push(elemKind); - i32Stack.push(elemPayload1); - f64Stack.push(elemPayload2); - } - i32Stack.push(values.length); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.JSValue)).lower(values); instance.exports.bjs_roundTripOptionalJSValueArray(); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const jsValuePayload2 = f64Stack.pop(); - const jsValuePayload1 = i32Stack.pop(); - const jsValueKind = i32Stack.pop(); - const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); - arrayResult.push(jsValue); - } - arrayResult.reverse(); - } - optResult = arrayResult; - } else { - optResult = null; - } - return optResult; + const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.JSValue)).lift(); + return optValue; }, JSValueHolder, }; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts index c7ff9a39c..737e94bce 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts index 01a392e91..88d337296 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts @@ -51,5 +51,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts index 89aad5c32..634065017 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts index ac9ea13c4..76daa290c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts @@ -126,5 +126,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index aa5e3dbb4..fcb6dd88d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -356,19 +666,17 @@ export async function createInstantiator(options, swift) { } getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Greeter.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); return arrayResult; } addItem(item) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts index debd3ffcf..59961720b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts @@ -73,5 +73,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 9a5c6473e..ef083c4d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -356,19 +666,17 @@ export async function createInstantiator(options, swift) { } getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { const ptr = ptrStack.pop(); const obj = Greeter.__construct(ptr); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); return arrayResult; } addItem(item) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts index c418ed8a5..5dfb48fcf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts @@ -42,5 +42,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index 972f9ae74..e03b09221 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -145,6 +145,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Player_Stats.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts index 0f64324cd..324947e18 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts @@ -82,5 +82,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 5a253cdc0..0a4fcc28c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + return { /** @@ -314,12 +624,19 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WithOptionalJSClass_childOrNull_get"] = function bjs_WithOptionalJSClass_childOrNull_get(self) { try { let ret = swift.memory.getObject(self).childOrNull; - const isSome = ret != null; - if (isSome) { - const objId = swift.memory.retain(ret); - i32Stack.push(objId); - } - i32Stack.push(isSome ? 1 : 0); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(ret); } catch (error) { setException(error); } @@ -490,12 +807,19 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WithOptionalJSClass_roundTripChildOrNull"] = function bjs_WithOptionalJSClass_roundTripChildOrNull(self, valueIsSome, valueObjectId) { try { let ret = swift.memory.getObject(self).roundTripChildOrNull(valueIsSome ? swift.memory.getObject(valueObjectId) : null); - const isSome = ret != null; - if (isSome) { - const objId = swift.memory.retain(ret); - i32Stack.push(objId); - } - i32Stack.push(isSome ? 1 : 0); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(ret); } catch (error) { setException(error); } @@ -722,17 +1046,20 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.bjs_roundTripExportedOptionalJSObject(+isSome, result); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optResult = obj; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, roundTripExportedOptionalJSClass: function bjs_roundTripExportedOptionalJSClass(value) { const isSome = value != null; @@ -743,17 +1070,20 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.bjs_roundTripExportedOptionalJSClass(+isSome, result); - const isSome1 = i32Stack.pop(); - let optResult; - if (isSome1) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optResult = obj; - } else { - optResult = null; - } - return optResult; + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + return optValue; }, roundTripString: function bjs_roundTripString(name) { const isSome = name != null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts index 961f97635..19680ec06 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.d.ts @@ -15,5 +15,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts index 77e269d16..a28a7b4bb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.d.ts @@ -20,5 +20,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts index 5872a3020..d7cd0e2e6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.d.ts @@ -44,5 +44,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts index a413fa500..f55109d2b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts @@ -119,5 +119,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index b2a894ffa..e2c711f8f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -55,6 +55,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createResultValuesHelpers = () => ({ lower: (value) => { const enumTag = value.tag; @@ -163,6 +473,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -724,11 +1035,19 @@ export async function createInstantiator(options, swift) { } constructor(delegates) { - for (const elem of delegates) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(delegates.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(delegates); const ret = instance.exports.bjs_DelegateManager_init(); return DelegateManager.__construct(ret); } @@ -737,55 +1056,68 @@ export async function createInstantiator(options, swift) { } get delegates() { instance.exports.bjs_DelegateManager_delegates_get(this.pointer); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { const objId = i32Stack.pop(); const obj = swift.memory.getObject(objId); swift.memory.release(objId); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec).lift(); return arrayResult; } set delegates(value) { - for (const elem of value) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(value.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(value); instance.exports.bjs_DelegateManager_delegates_set(this.pointer); } get delegatesByName() { instance.exports.bjs_DelegateManager_delegatesByName_get(this.pointer); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - const string = strStack.pop(); - dictResult[string] = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec).lift(); return dictResult; } set delegatesByName(value) { - const entries = Object.entries(value); - for (const entry of entries) { - const [key, value1] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const objId = swift.memory.retain(value1); - i32Stack.push(objId); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_dictCodec(elemCodec).lower(value); instance.exports.bjs_DelegateManager_delegatesByName_set(this.pointer); } } @@ -794,50 +1126,63 @@ export async function createInstantiator(options, swift) { const exports = { processDelegates: function bjs_processDelegates(delegates) { - for (const elem of delegates) { - const objId = swift.memory.retain(elem); - i32Stack.push(objId); - } - i32Stack.push(delegates.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_arrayCodec(elemCodec).lower(delegates); instance.exports.bjs_processDelegates(); - const arrayLen = i32Stack.pop(); - let arrayResult; - if (arrayLen === -1) { - arrayResult = taStack.pop(); - } else { - arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - arrayResult.push(obj); - } - arrayResult.reverse(); - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); return arrayResult; }, processDelegatesByName: function bjs_processDelegatesByName(delegates) { - const entries = Object.entries(delegates); - for (const entry of entries) { - const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - const objId = swift.memory.retain(value); - i32Stack.push(objId); - } - i32Stack.push(entries.length); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_dictCodec(elemCodec).lower(delegates); instance.exports.bjs_processDelegatesByName(); - const dictLen = i32Stack.pop(); - const dictResult = {}; - for (let i = 0; i < dictLen; i++) { - const objId1 = i32Stack.pop(); - const obj = swift.memory.getObject(objId1); - swift.memory.release(objId1); - const string = strStack.pop(); - dictResult[string] = obj; - } + const elemCodec1 = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const dictResult = __bjs_dictCodec(elemCodec1).lift(); return dictResult; }, Direction: DirectionValues, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts index 7d5a3c9aa..ce87ccd29 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts @@ -34,5 +34,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts index e5602e42d..b97a1bd8e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts @@ -73,5 +73,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 25f989a00..8f783865e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts index a168f3ad1..6176abb6f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts @@ -63,5 +63,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index ca4093992..4841e3350 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts index b54e14def..42cfe5870 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.d.ts @@ -68,5 +68,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 63dd9cba5..189db1f0e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts index aea927c79..42ff8507c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.d.ts @@ -54,5 +54,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index b5680b9b0..a5a003a1c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts index 5e45162a1..8d562d13a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts index b43ff062c..667db342e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.d.ts @@ -15,5 +15,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts index fe4708fd8..cf231e076 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.d.ts @@ -69,5 +69,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js index ee5cc0a3e..3270abd58 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js @@ -193,6 +193,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Widget_Bounds.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 2f56a1cb8..d0c84e109 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -43,5 +43,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts index 70f23c11a..81fd7f109 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts @@ -114,5 +114,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 62c2de8c6..bebe9179d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -61,6 +61,227 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + function __bjs_jsValueLower(value) { let kind; let payload1; @@ -330,6 +551,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Animal.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -863,32 +1085,23 @@ export async function createInstantiator(options, swift) { optResult = null; } let ret = callback(optResult); - const isSome = ret != null; - if (isSome) { - structHelpers.Animal.lower(ret); - } - i32Stack.push(isSome ? 1 : 0); + __bjs_optionalCodec(structHelpers.Animal).lower(ret); } catch (error) { setException(error); } } bjs["make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV = function(param0) { - const isSome = param0 != null; - if (isSome) { - structHelpers.Animal.lower(param0); - } - i32Stack.push(+isSome); + __bjs_optionalCodec(structHelpers.Animal).lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(boxPtr); - const isSome1 = i32Stack.pop(); - const optResult = isSome1 ? structHelpers.Animal.lift() : null; + const optValue = __bjs_optionalCodec(structHelpers.Animal).lift(); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); tmpRetException = undefined; throw error; } - return optResult; + return optValue; }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts index b66f960f8..47f1b89f9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts @@ -17,5 +17,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts index 3b394fb06..3503e138e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -90,5 +90,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index 92a99becb..c16b674ae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -36,6 +36,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createDataPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -44,34 +354,12 @@ export async function createInstantiator(options, swift) { const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - const isSome = value.optCount != null ? 1 : 0; - if (isSome) { - i32Stack.push((value.optCount | 0)); - } - i32Stack.push(isSome); - const isSome1 = value.optFlag != null ? 1 : 0; - if (isSome1) { - i32Stack.push(value.optFlag ? 1 : 0); - } - i32Stack.push(isSome1); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.optCount); + __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.optFlag); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const bool = i32Stack.pop() !== 0; - optValue = bool; - } - const isSome1 = i32Stack.pop(); - let optValue1; - if (isSome1 === 0) { - optValue1 = null; - } else { - const int = i32Stack.pop(); - optValue1 = int; - } + const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); + const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); const string = strStack.pop(); const f64 = f64Stack.pop(); const f641 = f64Stack.pop(); @@ -88,21 +376,10 @@ export async function createInstantiator(options, swift) { const id1 = swift.memory.retain(bytes1); i32Stack.push(bytes1.length); i32Stack.push(id1); - const isSome = value.zipCode != null ? 1 : 0; - if (isSome) { - i32Stack.push((value.zipCode | 0)); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.zipCode); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const int = i32Stack.pop(); - optValue = int; - } + const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); const string = strStack.pop(); const string1 = strStack.pop(); return { street: string1, city: string, zipCode: optValue }; @@ -116,28 +393,14 @@ export async function createInstantiator(options, swift) { i32Stack.push(id); i32Stack.push((value.age | 0)); structHelpers.Address.lower(value.address); - const isSome = value.email != null ? 1 : 0; - if (isSome) { - const bytes1 = textEncoder.encode(value.email); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); - i32Stack.push(id1); - } - i32Stack.push(isSome); + __bjs_optionalCodec(__bjs_stringCodec).lower(value.email); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const string = strStack.pop(); - optValue = string; - } + const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); const struct = structHelpers.Address.lift(); const int = i32Stack.pop(); - const string1 = strStack.pop(); - return { name: string1, age: int, address: struct, email: optValue }; + const string = strStack.pop(); + return { name: string, age: int, address: struct, email: optValue }; } }); const __bjs_createSessionHelpers = () => ({ @@ -156,24 +419,31 @@ export async function createInstantiator(options, swift) { lower: (value) => { f64Stack.push(value.value); f32Stack.push(Math.fround(value.precision)); - const isSome = value.optionalPrecision != null ? 1 : 0; - if (isSome) { - f32Stack.push(Math.fround(value.optionalPrecision)); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.optionalPrecision); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const rawValue = f32Stack.pop(); - optValue = rawValue; - } - const rawValue1 = f32Stack.pop(); + const elemCodec = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); + const rawValue = f32Stack.pop(); const f64 = f64Stack.pop(); - return { value: f64, precision: rawValue1, optionalPrecision: optValue }; + return { value: f64, precision: rawValue, optionalPrecision: optValue }; } }); const __bjs_createConfigStructHelpers = () => ({ @@ -192,24 +462,34 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const isSome = value.optionalObject != null ? 1 : 0; - if (isSome) { - const objId = swift.memory.retain(value.optionalObject); - i32Stack.push(objId); - } - i32Stack.push(isSome); + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + __bjs_optionalCodec(elemCodec).lower(value.optionalObject); }, lift: () => { - const isSome = i32Stack.pop(); - let optValue; - if (isSome === 0) { - optValue = null; - } else { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optValue = obj; - } + const elemCodec = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const optValue = __bjs_optionalCodec(elemCodec).lift(); const objectId = i32Stack.pop(); let value; if (objectId !== 0) { @@ -382,6 +662,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Vector2D.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts index e97b50fda..e95b78349 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts @@ -19,5 +19,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index 4a2e18d6b..9d613c8a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -31,6 +31,316 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + const __bjs_createPointHelpers = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); @@ -125,6 +435,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; @@ -242,11 +553,7 @@ export async function createInstantiator(options, swift) { optResult = null; } let ret = imports.roundTripOptional(optResult); - const isSome = ret != null; - if (isSome) { - structHelpers.Point.lower(ret); - } - i32Stack.push(isSome ? 1 : 0); + __bjs_optionalCodec(structHelpers.Point).lower(ret); } catch (error) { setException(error); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts index 99adf95b6..606de53ad 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts @@ -29,5 +29,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts index 9199ad1ae..13dccd568 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.d.ts @@ -14,5 +14,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts index 5a4ee78ce..b1ecc2000 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.d.ts @@ -34,5 +34,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index 457bfa973..704dbb021 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.PointerFields.lift(); return swift.memory.retain(value); } + bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts index 7acba67a0..d15ce0a8a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.d.ts @@ -15,5 +15,6 @@ export function createInstantiator(options: { }, swift: any): Promise<{ addImports: (importObject: WebAssembly.Imports) => void; setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; createExports: (instance: WebAssembly.Instance) => Exports; }>; \ No newline at end of file diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 36d840099..6181afe48 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -74,6 +74,8 @@ async function createInstantiator(options, swift) { }, /** @param {WebAssembly.Instance} instance */ setInstance: (instance) => {}, + /** Called once the instance is fully initialized and Swift code may run. */ + afterInitialize: () => {}, /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { return {}; @@ -84,17 +86,18 @@ async function createInstantiator(options, swift) { /** @type {import('./instantiate.d').instantiate} */ export async function instantiate(options) { - const result = await _instantiate(options); + const { instantiator, ...result } = await _instantiate(options); /* #if IS_WASI */ options.wasi.initialize(result.instance); /* #endif */ + instantiator.afterInitialize?.(); result.swift.main(); return result; } /** @type {import('./instantiate.d').instantiateForThread} */ export async function instantiateForThread(tid, startArg, options) { - const result = await _instantiate(options); + const { instantiator, ...result } = await _instantiate(options); /* #if IS_WASI */ options.wasi.setInstance(result.instance); /* #endif */ @@ -102,7 +105,7 @@ export async function instantiateForThread(tid, startArg, options) { return result; } -/** @type {import('./instantiate.d').instantiate} */ +/** @param {import('./instantiate.d').InstantiateOptions} options */ async function _instantiate(options) { const _WebAssembly = options.WebAssembly || WebAssembly; const moduleSource = options.module; @@ -184,5 +187,6 @@ async function _instantiate(options) { instance, swift, exports, + instantiator, }; } diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 4eeae4dac..b15e07b5d 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -204,6 +204,58 @@ extension _BridgedSwiftStackType { } } +/// Types usable as the generic argument of a generic imported `@JSFunction`. +/// Each conforming type owns a ``BridgeJSTypeHandle`` whose pointer is the +/// runtime type ID that selects the matching JS codec. Do not conform types by +/// hand; marking them `@JS` emits the conformance together with the JS codec. +public protocol BridgedSwiftGenericBridgeable: _BridgedSwiftStackType +where StackLiftResult == Self { + @_spi(BridgeJS) static var bridgeJSTypeHandle: BridgeJSTypeHandle { get } +} + +extension BridgedSwiftGenericBridgeable { + /// The runtime type ID passed across the bridge for this type. + @_spi(BridgeJS) public static var bridgeJSTypeID: Int32 { bridgeJSTypeHandle.typeID } + + /// Creates the type's unique handle. A generic static function so + /// conformances compile under Embedded Swift. + @_spi(BridgeJS) public static func bridgeJSMakeTypeHandle() -> BridgeJSTypeHandle { + #if hasFeature(Embedded) + return BridgeJSTypeHandle() + #else + return BridgeJSTypeHandle(Self.self) + #endif + } +} + +/// A per-type identity token for generic bridging: each conforming type stores +/// exactly one handle in a `static let`, so the handle's pointer identifies the +/// type at runtime without relying on type names, which could collide across +/// modules. +public final class BridgeJSTypeHandle: Sendable { + #if hasFeature(Embedded) + public init() {} + #else + /// The conforming type, for exported generics (planned follow-up) to map a + /// type ID back to. `nonisolated(unsafe)`: an immutable metatype is safe to + /// share, but the compiler cannot infer that. + public nonisolated(unsafe) let type: any BridgedSwiftGenericBridgeable.Type + + public init(_ type: any BridgedSwiftGenericBridgeable.Type) { + self.type = type + } + #endif + + /// The handle object's own address; pointers are 32-bit on wasm32. + @_spi(BridgeJS) public var typeID: Int32 { + #if arch(wasm32) + return Int32(bitPattern: UInt32(UInt(bitPattern: Unmanaged.passUnretained(self).toOpaque()))) + #else + _onlyAvailableOnWasm() + #endif + } +} + /// Types that bridge with the same (isSome, value) ABI as Optional. /// Used by JSUndefinedOr so all bridge methods delegate to Optional. public protocol _BridgedAsOptional { @@ -808,6 +860,49 @@ extension String: _BridgedSwiftStackType { } } +extension Bool: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Bool.bridgeJSMakeTypeHandle() +} +extension Int: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int.bridgeJSMakeTypeHandle() +} +extension Float: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Float.bridgeJSMakeTypeHandle() +} +extension Double: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Double.bridgeJSMakeTypeHandle() +} +extension String: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = String.bridgeJSMakeTypeHandle() +} +extension UInt: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt.bridgeJSMakeTypeHandle() +} +extension Int8: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int8.bridgeJSMakeTypeHandle() +} +extension UInt8: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt8.bridgeJSMakeTypeHandle() +} +extension Int16: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int16.bridgeJSMakeTypeHandle() +} +extension UInt16: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt16.bridgeJSMakeTypeHandle() +} +extension Int32: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int32.bridgeJSMakeTypeHandle() +} +extension UInt32: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt32.bridgeJSMakeTypeHandle() +} +extension Int64: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Int64.bridgeJSMakeTypeHandle() +} +extension UInt64: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = UInt64.bridgeJSMakeTypeHandle() +} + extension JSObject: _BridgedSwiftStackType { // JSObject is a non-final class, so we must explicitly specify the associated type // rather than relying on the default `Self` (which Swift requires for covariant returns). @@ -914,6 +1009,10 @@ extension JSValue: _BridgedSwiftStackType { } } +extension JSValue: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = JSValue.bridgeJSMakeTypeHandle() +} + /// A protocol that Swift heap objects exposed to JavaScript via `@JS class` must conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md index 9c0a80dc1..5a47746d6 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Generating-from-TypeScript.md @@ -416,4 +416,4 @@ When a TypeScript name is not a valid Swift identifier (e.g. contains dashes, sp ## Limitations - No first-class support for async/Promise-returning functions;. -- No generic type parameter can appear on a bridged function signature. \ No newline at end of file +- No generic type parameter can appear on a bridged function signature generated from TypeScript; a type parameter is lowered to `JSObject`. Generic imports are available only through `@JSFunction` declarations written in Swift — see . \ No newline at end of file diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md index 1b2be6cb0..ebc9ac857 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Importing-JavaScript/Importing-JS-Function.md @@ -77,11 +77,23 @@ If you used `from: .global` or `.module`, do not pass the function in `getImport Bound functions are `throws(JSException)`. Call them with `try` or `try?`; they throw when the JavaScript implementation throws. +## Generic functions + +A `@JSFunction` can be generic over a type parameter constrained to `BridgedSwiftGenericBridgeable`, so one declaration serves every bridged type: + +```swift +@JSFunction func parse(_ json: String) throws(JSException) -> T + +let user: User = try parse(jsonString) // T inferred from the call site +``` + +`T` can be any supported primitive, `String`, `JSValue`, or a `@JS` struct, `@JS` enum, or `final @JS class` (see ), used bare or wrapped as `[T]`, `T?`, or `[String: T]`. A function may declare multiple type parameters, and a return-only generic (`func make() -> T`) works too. Generic initializers, methods, and static methods on `@JSClass` types are supported the same way. `async` generic functions and `where` clauses are not supported. + ## Supported features | Feature | Status | |:--|:--| | Primitive parameter/result types (e.g. `Double`, `Bool`) | ✅ | | `String` parameter/result type | ✅ | +| Generic parameter/result types (constrained to `BridgedSwiftGenericBridgeable`) | ✅ | | Async function | ❌ | -| Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md index 5c609ab72..539f7ce15 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md @@ -31,6 +31,10 @@ When using `JSTypedArray` (or convenience typealiases) in `@JS` signatures, t See for usage details. +## Generic type parameters + +An imported `@JSFunction` can be generic over a type parameter constrained to `BridgedSwiftGenericBridgeable` (see ); exported `@JS` functions cannot yet. The constraint is satisfied by all supported primitives, `String`, `JSValue`, and any `@JS` struct, `@JS` enum, or `final @JS class`, including ones from another linked module. Do not write the conformance by hand; marking the type `@JS` is what provides it, together with the JavaScript side of the bridge. + ## See Also - diff --git a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift index 4e35a1c9f..deedc1ccf 100644 --- a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift @@ -353,4 +353,53 @@ fileprivate func _bjs_GlobalUtils_PublicConverter_wrap_extern(_ pointer: UnsafeM #endif @inline(never) fileprivate func _bjs_GlobalUtils_PublicConverter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_GlobalUtils_PublicConverter_wrap_extern(pointer) -} \ No newline at end of file +} + +extension GlobalNetworking.API.CallMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GlobalNetworking.API.CallMethod.bridgeJSMakeTypeHandle() +} + +extension GlobalConfiguration.PublicLogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GlobalConfiguration.PublicLogLevel.bridgeJSMakeTypeHandle() +} + +extension GlobalConfiguration.AvailablePort: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GlobalConfiguration.AvailablePort.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedServerMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedServerMethod.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_BridgeJSGlobalTests_register_type_handles") +fileprivate func _bjs_BridgeJSGlobalTests_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_BridgeJSGlobalTests_register_type_handles") +public func _bjs_BridgeJSGlobalTests_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + GlobalNetworking.API.CallMethod.bridgeJSTypeID, + GlobalConfiguration.PublicLogLevel.bridgeJSTypeID, + GlobalConfiguration.AvailablePort.bridgeJSTypeID, + Internal.SupportedServerMethod.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_BridgeJSGlobalTests_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 6c5fe3b05..156f044d2 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -13608,6 +13608,246 @@ fileprivate func _bjs_LeakCheck_wrap_extern(_ pointer: UnsafeMutableRawPointer) return _bjs_LeakCheck_wrap_extern(pointer) } +extension JSCoordinate: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = JSCoordinate.bridgeJSMakeTypeHandle() +} + +extension NestedStructGroupA.Metadata: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedStructGroupA.Metadata.bridgeJSMakeTypeHandle() +} + +extension NestedStructGroupB.Metadata: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedStructGroupB.Metadata.bridgeJSMakeTypeHandle() +} + +extension NestedTypeHost.Label: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedTypeHost.Label.bridgeJSMakeTypeHandle() +} + +extension Point: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() +} + +extension PointerFields: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PointerFields.bridgeJSMakeTypeHandle() +} + +extension DataPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = DataPoint.bridgeJSMakeTypeHandle() +} + +extension PublicPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PublicPoint.bridgeJSMakeTypeHandle() +} + +extension Address: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Address.bridgeJSMakeTypeHandle() +} + +extension Contact: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Contact.bridgeJSMakeTypeHandle() +} + +extension Config: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Config.bridgeJSMakeTypeHandle() +} + +extension SessionData: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SessionData.bridgeJSMakeTypeHandle() +} + +extension ValidationReport: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ValidationReport.bridgeJSMakeTypeHandle() +} + +extension AdvancedConfig: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AdvancedConfig.bridgeJSMakeTypeHandle() +} + +extension MeasurementConfig: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = MeasurementConfig.bridgeJSMakeTypeHandle() +} + +extension MathOperations: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = MathOperations.bridgeJSMakeTypeHandle() +} + +extension CopyableCart: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CopyableCart.bridgeJSMakeTypeHandle() +} + +extension CopyableCartItem: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CopyableCartItem.bridgeJSMakeTypeHandle() +} + +extension CopyableNestedCart: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = CopyableNestedCart.bridgeJSMakeTypeHandle() +} + +extension ConfigStruct: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ConfigStruct.bridgeJSMakeTypeHandle() +} + +extension Vector2D: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Vector2D.bridgeJSMakeTypeHandle() +} + +extension JSObjectContainer: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = JSObjectContainer.bridgeJSMakeTypeHandle() +} + +extension FooContainer: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FooContainer.bridgeJSMakeTypeHandle() +} + +extension ArrayMembers: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ArrayMembers.bridgeJSMakeTypeHandle() +} + +extension PolygonReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PolygonReference.bridgeJSMakeTypeHandle() +} + +extension TagReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TagReference.bridgeJSMakeTypeHandle() +} + +extension TagHolderReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TagHolderReference.bridgeJSMakeTypeHandle() +} + +extension PriorityReference: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = PriorityReference.bridgeJSMakeTypeHandle() +} + +extension Severity: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Severity.bridgeJSMakeTypeHandle() +} + +extension Shape: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Shape.bridgeJSMakeTypeHandle() +} + +extension InnerTag: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = InnerTag.bridgeJSMakeTypeHandle() +} + +extension AsyncImportedPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncImportedPayloadResult.bridgeJSMakeTypeHandle() +} + +extension Direction: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() +} + +extension Status: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() +} + +extension Theme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Theme.bridgeJSMakeTypeHandle() +} + +extension HttpStatus: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = HttpStatus.bridgeJSMakeTypeHandle() +} + +extension FileSize: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = FileSize.bridgeJSMakeTypeHandle() +} + +extension SessionId: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = SessionId.bridgeJSMakeTypeHandle() +} + +extension Precision: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() +} + +extension Ratio: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Ratio.bridgeJSMakeTypeHandle() +} + +extension TSDirection: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSDirection.bridgeJSMakeTypeHandle() +} + +extension TSTheme: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TSTheme.bridgeJSMakeTypeHandle() +} + +extension AsyncPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncPayloadResult.bridgeJSMakeTypeHandle() +} + +extension Networking.API.Method: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Networking.API.Method.bridgeJSMakeTypeHandle() +} + +extension Configuration.LogLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.LogLevel.bridgeJSMakeTypeHandle() +} + +extension Configuration.Port: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Configuration.Port.bridgeJSMakeTypeHandle() +} + +extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() +} + +extension APIResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() +} + +extension ComplexResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ComplexResult.bridgeJSMakeTypeHandle() +} + +extension Utilities.Result: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Utilities.Result.bridgeJSMakeTypeHandle() +} + +extension API.NetworkingResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = API.NetworkingResult.bridgeJSMakeTypeHandle() +} + +extension AllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = AllTypesResult.bridgeJSMakeTypeHandle() +} + +extension TypedPayloadResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = TypedPayloadResult.bridgeJSMakeTypeHandle() +} + +extension StaticCalculator: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = StaticCalculator.bridgeJSMakeTypeHandle() +} + +extension StaticPropertyEnum: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = StaticPropertyEnum.bridgeJSMakeTypeHandle() +} + +extension NestedTypeHost.Variant: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedTypeHost.Variant.bridgeJSMakeTypeHandle() +} + +extension LightColor: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = LightColor.bridgeJSMakeTypeHandle() +} + +extension ImportedPayloadSignal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ImportedPayloadSignal.bridgeJSMakeTypeHandle() +} + +extension OptionalAllTypesResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = OptionalAllTypesResult.bridgeJSMakeTypeHandle() +} + +extension APIOptionalResult: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIOptionalResult.bridgeJSMakeTypeHandle() +} + @JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) #if arch(wasm32) @@ -18191,4 +18431,93 @@ func _$SwiftClassSupportImports_jsConsumeOptionalLeakCheck(_ value: Optional?, _ count: Int32) + +@_expose(wasm, "bjs_BridgeJSRuntimeTests_register_type_handles") +public func _bjs_BridgeJSRuntimeTests_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + JSCoordinate.bridgeJSTypeID, + NestedStructGroupA.Metadata.bridgeJSTypeID, + NestedStructGroupB.Metadata.bridgeJSTypeID, + NestedTypeHost.Label.bridgeJSTypeID, + Point.bridgeJSTypeID, + PointerFields.bridgeJSTypeID, + DataPoint.bridgeJSTypeID, + PublicPoint.bridgeJSTypeID, + Address.bridgeJSTypeID, + Contact.bridgeJSTypeID, + Config.bridgeJSTypeID, + SessionData.bridgeJSTypeID, + ValidationReport.bridgeJSTypeID, + AdvancedConfig.bridgeJSTypeID, + MeasurementConfig.bridgeJSTypeID, + MathOperations.bridgeJSTypeID, + CopyableCart.bridgeJSTypeID, + CopyableCartItem.bridgeJSTypeID, + CopyableNestedCart.bridgeJSTypeID, + ConfigStruct.bridgeJSTypeID, + Vector2D.bridgeJSTypeID, + JSObjectContainer.bridgeJSTypeID, + FooContainer.bridgeJSTypeID, + ArrayMembers.bridgeJSTypeID, + PolygonReference.bridgeJSTypeID, + TagReference.bridgeJSTypeID, + TagHolderReference.bridgeJSTypeID, + PriorityReference.bridgeJSTypeID, + Severity.bridgeJSTypeID, + Shape.bridgeJSTypeID, + InnerTag.bridgeJSTypeID, + AsyncImportedPayloadResult.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Status.bridgeJSTypeID, + Theme.bridgeJSTypeID, + HttpStatus.bridgeJSTypeID, + FileSize.bridgeJSTypeID, + SessionId.bridgeJSTypeID, + Precision.bridgeJSTypeID, + Ratio.bridgeJSTypeID, + TSDirection.bridgeJSTypeID, + TSTheme.bridgeJSTypeID, + AsyncPayloadResult.bridgeJSTypeID, + Networking.API.Method.bridgeJSTypeID, + Configuration.LogLevel.bridgeJSTypeID, + Configuration.Port.bridgeJSTypeID, + Internal.SupportedMethod.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ComplexResult.bridgeJSTypeID, + Utilities.Result.bridgeJSTypeID, + API.NetworkingResult.bridgeJSTypeID, + AllTypesResult.bridgeJSTypeID, + TypedPayloadResult.bridgeJSTypeID, + StaticCalculator.bridgeJSTypeID, + StaticPropertyEnum.bridgeJSTypeID, + NestedTypeHost.Variant.bridgeJSTypeID, + LightColor.bridgeJSTypeID, + ImportedPayloadSignal.bridgeJSTypeID, + OptionalAllTypesResult.bridgeJSTypeID, + APIOptionalResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_BridgeJSRuntimeTests_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index d4e1878e1..6748d7c16 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -127,6 +127,7 @@ } ] }, + "isFinal" : true, "methods" : [ { "abiName" : "bjs_PolygonReference_vertexCount", @@ -265,6 +266,7 @@ "swiftCallName" : "PolygonReference" }, { + "isFinal" : true, "methods" : [ { "abiName" : "bjs_TagReference_describe", @@ -327,6 +329,7 @@ } ] }, + "isFinal" : true, "methods" : [ { "abiName" : "bjs_TagHolderReference_describe", @@ -380,6 +383,7 @@ "swiftCallName" : "TagHolderReference" }, { + "isFinal" : true, "methods" : [ { "abiName" : "bjs_PriorityReference_describe", diff --git a/docs/superpowers/javascriptkit-508-counterproposal.html b/docs/superpowers/javascriptkit-508-counterproposal.html new file mode 100644 index 000000000..de70990cd --- /dev/null +++ b/docs/superpowers/javascriptkit-508-counterproposal.html @@ -0,0 +1,413 @@ + + + + + + JavaScriptKit #508 — Design Review & Alternative Approach + + + +
+
+

JavaScriptKit #508 — design review & alternative approach

+

+ A peer review of the AoT-composition design, exploring whether there's a better-fitting approach. The conclusion + agrees with ~90% of it; the one alternative worth weighing is keeping the durable contract at the + skeleton-IR / JSON schema layer rather than freezing a public inter-module runtime ABI + — with evidence that the three issues can ship with no developer workflow change. +

+
+ Direction: skeleton-IR is the contract + Divergence: don't freeze the runtime ABI + Date: 2026-06-17 +
+
+ Short version. Yuta's per-target direction is right. Our one change: treat the inter-module boundary + as an internal, codegen-version-stamped detail (regenerate on mismatch) instead of a semver'd public ABI. The three + original problems (snippets, multi-package composition, fast TS feedback) each ship on the existing single-link + architecture with no new commands; the per-target restructure becomes an optional, separable phase. +
+
+ + + + + + + +
+
+ + +
+

Summary & relationship to Yuta's design

+

+ Your design and ours share almost everything: per-target bridge-js.js / bridge-js.d.ts / + BridgeJS.json, a shared runtime helper with private bjs state, primary-walks-emission with + dependencies as lookup-only, early .d.ts, and bundler-friendly ESM imports. The designs differ on + exactly one axis. +

+ + + + + + + + + + + + + + + +
DecisionYuta's designThis proposalSame?
Per-target artifacts (.js/.d.ts/.json)YesYes (regenerable)
Shared runtime helper, private bjs stateYesYes
Primary emission, dependencies lookup-onlyYesYes
Early bridge-js.d.ts (fast TS feedback)YesYes
Bundler/runtime-friendly ESM importsYesYes
The stable cross-version contractcreateBridgeModule() + bridgeJSRuntimeRange as a frozen public runtime ABIThe skeleton JSON schema; per-target modules are internal, codegen-version-stamped, regenerated on mismatch❌ the one difference
+
+ The nesting. + Architecture 2 ⊂ Architecture 3 ⊂ Yuta. + Arch 2 = skeleton contract + single merged glue. Arch 3 = Arch 2 + per-target regenerable modules (internal boundary). + Yuta = Arch 3 + freezing that boundary as a public ABI. Recommendation: Architecture 3 — Yuta's design minus the + one piece the demand analysis shows isn't needed. +
+

+ Notably, Yuta's own Decision 3 (“keep the compatibility surface minimal; generated modules must not read raw runtime storage”) + already pushes toward this. We take that instinct to its conclusion: shrink the public surface to zero by making the + boundary regenerable, so there's no runtime×module version matrix to maintain. +

+
+ + +
+

Demand analysis: is a frozen runtime ABI actually needed?

+

+ A frozen inter-module ABI is only required to compose a package's prebuilt bridge JS without running BridgeJS codegen. + One structural fact removes that need: +

+
+ All Swift links into ONE wasm module/instance. Every package's Swift — ElementaryUI, an OpenAPI client, the app — + is a SwiftPM dependency statically compiled into the single app .wasm, with one memory and one shared bjs ABI. + A package cannot ship a standalone runnable wasm that composes at runtime; they must be co-compiled. So the bridge glue is + intrinsically an app-build artifact, produced where the Swift toolchain is present by necessity. +
+ + + + + + + + + +
ScenarioNeeds prebuilt-compose w/o tooling?Why
Typical Swift-wasm app (SwiftPM deps)NoToolchain + codegen already run; all Swift co-compiles.
Vite / manual-wiring dev loopNoThe .wasm is rebuilt by Swift on any Swift change; bridge regen rides along. JS-only changes reuse committed AoT outputs as plain files.
Pure-JS npm consumer of a Swift libNo (structurally)The lib's Swift must compile into the consumer's wasm; you can't skip co-compiling.
Binary / closed-source wasm packageMarginalNot an established SwiftWasm pattern; would ship its skeleton JSON anyway.
Future: WASM Component ModelMaybeSpeculative; it brings its own canonical ABI that would supersede a hand-rolled one.
+

+ Verdict: the capability the frozen ABI buys isn't reachable today. Its real wins — per-target files, incremental builds, + early .d.ts, Vite-friendly imports — are all captured by Architecture 3 without the ABI. +

+
+ + +
+

Architecture decision: what do we freeze?

+

+ All three problems reduce to one question: when packages built at different times compose, what is the stable thing they agree on? + The codebase already answers this — the skeleton IR. +

+
+

Today = skeleton-IR contract

Each target emits BridgeJS.json; ExternalModuleIndex composes skeletons for cross-module type refs; PackageToJS runs one BridgeJSLink pass over all skeletons → one merged bridge-js.js.

+

Arch 1 — Yuta

Compiled module is the contract. Per-target runtime modules compose via a frozen, semver'd ABI over shared bjs state. Most expensive layer to keep stable.

+

Arch 2 — minimal

Keep skeleton contract + single merged glue. Add snippets, cross-package plumbing, early .d.ts. Fewest moving parts.

+

Arch 3 — recommended

Skeleton contract plus per-target regenerable modules stamped to one codegen version. Yuta's ergonomics; no frozen ABI.

+
+
+ The volatile, performance-critical layer (the inter-module handshake over the bjs stack/scratch state) is the thing you + least want to freeze. A JSON schema is far cheaper to version and migrate than a live runtime ABI. +
+
+ + +
+

Technical approach — concrete change points

+

+ How each problem is solved on the existing single-link architecture. All anchors verified against the current code. + Full task-by-task detail is in the linked plans; this is the mechanism. +

+ +

Problem 1 — package-owned JS snippets (#508)

+

+ Add a third value to the existing import-source axis. Today routing is binary at four sites in BridgeJSLink.swift + (:3335/3359/3458/3513): +

+
// today
+let importRootExpr = X.from == .global ? "globalThis" : "imports"
+
+// proposed: reuse the existing `from:` parameter, add a .module case
+switch X.from {
+case .global:        importRootExpr = "globalThis"
+case .module(name):  importRootExpr = snippetNamespace(swiftModule, name) // package-scoped
+case nil:            importRootExpr = "imports"
+}
+

Authoring stays on the existing macros — no new macro argument:

+
// Swift: bind to package-owned JS
+@JSFunction(from: .module("components"))
+func defineComponent(name: String, render: (JSObject) -> Void)
+
+// bridge-js.config.json
+{ "jsModules": { "components": "JavaScript/components.js" } }
+

+ The generated bridge-js.js emits a real ESM import of the bundled snippet — which also runs its top-level + side effects — and PackageToJS copies the snippet's whole directory (siblings preserved), keyed by the owning + Swift module so two packages can both call a module "components" without collision: +

+
import * as __bjs_snippet_ElementaryUI$components from "./snippets/ElementaryUI/components/components.js";
+

+ Both JSImportFrom enums get .module(String) — the public one in Sources/JavaScriptKit/Macros.swift:12 + (typed in the macro signatures) and the skeleton one in BridgeJSSkeleton.swift:1085 (serialized, back-compatible codec). + SwiftToSkeleton.extractJSImportFrom (:2344) learns to parse .module("…"). A generate-time + diagnostic rejects a .module reference that isn't declared in jsModules. +

+ +

Problem 2 — multi-package composition

+

+ The type resolver already composes across modules (ExternalModuleIndex; proven by CrossModuleResolutionTests), + and runtime composition already crosses packages (SkeletonCollector). The only blocker is a one-line same-package + filter in the build plugin: +

+
// BridgeJSBuildPlugin.swift:110 — drops cross-package dependency targets
+context.package.targets.contains(where: { $0.id == swiftTarget.id })
+

+ Lift it, build a target.id → package map (the pattern SkeletonCollector already uses), and resolve a + cross-package dependency's committed Generated/JavaScript/BridgeJS.json. A source-hash stamp on the skeleton + plus a CI regenerate-check guards against a dependency shipping a stale skeleton. +

+ +

Problem 3 — fast TS feedback

+

+ The export .d.ts is already a pure function of the skeleton — link() computes JS and TS independently: +

+
// BridgeJSLink.link() :1209  →  generateJavaScript(data) + generateTypeScript(data)
+// proposed: a wasm-free, link-free entry point
+public func linkTypeScriptOnly() throws -> String {
+    intrinsicRegistry.reset(); /* set classNamespaces */
+    return generateTypeScript(data: try collectLinkData())
+}
+

+ Emitted per target during generate (primary skeleton only, so it's the target's own surface — not a merged + superset), to Generated/JavaScript/bridge-js.d.ts. Point tsc --watch at it; no wasm build, no final link. +

+

+ Collocation (Yuta feedback): a `.d.ts` must sit next to a real `.js`, since the surface includes value exports + (e.g. createInstantiator). So generate also writes a collocated stub bridge-js.js whose value + exports throw "bridge not built" — the module path always resolves, the typecheck loop is unaffected, and Phase 4's real + per-target runtime module later supersedes the stub at the same path. +

+
+ Important scope rule until Phase 4: Generated/JavaScript/ is a types surface + (+ stub safety), not a runtime import target. Manual-wiring/Vite apps must take runtime value + imports from the packaged output (.build/plugins/PackageToJS/outputs/Package/bridge-js.js) — importing + Generated/JavaScript/bridge-js.js before Phase 4 gets the throwing stub. Phase 4 turns that path into the real + per-target runtime module. Also note: the stable tsc --watch location is an AoT-workflow benefit; build-plugin + users get the early .d.ts in the plugin work dir. +
+ +
+ None of these touch a runtime ABI. The contract that evolves is the skeleton JSON schema (a versioned codec), which is why + Problems 1–3 ship on today's single-link model without the per-target restructure. +
+
+ + +
+

Phased plan — issues map 1:1 to phases

+

+ Full task-by-task plans (Markdown, executable with checkboxes) are linked below. Phases 1–3 each close one original + problem on the existing single-link architecture. The restructure is an optional Phase 4. +

+ +

Workflow impact — existing commands are unchanged

+ + + + + + + + +
Phase / IssueNew command?What changes for the developer
P1 — fast TS feedback (Problem 3)NoSame swift package plugin bridge-js now also drops Generated/JavaScript/bridge-js.d.ts (no wasm); point tsc --watch at it.
P2 — JS snippets / #508 (Problem 1)NoAuthoring only: a JavaScript/ dir, a bridge-js.config.json entry, from: .module("name") on an existing import macro. The snippet rides along with swift package js.
P3 — cross-package types (Problem 2)NoConsumer runs swift package js as before. New expectation: cross-package deps ship committed BridgeJS.json.
P4 — restructure (optional)No mandatoryswift package js still works; optionally enables a manual-wiring (Vite) loop.
+ +

The plans

+
+
+

Phase 1 — fast TS feedback (Problem 3)

+

Add BridgeJSLink.linkTypeScriptOnly() (the .d.ts is already a pure function of skeletons via generateTypeScript(data:)) and emit a per-target bridge-js.d.ts during generate. Per Yuta's feedback, the .d.ts ships with a collocated stub bridge-js.js (value exports throw "not built") so a value import never dangles; the typecheck loop is unaffected. No wasm, no ABI change. Full TDD.

+ → plans/2026-06-17-bridgejs-phase1-early-dts.md +
+
+

Phase 2 — package JS snippets (Problem 1 / #508)

+

Extend both JSImportFrom enums (public Macros.swift + skeleton) with .module(name) and reuse the existing from: parameter — no new macro argument. Route the four importRootExpr sites to a package-scoped snippet namespace, declare snippets in BridgeJSConfig.jsModules, validate that every referenced module is declared, and bundle whole snippet directories (preserving sibling imports) via a SnippetCollector mirroring SkeletonCollector (cross-package, collision-safe). Side effects run via the ESM import; .js/.mjs only. Full TDD, 7 tasks.

+ → plans/2026-06-17-bridgejs-phase2-js-snippets.md +
+
+

Phase 3 — multi-package composition (Problem 2)

+

The resolver already supports cross-module types (CrossModuleResolutionTests); runtime composition already crosses packages (SkeletonCollector). The only gap is the same-package filter at BridgeJSBuildPlugin.swift:110. Lift it and resolve dependency skeletons via committed BridgeJS.json. Full TDD, 5 tasks.

+ → plans/2026-06-17-bridgejs-phase3-cross-package.md +
+
+

Phase 4 — per-target modules (OPTIONAL)

+

Yuta's restructure: extract the shared runtime, split BridgeJSLink into primary + dependencies, emit per-target modules + thin composition. Divergence lives only here: codegen-version stamp + regenerate, not a frozen ABI. Feasibility spikes A/B/C complete — no blocker. The dominant cost is threading shared ABI state through an explicit context in the lowering codegen (`JSGlueGen.swift`) — exactly the internal, regenerable contract the divergence keeps non-public. Not one of the three issues. Architectural.

+ → plans/2026-06-17-bridgejs-phase4-per-target-modules.md +
+
+

+ Markdown is the source of truth (git/PR-friendly, checkbox task tracking). This HTML summarizes; open the .md for full, + executable detail. On GitHub/GitLab the .md renders natively. +

+
+ + +
+

Spike findings — feasibility, grounded in the code

+ + + + + + + + + + +
SpikeFindingRisk
1 · .module import sourceRouting is centralized at 4 importRootExpr sites (BridgeJSLink.swift:3335/3359/3458/3513); JSImportFrom is a one-case enum (:1085); ImportObjectBuilder already keys by module name.Low
2 · Snippet collectionSkeletonCollector (PackageToJSPlugin.swift:703) already walks the transitive graph cross-package; mirror it + reuse the copy mechanism.Low
3 · Per-target partitioningEmission iterates all skeletons; needs a primary + dependencies split. Same refactor Yuta requires.High effort
4 · Early .d.tslink() already calls generateJavaScript and generateTypeScript separately from skeleton-derived data; .d.ts never touches wasm.Low
5 · Cross-packageRuntime composition already crosses packages; build-time type refs blocked solely by the same-package filter at BridgeJSBuildPlugin.swift:110 (a documented discovery limit).Med
6 · Shared bjs stateAll shared state is isolated in generateVariableDeclarations() (:329-358) behind JSGlueVariableScope.reserved* symbols — extractable.Med
+
+ The spikes confirm Architecture 3 is feasible with concrete change points, and that it is minimally divergent from the original design: + the two hard refactors (Spikes 3, 6) are shared; only the contract-freezing decision differs. +
+ +

Phase 4 composition spikes (A · B · C) — completed

+

+ The optional restructure was de-risked by reading the code, since it underpins the counter-proposal's thesis (per-target + modules without a frozen ABI). Result: feasible, no fundamental blocker. +

+
    +
  • A · Shared-state inventory: classified every JSGlueVariableScope.reserved* symbol as runtime-owned vs shared-context. sharedMemory confirmed to touch glue at a single site (:1158), not in per-target thunks.
  • +
  • B · Cross-target references: emission is primary-scoped; dependencies are needed only as a lookup index (namespaces/type resolution). Two coordination wrinkles noted (closure-unregister ownership, helper-factory ownership).
  • +
  • C · Composition shape: the proposed createBridgeRuntime() / createBridgeModule() interface can express everything createInstantiator does. Critical finding: the real cost is that per-target thunk codegen references shared state by bare lexical name (e.g. strStack.pop()) and must be threaded through an explicit context — a pervasive but mechanical edit in JSGlueGen.swift. Runnable two-module PoC deferred until the restructure is greenlit.
  • +
+

Full findings + updated tasks are in plans/2026-06-17-bridgejs-phase4-per-target-modules.md.

+
+ + +
+

Open questions for discussion

+

+ These are the decisions worth settling together before committing the design direction — not blockers, just the forks + where the two approaches diverge. +

+
    +
  1. The contract axis. Should the durable cross-version contract be the skeleton JSON schema (per-target modules regenerated per codegen version), or a frozen bridgeJSRuntimeRange runtime ABI? This is the one substantive difference between the two designs.
  2. +
  3. The demand premise. Is there a real requirement for composing a prebuilt bridge with zero Swift tooling that the demand analysis missed? If so, it changes the calculus and argues for designing the ABI properly.
  4. +
  5. Phasing. Ship Problems 1–3 on the existing single-link architecture first (no workflow change), and treat the per-target restructure as a separate, optional initiative? Or do the restructure up front?
  6. +
  7. Snippet authoring. Config-declared jsModules (explicit) vs convention-only directory discovery (less friction, more “magic”)?
  8. +
  9. TS in snippets. Keep snippets .js/.mjs-only (current proposal, matches the non-goals), or is there appetite for a TS transpile step later?
  10. +
  11. Snippets from the d.ts route. Phase 2 wires from: .module through the Swift-macro path only; bridge-js.d.ts-declared imports can't target snippets yet. Is a JSDoc tag (e.g. /** @bridgeModule components */) that ts2swift lowers to .module worth speccing, and when?
  12. +
  13. Module-name uniqueness. BridgeJS keys bridge state/snippets by Swift module name, but SwiftPM allows same-named targets in different packages. The plans now add a graph-wide duplicate-name diagnostic — is erroring acceptable, or does anyone need a disambiguation scheme?
  14. +
+
+ Bottom line: the proposal agrees with the bulk of the original design. The alternative on the table removes one long-term + liability — a frozen runtime ABI — while keeping every ergonomic win it outlined. Whoever ships it (individually or as a + team), these are the points to align on first. +
+

Artifacts in this bundle

+
    +
  • javascriptkit-508-counterproposal.html — this report
  • +
  • plans/2026-06-17-bridgejs-phase1-early-dts.md — Problem 3 (full TDD)
  • +
  • plans/2026-06-17-bridgejs-phase2-js-snippets.md — Problem 1 / #508 (full TDD)
  • +
  • plans/2026-06-17-bridgejs-phase3-cross-package.md — Problem 2 (full TDD)
  • +
  • plans/2026-06-17-bridgejs-phase4-per-target-modules.md — optional restructure (staged)
  • +
+
+
+ + + + diff --git a/docs/superpowers/plans/2026-06-17-bridgejs-phase1-early-dts.md b/docs/superpowers/plans/2026-06-17-bridgejs-phase1-early-dts.md new file mode 100644 index 000000000..3749cbe59 --- /dev/null +++ b/docs/superpowers/plans/2026-06-17-bridgejs-phase1-early-dts.md @@ -0,0 +1,374 @@ +# BridgeJS Early `.d.ts` (Phase 1) Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make a target's exported TypeScript surface (`bridge-js.d.ts`) regenerate from its BridgeJS skeleton at code-generation time, without a WebAssembly build or the final `PackageToJS` link, so TypeScript consumers can typecheck **the target's own exported surface** immediately after editing `@JS` annotations. (Scope note — see M3 below: when a target's exported API *references a type defined in a dependency target*, that name is not yet defined/imported in the per-target `.d.ts`; full standalone typechecking of cross-target references requires emitting `import type` statements, which is a follow-up tracked here, not part of this minimal phase.) + +**Architecture:** `BridgeJSLink` already produces the export `.d.ts` purely from skeleton-derived data (`generateTypeScript(data:)`), entirely independent of the JS/wasm path. This phase exposes a TypeScript-only entry point on `BridgeJSLink`, then calls it from the `generate` subcommand so each target writes a per-target `Generated/JavaScript/bridge-js.{d.ts,js}` **pair** right after its skeleton is produced. No runtime/ABI changes. + +**Tech Stack:** Swift (SwiftPM command/build plugins + plugin tools), Swift Testing, the repo's snapshot-test harness. + +> ### Design note — collocation requirement (Yuta feedback, 2026-06-17) +> TypeScript assumes every `.d.ts` is collocated with a real implementation `.js`. Our generated surface is mostly type-only (`interface`s, `type` aliases), **but it includes value exports** — notably `export function createInstantiator(...)` (verified in the `SwiftClass.d.ts` snapshot) plus enum/namespace `const` objects. So emitting a **lone `.d.ts`** is unsafe: if a consumer does a *non-type* import of a value, `tsc` keeps the import in the emitted JS and it points at a non-existent `bridge-js.js` ("module not found" at runtime). +> +> **What this does and doesn't affect:** +> - **Unaffected (the main win):** editor diagnostics and `tsc --noEmit` typechecking emit no JS, so the fast typecheck loop is safe with the `.d.ts` alone. +> - **Affected:** a consumer that *emits/runs* JS with a value import before the real bridge is built. +> +> **Decision for Phase 1:** always write the `.d.ts` **with a collocated `.js`**. The minimal form is a generated **stub `.js`** (Task 4) whose value exports throw a clear "bridge not built — run `swift package js`" error, so the module path always resolves. When Phase 4's per-target runtime `.js` lands, it supersedes the stub at the same path. (Yuta's "just generate `.ts`" idea doesn't fix it alone: a types-only `.ts` compiles to an empty `.js`, so value imports still fail — just with "undefined is not a function" instead of "module not found".) +> +> **Scope boundaries (F1/F3 from the follow-up review):** +> - **`Generated/JavaScript/` is a TYPES (+ stub-safety) surface until Phase 4 — never a runtime import target.** Manual-wiring/Vite users must take *runtime* imports from the packaged output (`.build/plugins/PackageToJS/outputs/Package/bridge-js.js`), not from `Generated/JavaScript/bridge-js.js` (which is the throwing stub until Phase 4 replaces it). Document this in the Task 2 example check and in any consumer-facing docs. +> - **The fast `tsc --watch` loop is an AoT-workflow benefit.** The build plugin passes `--output-dir ` (`BridgeJSBuildPlugin.swift:53-54`), so for build-plugin users the early `.d.ts`/stub land in `.build/plugins/...` — functional, but not a stable watch path. AoT users (`swift package plugin bridge-js`) get the stable `Sources//Generated/JavaScript/` location. A future `--emit-dts-into-target` opt-in for build-plugin users is possible but out of scope here. + +--- + +## Context: why this phase first + +This is the cheapest and most isolated of the four phases identified in the design review (see `docs/superpowers/specs/2026-06-17-bridgejs-composition-design.md` once written). It ships value on its own (fast TS feedback, JavaScriptKit issue context #508 / Yuta's Decision 6), touches no runtime ABI, and de-risks the larger work. + +### Roadmap — issue-aligned phases (each its own plan) + +Phases 1–3 each close exactly one of the three originally-identified problems, on top of the **existing single-link architecture**, with **no change to the commands a developer runs** (`swift package js`, `swift package plugin bridge-js` stay identical). The per-target/shared-runtime restructure is demoted to an **optional** Phase 4 because none of the three issues require it. + +- **Phase 1 — Problem 3: fast TS feedback.** *(this plan)* `linkTypeScriptOnly()` + per-target `Generated/JavaScript/bridge-js.d.ts` emitted during `generate`. No wasm, no ABI change. +- **Phase 2 — Problem 1: package-owned JS snippets (#508).** Extend **both** `JSImportFrom` enums (public `Macros.swift` + skeleton) with `.module(name)` and reuse the existing `from:` parameter; route the four `importRootExpr` sites in `BridgeJSLink.swift` (~`:3335, 3359, 3458, 3513`) to a package-scoped namespace; add a `SnippetCollector` mirroring `SkeletonCollector` in `PackageToJSPlugin.swift` (it traverses cross-package, so snippets compose across packages); bundle snippet directories and emit real ESM imports. Authoring-only additions for the developer (a `JavaScript/` dir + `bridge-js.config.json` entry + `from: .module("name")`); no new command. +- **Phase 3 — Problem 2: multi-package composition.** Runtime composition already works cross-package via `SkeletonCollector`; the missing user-facing piece is cross-package `@JS` **type references**. Lift the same-package filter at `BridgeJSBuildPlugin.swift:110` and resolve dependency skeletons across package boundaries via committed `Generated/JavaScript/BridgeJS.json`. New *expectation* (not command): cross-package `@JS` dependencies ship committed skeletons. +- **Phase 4 — OPTIONAL architectural investment (not one of the three issues): shared-runtime extraction + per-target bridge modules.** Move `generateVariableDeclarations()` state into a shared runtime helper; split `BridgeJSLink` into `primary + dependencies` so emission is per-target while lookups stay global. This is the same refactor Yuta's design requires — **but our divergence keeps the inter-module boundary an internal, codegen-version-stamped detail rather than a frozen public ABI.** Pursue only if incremental-build and manual-wiring (Vite) ergonomics are wanted; the three issues ship without it. + +--- + +## File Structure + +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` — add public `linkTypeScriptOnly() -> String` (the `.d.ts`) and `linkStubJavaScript() -> String` (the collocated stub `.js`). Both are pure functions of the loaded skeletons; neither touches wasm. +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift` — after writing the skeleton in the `generate` subcommand, emit the per-target `Generated/JavaScript/bridge-js.d.ts` **and** the collocated `Generated/JavaScript/bridge-js.js` stub. +- **Test** `Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift` — assert `linkTypeScriptOnly()` equals `link()`'s `outputDts`, and that the stub `.js` exports exactly the value-bearing names the `.d.ts` declares (so a value import resolves rather than dangles). + +> Naming note: the target-root `bridge-js.d.ts` is the **input** for TypeScript-import (`@JSFunction` generation). The new files live under `Generated/JavaScript/bridge-js.{d.ts,js}` (next to `BridgeJS.json`) and are the **output** export surface. Different directories, no collision. + +--- + +## Task 1: `BridgeJSLink.linkTypeScriptOnly()` + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` (add method next to `link()` at `:1210`) +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift` + +- [ ] **Step 1: Write the failing test** + +Add to `BridgeJSLinkTests` in `Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift`: + +```swift +@Test +func typeScriptOnlyMatchesLink() throws { + let url = Self.inputsDirectory.appendingPathComponent("SwiftClass.swift") + let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) + let importSwift = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + importSwift.addSourceFile(sourceFile, inputFilePath: "SwiftClass.swift") + let importResult = try importSwift.finalize() + + var fullLink = BridgeJSLink(sharedMemory: false) + var dtsOnlyLink = BridgeJSLink(sharedMemory: false) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + let unifiedData = try encoder.encode(importResult) + try fullLink.addSkeletonFile(data: unifiedData) + try dtsOnlyLink.addSkeletonFile(data: unifiedData) + + let (_, expectedDts) = try fullLink.link() + let actualDts = try dtsOnlyLink.linkTypeScriptOnly() + + #expect(actualDts == expectedDts) +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests.typeScriptOnlyMatchesLink` +Expected: FAIL to compile — `value of type 'BridgeJSLink' has no member 'linkTypeScriptOnly'`. + +- [ ] **Step 3: Write minimal implementation** + +In `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift`, immediately after the `link()` method (ends at `:1224`), add: + +```swift +/// Generates only the exported TypeScript surface (`.d.ts`) from the loaded skeletons. +/// +/// This is a pure function of the skeletons and never touches the WebAssembly +/// build or JS glue generation, so it can run at code-generation time to give +/// TypeScript consumers fast feedback after editing `@JS` annotations. +public func linkTypeScriptOnly() throws -> String { + intrinsicRegistry.reset() + intrinsicRegistry.classNamespaces = skeletons.reduce(into: [:]) { result, unified in + guard let skeleton = unified.exported else { return } + for klass in skeleton.classes { + if let namespace = klass.namespace { + result[klass.name] = namespace + } + } + } + let data = try collectLinkData() + return generateTypeScript(data: data) +} +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests.typeScriptOnlyMatchesLink` +Expected: PASS. + +- [ ] **Step 5: Run the full link test suite to confirm no regressions** + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests` +Expected: PASS (all existing snapshot tests unchanged — no production output paths were modified). + +- [ ] **Step 6: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +git commit -m "feat(bridge-js): add linkTypeScriptOnly() for wasm-free .d.ts generation" +``` + +--- + +## Task 2: Emit per-target export `.d.ts` (+ collocated stub `.js`) from the `generate` subcommand + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift` (the `generate` case; skeleton is written near `:264-274`) + +The `generate` subcommand already builds the primary skeleton and loads dependency skeletons (`ExternalModuleIndex(dependencies:)`, `:173`). We reuse those exact objects to drive `BridgeJSLink`. + +- [ ] **Step 1: Locate the skeleton-write site** + +Read `Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift` around `:255-290` to find where `outputSkeletonURL` (`Generated/JavaScript/BridgeJS.json`) is written via `writeIfChanged(skeletonData, to: outputSkeletonURL)`. The new `.d.ts` is written to the **same directory**. + +- [ ] **Step 2: Add the export `.d.ts` emission immediately after the skeleton-write `withSpan` block** + +The `generate` case writes the skeleton inside a `withSpan("Writing output skeleton") { ... }` block ending at `:275`, where the primary skeleton model value is the local `skeleton` (encoded at `:273`). After that closing brace (`:275`), insert: + +```swift +// Emit the exported TypeScript surface alongside the skeleton so TS consumers +// can typecheck without a wasm build or the final PackageToJS link. +// IMPORTANT (Yuta feedback): a .d.ts must be collocated with a real .js, or a +// consumer's *value* import dangles in emitted JS. Write the stub .js too (Task 4). +try withSpan("Writing export .d.ts + stub .js") { + let dir = outputSkeletonURL.deletingLastPathComponent() + var dtsLink = BridgeJSLink(sharedMemory: false) + dtsLink.addSkeleton(skeleton) // primary only — see note below + let exportDts = try dtsLink.linkTypeScriptOnly() + let stubJs = try dtsLink.linkStubJavaScript() // Task 4 + try writeIfChanged(Data(exportDts.utf8), to: dir.appending(path: "bridge-js.d.ts")) + try writeIfChanged(Data(stubJs.utf8), to: dir.appending(path: "bridge-js.js")) +} +``` + +> **`skeleton` is the PRIMARY skeleton only — do not add `dependencySkeletons` here.** `linkTypeScriptOnly()` re-emits a `.d.ts` declaration for *every* added skeleton that has an `exported` section. Because the `primary + dependencies` emission split is Phase 4, adding dependency skeletons would make each target's `Generated/JavaScript/bridge-js.d.ts` a **merged superset** that duplicates its dependencies' declarations — causing duplicate-identifier risk if a consumer references two such files, and a surface broader than the target itself. +> +> **Known limitation — M3 (cross-target referenced types):** with primary-only input, a type referenced from a *dependency* target (e.g. a return type defined in another module) renders **by name** in the `.d.ts` but is neither defined nor imported. Consequences: +> - For a target whose own exported API references a dependency `@JS` type, the per-target `.d.ts` **does not typecheck standalone** (the referenced name is undefined). +> - We deliberately do **not** re-inline dependency declarations here (that caused the duplicate-identifier / merged-superset problem this fix removed). +> +> **Resolution path (follow-up, not this phase):** emit `import type { Foo } from "/bridge-js.d.ts"` for each referenced external type, so the per-target `.d.ts` is a proper TS module that resolves cross-target names without duplication. This needs (a) the set of referenced external types (already available via the `ExternalModuleIndex` model) and (b) a resolvable path to each dependency's `bridge-js.d.ts`. It is the natural companion to Phase 3 (cross-package) / Phase 4 (per-target modules); track it there. The fully-resolved merged surface is meanwhile still produced by the final `PackageToJS` link (the package-level `bridge-js.d.ts`). +> +> `skeleton` is the primary `BridgeJSSkeleton` produced by `swiftToSkeleton.finalize()` (encoded at `:273`). + +- [ ] **Step 3: Add the `addSkeleton(_:)` convenience used above** + +The tool holds decoded `BridgeJSSkeleton` values, not `Data`. Add a sibling to `addSkeletonFile(data:)` in `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` (after `:60`): + +```swift +/// Adds an already-decoded skeleton (used by callers that hold model values +/// rather than serialized skeleton files). +public mutating func addSkeleton(_ skeleton: BridgeJSSkeleton) { + skeletons.append(skeleton) +} +``` + +- [ ] **Step 4: Build the plugin tool to verify it compiles** + +Run: `swift build --package-path Plugins/BridgeJS --product BridgeJSTool` +Expected: Build succeeds. + +- [ ] **Step 5: Verify behavior on an example target** + +Run: +```bash +swift package --package-path Examples/MultiModule plugin bridge-js --target MarkdownParser --allow-writing-to-package-directory +``` +Expected: `Examples/MultiModule/Sources/MarkdownParser/Generated/JavaScript/bridge-js.d.ts` **and** `bridge-js.js` now exist; the `.d.ts` contains the exported declarations and the `.js` is the stub from Task 4. (Adjust target/example name to one that has `@JS` exports.) + +- [ ] **Step 6: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +git commit -m "feat(bridge-js): emit per-target export bridge-js.{d.ts,js} during generate" +``` + +--- + +## Task 4: Generate the collocated stub `bridge-js.js` (Yuta collocation fix) + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` — add `linkStubJavaScript() -> String`. +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift` + +The stub exists so the `.d.ts` is never an orphan: the module path resolves, the typecheck loop is unaffected, and a value import used *before* the real bridge is built fails with a clear message instead of "module not found". It must export **every value-bearing name** the `.d.ts` declares (so the named import resolves), each throwing. + +- [ ] **Step 1: Write the failing test** + +```swift +@Test func stubJsExportsValueNamesAndThrows() throws { + let url = Self.inputsDirectory.appendingPathComponent("SwiftClass.swift") + let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) + let importSwift = SwiftToSkeleton( + progress: .silent, moduleName: "TestModule", + exposeToGlobal: false, externalModuleIndex: .empty + ) + importSwift.addSourceFile(sourceFile, inputFilePath: "SwiftClass.swift") + var link = BridgeJSLink(sharedMemory: false) + let encoder = JSONEncoder(); encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + try link.addSkeletonFile(data: encoder.encode(try importSwift.finalize())) + + let stub = try link.linkStubJavaScript() + // createInstantiator is a value export in the .d.ts (verified in SwiftClass.d.ts snapshot) + #expect(stub.contains("export function createInstantiator")) + #expect(stub.contains("throw new Error")) +} +``` + +- [ ] **Step 2: Run to verify it fails** + +Run: `swift test --package-path Plugins/BridgeJS --filter stubJsExportsValueNamesAndThrows` +Expected: FAIL — no `linkStubJavaScript`. + +- [ ] **Step 3: Implement `linkStubJavaScript()`** + +Reuse `collectLinkData()` to find the value-bearing exports (the same data the `.d.ts` uses). Emit an ESM module that exports each value name with a throwing body. Value exports are: `createInstantiator` (always, when a bridge exists), plus enum/namespace `const` objects and any top-level exported functions. Pure types (`interface`/`type`) are **not** emitted (they don't exist at runtime). + +```swift +/// Generates a placeholder `bridge-js.js` collocated with the early `.d.ts`. +/// Every value-bearing export the `.d.ts` declares is present but throws, so a +/// consumer's value import resolves (no dangling module) yet fails loudly if used +/// before the real bridge is built by `swift package js`. Superseded by the real +/// per-target runtime module in Phase 4. +public func linkStubJavaScript() throws -> String { + let data = try collectLinkData() + var lines: [String] = [ + "// NOTICE: Auto-generated placeholder by BridgeJS. The real runtime is produced", + "// by `swift package js`. This file exists so bridge-js.d.ts is collocated with a module.", + "const __bridgeNotBuilt = (name) => { throw new Error(", + " `BridgeJS runtime is not built yet (accessed '${name}'). Run \\`swift package js\\`.`); };", + ] + for name in data.valueExportNames.sorted() { + lines.append("export function \(name)() { return __bridgeNotBuilt(\"\(name)\"); }") + } + return lines.joined(separator: "\n") + "\n" +} +``` + +> `data.valueExportNames` is the set of value-bearing top-level export identifiers. If `LinkData` doesn't already track these, add a `Set` populated where the `.d.ts` value exports are emitted (top-level functions, enum/namespace consts, and the always-present `createInstantiator`). For enum/namespace consts that must be *objects* (not callables), note that ESM named exports don't support lazy `defineProperty` getters on the namespace — instead export a throwing `Proxy`: +> ```js +> const __stubProxy = (name) => new Proxy({}, { get() { return __bridgeNotBuilt(name); } }); +> export const Direction = __stubProxy("Direction"); +> ``` +> Keep `export function` only for callable exports. Match each value name to how the `.d.ts` declares it. + +- [ ] **Step 4: Run to verify it passes** + +Run: `swift test --package-path Plugins/BridgeJS --filter stubJsExportsValueNamesAndThrows` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +git commit -m "feat(bridge-js): generate collocated stub bridge-js.js for the early .d.ts" +``` + +--- + +## Task 5: Snapshot-cover the per-target `.d.ts` output + +**Files:** +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift` + +- [ ] **Step 1: Add a snapshot test for the TypeScript-only path across all inputs** + +Add to `BridgeJSLinkTests`: + +```swift +@Test(arguments: collectInputs(extension: ".swift")) +func typeScriptOnlySnapshot(input: String) throws { + let url = Self.inputsDirectory.appendingPathComponent(input) + let name = url.deletingPathExtension().lastPathComponent + let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) + let importSwift = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + importSwift.addSourceFile(sourceFile, inputFilePath: "\(name).swift") + let importResult = try importSwift.finalize() + var link = BridgeJSLink(sharedMemory: false) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + try link.addSkeletonFile(data: encoder.encode(importResult)) + + let dts = try link.linkTypeScriptOnly() + try assertSnapshot( + name: name, + input: dts.data(using: .utf8)!, + fileExtension: "ts-only.d.ts" + ) +} +``` + +> If `assertSnapshot` requires the `filePath`/`function`/`sourceLocation` arguments (as the private `snapshot(...)` helper passes them), include them with the same `#filePath`, `#function`, `#_sourceLocation` defaults used at `:13-15`. + +- [ ] **Step 2: Run to generate snapshots (first run records them)** + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests.typeScriptOnlySnapshot` +Expected: On first run the harness records `*.ts-only.d.ts` snapshots; confirm the recorded files match the `.d.ts` portion already recorded by the existing `snapshot(input:)` test. + +- [ ] **Step 3: Re-run to verify stability** + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests.typeScriptOnlySnapshot` +Expected: PASS with no snapshot diffs. + +- [ ] **Step 4: Commit** + +```bash +git add Plugins/BridgeJS/Tests/BridgeJSToolTests +git commit -m "test(bridge-js): snapshot the TypeScript-only link output" +``` + +--- + +## Self-Review + +**Spec coverage:** +- Fast `.d.ts` without wasm/link → Task 1 (`linkTypeScriptOnly`) + Task 2 (emission during `generate`). ✓ +- **Collocation fix (Yuta):** the `.d.ts` ships with a collocated stub `.js` so a value import never dangles → Task 4 (`linkStubJavaScript`) + Task 2 writes both. The fast **typecheck** loop (editor / `tsc --noEmit`) is unaffected; the stub only matters when a consumer emits/runs before the real bridge is built. ✓ +- Stable per-target output location for TS watch → Task 2 writes `Generated/JavaScript/bridge-js.{d.ts,js}`. ✓ +- No runtime/ABI change → confirmed; only additive methods and two extra output files (the stub `.js` is superseded by Phase 4's real per-target runtime module at the same path). ✓ +- Per-target surface is primary-only (not a merged superset) → Task 2 Step 2 adds only the primary skeleton. ✓ +- **M3 (cross-target referenced types):** the goal is scoped to the target's *own* exported surface; a target that re-exports a dependency `@JS` type yields a `.d.ts` that does not typecheck standalone until `import type` emission is added (a Phase 3/4 follow-up, documented in the Task 2 Known-limitation note). This is an explicit, accepted limitation of the minimal phase — not an oversight. ✓ +- **F-series (follow-up review):** F1 — `Generated/JavaScript/` declared a types-only surface until Phase 4 (runtime imports come from the packaged output); F3 — fast-watch loop honestly scoped to the AoT workflow (build-plugin outputs land in the work dir); F7 — object-shaped stub exports use a throwing `Proxy` const (ESM namespaces don't support defineProperty getters). Design-note + Task 4. ✓ + +**Placeholder scan:** Adaptation notes in Task 2 (the exact `dependencySkeletons` shape / `assertSnapshot` signature) and Task 4 Step 3 (how `valueExportNames` is populated and how object-shaped consts are stubbed) are "match the existing local code" instructions referencing concrete anchors (`:125`, `:13-34`, the `.d.ts` value-export emission), not deferred design. + +**Type consistency:** `linkTypeScriptOnly()`, `linkStubJavaScript()`, and `addSkeleton(_:)` are defined in Tasks 1/4/2 and used consistently in Task 2. `LinkData.valueExportNames` is introduced in Task 4 Step 3. `collectLinkData()`, `generateTypeScript(data:)`, `intrinsicRegistry` all exist in `BridgeJSLink.swift` (`:179`, `:924`, used at `:1211`). `BridgeJSSkeleton` is the decoded type appended in `addSkeletonFile` (`:45`). + +--- + +## Execution Handoff + +Once reviewed, choose execution: +1. **Subagent-Driven (recommended)** — fresh subagent per task with review between tasks. +2. **Inline Execution** — execute tasks in-session with checkpoints. diff --git a/docs/superpowers/plans/2026-06-17-bridgejs-phase2-js-snippets.md b/docs/superpowers/plans/2026-06-17-bridgejs-phase2-js-snippets.md new file mode 100644 index 000000000..c5b43bd13 --- /dev/null +++ b/docs/superpowers/plans/2026-06-17-bridgejs-phase2-js-snippets.md @@ -0,0 +1,593 @@ +# BridgeJS Package-Owned JS Snippets (Phase 2) Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Let a Swift package ship its own JavaScript (a "snippet" module) and bind to it from Swift, so that `@JS` imported declarations resolve to the package's own JS — bundled automatically into the final app — instead of `globalThis` or app-provided imports. This closes JavaScriptKit issue #508 (e.g. ElementaryUI custom elements). + +**Architecture:** Add a third import source to the existing single-link model. Today every imported `@JS` binding routes to either `globalThis` (`from: .global`) or the app-provided `imports` object (`from == nil`) — decided at four `importRootExpr` sites in `BridgeJSLink.swift`. We extend the existing `from:` axis with `.module(name)` (no new macro argument), route those sites to a **package-scoped** snippet namespace bound by a real ESM `import` of the package's JS, and collect/copy snippet source trees transitively via a new `SnippetCollector` mirroring `SkeletonCollector`. The import statement also runs the snippet's top-level code, covering load-time side effects. + +**Tech Stack:** Swift (BridgeJS macros API, skeleton, core, link, plugins), Swift Testing + snapshot harness, the PackageToJS plugin. + +--- + +## Context + +Depends on nothing from Phase 1; can ship independently. This is the headline #508 feature. No developer-facing command changes — authoring-only additions (a `JavaScript/` dir, a config entry, and `from: .module("name")` on existing `@JSFunction`/`@JSGetter`/`@JSClass`). The existing `swift package js` / build-plugin run bundles the snippet automatically. + +### Design decision: reuse `from:`, do NOT add a `module:` argument +There are **two** `JSImportFrom` types and they are both load-bearing: +- **Public** `enum JSImportFrom: String { case global }` — `Sources/JavaScriptKit/Macros.swift:12`. This is the type users write; the macros already declare `from: JSImportFrom?` (`Macros.swift:141/159/180/205`). There is **no** `module:` parameter on any macro. +- **Skeleton** `enum JSImportFrom` — `BridgeJSSkeleton.swift:1085`. The serialized form stored in `BridgeJS.json`. + +The macro *implementations* (`BridgeJSMacros/*`) do **not** parse `from:` — `SwiftToSkeleton.AttributeChecker.extractJSImportFrom` (`SwiftToSkeleton.swift:2344`) reads it from attribute syntax and constructs the skeleton enum. Therefore: +- Adding a `module:` argument would require editing the public macro **declarations** in `Macros.swift` (not `BridgeJSMacros/*`), and `@JSFunction(module: …)` would otherwise fail to compile ("extra argument 'module'"). +- Reusing the existing `from:` parameter avoids all macro-signature changes: once `.module(String)` exists on the enum, users write `@JSFunction(from: .module("components"))`, unifying routing on one axis (`.global` / `.module(name)` / `nil`). + +So this plan **extends both enums** and updates `extractJSImportFrom`; it does **not** touch macro expansion code and adds **no** `module:` argument. + +### Scope: JS snippets only (no TypeScript transpilation) +Per the design (and Yuta's non-goals), snippet files are **plain `.js`/`.mjs`** shipped as-is to the bundler/dev-server. A `.ts` snippet is rejected with a diagnostic. Transpiling TS is explicitly out of scope. + +### Scope: macro-authored imports only (F5 — the d.ts route can't target snippets yet) +`.module` is wired through the **Swift macro** path (`extractJSImportFrom`). Projects that declare imports via the TypeScript route (`bridge-js.d.ts` → ts2swift → `BridgeJS.Macros.swift`) have **no way to say "this import comes from my snippet"** in this phase — d.ts-declared imports remain app-provided (`from == nil`). This matters for d.ts-heavy codebases (e.g. khasm-style projects). Follow-up option (out of scope here): a JSDoc tag in the d.ts (e.g. `/** @bridgeModule components */`) that ts2swift lowers to `from: .module("components")`. Listed in the report's Open Questions. + +**Verified anchors:** +- Public enum + macro signatures: `Macros.swift:12, 141, 159, 180, 205` (only used in macro signatures; no `rawValue` dependence in `Sources`/`Tests`/`Examples`, so dropping `: String` is safe). +- `from:` parsing: `SwiftToSkeleton.swift:2344-2357` (`extractJSImportFrom`, splits the expression text on `.` and calls `JSImportFrom(rawValue:)`). +- Skeleton enum + `from:` fields: `BridgeJSSkeleton.swift:1085-1087, 1094, 1187, 1306`. +- Routing sites: `importRootExpr = X.from == .global ? "globalThis" : "imports"` at `BridgeJSLink.swift:3335, 3359, 3458, 3513`; "app must provide" `.d.ts` gated on `from == nil` (`:3339, 3367, 3418`). +- Each unified skeleton carries its owning Swift module name as `unified.moduleName` (used throughout `collectLinkData`, e.g. `:270, 296`) — used to **package-scope** snippet namespaces. +- Transitive collector to mirror: `SkeletonCollector` — `PackageToJSPlugin.swift:703-784` (crosses package boundaries at `:773-776`). +- Template-copy mechanism: `planCopyTemplateFile` / `make.addTask` — `PackageToJS.swift:587, 597-617, 620-634`. +- Config struct: `BridgeJSConfig` in `BridgeJSCore/Misc.swift` (fields `exposeToGlobal`, `identityMode`, `tools`). + +--- + +## File Structure + +- **Modify** `Sources/JavaScriptKit/Macros.swift:12-14` — change the **public** `JSImportFrom` from a `String` raw enum to an enum with `.global` and `.module(String)`. (No macro-signature change; `from:` already exists.) +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift:1085-1087` — change the **skeleton** `JSImportFrom` to a custom `Codable` enum with `.global` and `.module(String)` (back-compatible codec). +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift:2344` — extend `extractJSImportFrom` to parse `.module("name")` call syntax. +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` — route `.module(name)` at the four `importRootExpr` sites to a **package-scoped** namespace; emit an ESM `import` per referenced snippet at the top of `bridge-js.js`; record references for validation. +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift` — add `jsModules: [String: String]` to `BridgeJSConfig` (logical module name → snippet **entry file** path, relative to the target dir). +- **Create** `Plugins/PackageToJS/Sources/SnippetCollector.swift` — transitive collection of declared snippet entry files + their owning Swift module name. +- **Modify** `Plugins/PackageToJS/Sources/PackageToJS.swift` + `PackageToJSPlugin.swift` — copy each snippet's **source directory** (preserving structure/extension) into `snippets//`, validate every referenced `.module` is declared, and ensure import paths resolve. +- **Tests** under `Plugins/BridgeJS/Tests/BridgeJSToolTests/` + an `Examples/` fixture. + +--- + +## Task 1: Extend the skeleton `JSImportFrom` with `.module(name)` + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift:1085-1087` +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/JSImportFromTests.swift` (new) + +- [ ] **Step 1: Write the failing test** + +```swift +import Foundation +import Testing +@testable import BridgeJSSkeleton + +@Suite struct JSImportFromTests { + @Test func encodesAndDecodesModuleCase() throws { + let value = JSImportFrom.module("elementary-components") + let data = try JSONEncoder().encode(value) + let decoded = try JSONDecoder().decode(JSImportFrom.self, from: data) + #expect(decoded == .module("elementary-components")) + } + + @Test func decodesLegacyGlobalString() throws { + // Back-compat: existing skeletons encode `.global` as the bare string "global". + let data = Data("\"global\"".utf8) + let decoded = try JSONDecoder().decode(JSImportFrom.self, from: data) + #expect(decoded == .global) + } +} +``` + +- [ ] **Step 2: Run to verify it fails** + +Run: `swift test --package-path Plugins/BridgeJS --filter JSImportFromTests` +Expected: FAIL to compile — `type 'JSImportFrom' has no member 'module'`. + +- [ ] **Step 3: Replace the skeleton enum with a back-compatible custom codec** + +Replace `BridgeJSSkeleton.swift:1085-1087`: + +```swift +public enum JSImportFrom: Codable, Equatable { + case global + case module(String) + + public init(from decoder: any Decoder) throws { + // Legacy form: the bare string "global". + if let single = try? decoder.singleValueContainer(), + let raw = try? single.decode(String.self), raw == "global" { + self = .global + return + } + // New form: { "module": "" }. + let keyed = try decoder.container(keyedBy: CodingKeys.self) + if let name = try keyed.decodeIfPresent(String.self, forKey: .module) { + self = .module(name) + return + } + throw DecodingError.dataCorrupted( + .init(codingPath: decoder.codingPath, debugDescription: "Unrecognized JSImportFrom") + ) + } + + public func encode(to encoder: any Encoder) throws { + switch self { + case .global: + var c = encoder.singleValueContainer() + try c.encode("global") // preserve legacy bare-string form + case .module(let name): + var c = encoder.container(keyedBy: CodingKeys.self) + try c.encode(name, forKey: .module) + } + } + + private enum CodingKeys: String, CodingKey { case module } +} +``` + +- [ ] **Step 4: Run to verify it passes** + +Run: `swift test --package-path Plugins/BridgeJS --filter JSImportFromTests` +Expected: PASS. + +- [ ] **Step 5: Confirm no skeleton/link snapshot drift** + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests` +Expected: PASS — `.global` still serializes to `"global"`, so existing snapshots are unchanged. + +- [ ] **Step 6: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift Plugins/BridgeJS/Tests/BridgeJSToolTests/JSImportFromTests.swift +git commit -m "feat(bridge-js): add skeleton JSImportFrom.module case (back-compatible codec)" +``` + +--- + +## Task 2: Extend the public enum and parse `from: .module("…")` + +**Files:** +- Modify: `Sources/JavaScriptKit/Macros.swift:12-14` +- Modify: `Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift:2344-2357` +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/ModuleImportSkeletonTests.swift` (new) + +- [ ] **Step 1: Write the failing skeleton test** + +```swift +import Foundation +import SwiftParser +import Testing +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +@Suite struct ModuleImportSkeletonTests { + @Test func parsesModuleFromAttributeIntoFrom() throws { + let source = """ + import JavaScriptKit + @JSFunction(from: .module("elementary-components")) + func defineComponent(name: String) + """ + let file = Parser.parse(source: source) + let importer = SwiftToSkeleton( + progress: .silent, moduleName: "TestModule", + exposeToGlobal: false, externalModuleIndex: .empty + ) + importer.addSourceFile(file, inputFilePath: "ModuleImport.swift") + let result = try importer.finalize() + let fn = try #require(result.imported?.children.flatMap(\.functions).first) + #expect(fn.from == .module("elementary-components")) + } +} +``` + +- [ ] **Step 2: Run to verify it fails** + +Run: `swift test --package-path Plugins/BridgeJS --filter ModuleImportSkeletonTests` +Expected: FAIL — `extractJSImportFrom` returns `nil` for `.module("…")` (current `JSImportFrom(rawValue:)` can't build an associated-value case). + +- [ ] **Step 3: Extend the public enum (drop the raw-value conformance)** + +Replace `Macros.swift:12-14`: + +```swift +/// Controls where BridgeJS reads imported JS values from. +/// +/// - `global`: Read from `globalThis`. +/// - `module(name)`: Read from a package-owned JS snippet module declared in +/// `bridge-js.config.json` under `jsModules`. +public enum JSImportFrom { + case global + case module(String) +} +``` + +> **Source-compatibility note (M1) — this is a public API change, call it out in the changelog.** `JSImportFrom` is `public`; dropping `: String` removes its `RawRepresentable` conformance, so any *external* code using `JSImportFrom(rawValue:)` or `.global.rawValue` stops compiling. A Swift enum with associated values cannot keep a raw type, so the conformance cannot be preserved as-is. +> +> - **In-repo:** verified safe — the enum is referenced only in the four macro signatures; nothing reads `rawValue`. +> - **External impact:** likely negligible (this is a niche macro-argument enum, and BridgeJS is pre-1.0 / post-MVP), but it is still a source break. Document it in `CHANGELOG.md`. +> - **Optional softening (only if external source-compat is a hard requirement):** hand-conform to `RawRepresentable` with `String` raw values — `var rawValue` returns `"global"` / `"module()"`, and `init?(rawValue:)` parses them back. This preserves `.global` round-trips and most existing call sites; weigh the API ugliness against the break. Default recommendation: take the clean break + changelog entry. + +- [ ] **Step 4: Teach `extractJSImportFrom` to parse `.module("…")`** + +Replace the body of `extractJSImportFrom` (`SwiftToSkeleton.swift:2344-2357`) so it handles both the member-access form (`.global`) and the function-call form (`.module("name")`): + +```swift +static func extractJSImportFrom(from attribute: AttributeSyntax) -> JSImportFrom? { + guard let arguments = attribute.arguments?.as(LabeledExprListSyntax.self) else { return nil } + for argument in arguments { + guard argument.label?.text == "from" else { continue } + + // Function-call form: `.module("name")` + if let call = argument.expression.as(FunctionCallExprSyntax.self), + let member = call.calledExpression.as(MemberAccessExprSyntax.self), + member.declName.baseName.text == "module", + let firstArg = call.arguments.first, + let str = firstArg.expression.as(StringLiteralExprSyntax.self), + let seg = str.segments.first?.as(StringSegmentSyntax.self) { + return .module(seg.content.text) + } + + // Member-access form: `.global` / `JSImportFrom.global` + let description = argument.expression.trimmedDescription + let caseName = description.split(separator: ".").last.map(String.init) ?? description + if caseName == "global" { return .global } + } + return nil +} +``` + +> `JSImportFrom` here is the **skeleton** enum (BridgeJSCore imports BridgeJSSkeleton). `.module(_)` was added in Task 1. + +- [ ] **Step 5: Run to verify it passes** + +Run: `swift test --package-path Plugins/BridgeJS --filter ModuleImportSkeletonTests` +Expected: PASS. + +- [ ] **Step 6: Commit** + +```bash +git add Sources/JavaScriptKit/Macros.swift Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift Plugins/BridgeJS/Tests/BridgeJSToolTests/ModuleImportSkeletonTests.swift +git commit -m "feat(bridge-js): support from: .module(name) on import macros" +``` + +--- + +## Task 3: Route `.module(name)` to a package-scoped snippet namespace in BridgeJSLink + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` (routing sites `:3335, 3359, 3458, 3513`; import-collection in `collectLinkData` `:267-292`; `LinkData` `:166-177`; JS header in `generateJavaScript` `:1056+`) +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift` + new snapshot input + +**Package-scoping (fixes cross-package name collisions):** the bundled path and JS namespace are keyed by the **owning Swift module name** (`unified.moduleName`, always unique in a package graph) plus the user's logical module name. Two packages each declaring `"components"` therefore never collide. + +- [ ] **Step 1: Add scoping + namespace helpers** + +Add near the `renderImported*` functions (above `:3322`): + +```swift +/// Deterministic, collision-resistant JS identifier for a snippet namespace, +/// scoped by the owning Swift module so two packages can reuse the same logical name. +static func snippetNamespaceConst(swiftModule: String, moduleName: String) -> String { + func enc(_ s: String) -> String { + // Reversible-enough encoding: non-alphanumerics become __ so + // "a-b" and "a.b" and "a_b" never collide. + s.unicodeScalars.map { sc in + (("a"..."z").contains(Character(sc)) || ("A"..."Z").contains(Character(sc)) || ("0"..."9").contains(Character(sc))) + ? String(sc) : "_\(String(sc.value, radix: 16))_" + }.joined() + } + return "__bjs_snippet_\(enc(swiftModule))$\(enc(moduleName))" +} + +/// Bundled path for a snippet module's entry file (matches PackageToJS copy in Task 6). +/// Keyed by BOTH the owning Swift module AND the logical module name so two +/// logical modules in the SAME target (e.g. entries `JavaScript/a/index.js` and +/// `JavaScript/b/index.js`) never collide on a shared `index.js`. +static func snippetImportPath(swiftModule: String, moduleName: String, entryFileName: String) -> String { + "./snippets/\(swiftModule)/\(moduleName)/\(entryFileName)" +} +``` + +- [ ] **Step 2: Route the four sites through the owning skeleton's module name** + +Each `renderImported*` is called from `collectLinkData` with the `unified` skeleton in scope (`:268-292`). Thread the owning `moduleName` into the `renderImported*` functions (add a `swiftModule: String` parameter), and at the four sites replace +`let importRootExpr = X.from == .global ? "globalThis" : "imports"` +with: + +```swift +let importRootExpr: String +switch X.from { +case .global: importRootExpr = "globalThis" +case .module(let name): + importRootExpr = Self.snippetNamespaceConst(swiftModule: swiftModule, moduleName: name) +case nil: importRootExpr = "imports" +} +``` + +Leave the `if X.from == nil { appendDts(...) }` blocks unchanged — only app-provided (`nil`) imports belong in the consumer-facing `.d.ts`; `.module` imports are satisfied by the package. + +- [ ] **Step 3: Record (swiftModule, moduleName) references for import emission + validation** + +In `struct LinkData` (`:166-177`) add: +```swift +// (owning Swift module, logical snippet module name) pairs referenced via .module(_) +var referencedSnippetModules: Set = [] +``` +Define `struct SnippetRef: Hashable { let swiftModule: String; let moduleName: String }` near `LinkData`. + +In the imported-skeleton loop (`:268-292`), when a getter/function/type has `from == .module(name)`, insert `data.referencedSnippetModules.insert(.init(swiftModule: unified.moduleName, moduleName: name))`. + +- [ ] **Step 4: Emit ESM imports for referenced snippets** + +In `generateJavaScript(data:)` (`:1056+`), at the very top of the emitted file, emit one import + namespace const per referenced module, sorted for determinism. The **entry file name** is provided by PackageToJS (Task 6) as the snippet's *real* entry filename (e.g. `components.js`); BridgeJSLink receives it via a new `snippetEntryNames: [SnippetRef: String]` map passed into `BridgeJSLink` (defaulting to `"index.js"` when absent, only so unit snapshots without PackageToJS are stable): + +```swift +for ref in data.referencedSnippetModules.sorted(by: { ($0.swiftModule, $0.moduleName) < ($1.swiftModule, $1.moduleName) }) { + let ns = Self.snippetNamespaceConst(swiftModule: ref.swiftModule, moduleName: ref.moduleName) + let entry = snippetEntryNames[ref] ?? "index.js" + printer.write("import * as \(ns) from \"\(Self.snippetImportPath(swiftModule: ref.swiftModule, moduleName: ref.moduleName, entryFileName: entry))\";") +} +``` + +- [ ] **Step 5: Add a link snapshot input that uses a module import** + +Create `Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ModuleImport.swift`: + +```swift +import JavaScriptKit + +@JSFunction(from: .module("elementary-components")) +func defineComponent(name: String, render: (JSObject) -> Void) +``` + +- [ ] **Step 6: Run link snapshots (records new snapshot)** + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests` +Expected: records `ModuleImport.js`/`.d.ts`; verify `bridge-js.js` contains +`import * as __bjs_snippet_TestModule$elementary_2d_components from "./snippets/TestModule/elementary-components/index.js";` +(owning module "TestModule" comes from the test harness; the `elementary-components` subdirectory is the logical module name), the `defineComponent` thunk reads from that namespace, and `ModuleImport.d.ts` does **not** list `defineComponent` under the app `imports` interface. + +- [ ] **Step 7: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift Plugins/BridgeJS/Tests/BridgeJSToolTests +git commit -m "feat(bridge-js): route .module imports to package-scoped snippet namespaces" +``` + +--- + +## Task 4: Declare snippet entry files in `BridgeJSConfig` + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift` (`BridgeJSConfig`) +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/ConfigJSModulesTests.swift` (new) + +- [ ] **Step 1: Write a failing config-decode test** + +```swift +import Foundation +import Testing +@testable import BridgeJSCore + +@Suite struct ConfigJSModulesTests { + @Test func decodesJsModulesMap() throws { + let json = """ + { "jsModules": { "elementary-components": "JavaScript/elementary-components.js" } } + """ + let config = try JSONDecoder().decode(BridgeJSConfig.self, from: Data(json.utf8)) + #expect(config.jsModules["elementary-components"] == "JavaScript/elementary-components.js") + } + + @Test func defaultsToEmptyWhenAbsent() throws { + let config = try JSONDecoder().decode(BridgeJSConfig.self, from: Data("{}".utf8)) + #expect(config.jsModules.isEmpty) + } +} +``` + +- [ ] **Step 2: Run to verify it fails** + +Run: `swift test --package-path Plugins/BridgeJS --filter ConfigJSModulesTests` +Expected: FAIL — `BridgeJSConfig` has no `jsModules`. + +- [ ] **Step 3: Add the field** + +In `Misc.swift`, add to `BridgeJSConfig`, mirroring the existing optional-with-default pattern of `exposeToGlobal`/`identityMode` (field + `CodingKeys` entry + `decodeIfPresent(...) ?? [:]` in `init(from:)`): + +```swift +/// Maps a logical JS module name (used in `from: .module("name")`) to the snippet +/// ENTRY file path relative to the target source directory. The entry file may +/// import sibling files; the whole containing directory is bundled (see PackageToJS). +/// Module names are scoped per target, so two packages may reuse the same name. +public var jsModules: [String: String] = [:] +``` + +- [ ] **Step 4: Run to verify it passes** + +Run: `swift test --package-path Plugins/BridgeJS --filter ConfigJSModulesTests` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift Plugins/BridgeJS/Tests/BridgeJSToolTests/ConfigJSModulesTests.swift +git commit -m "feat(bridge-js): add jsModules snippet declaration to BridgeJSConfig" +``` + +--- + +## Task 5: Validate referenced `.module` names are declared (no dangling imports) + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift` (the `generate` subcommand, where the imported skeleton and `BridgeJSConfig` are both in scope, ~`:132, :255`) +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/` diagnostic test (or a `BridgeJSCore` validation unit test) + +A typo'd or undeclared `from: .module("nope")` must fail with a clear diagnostic at generate time, not produce a dangling ESM import that breaks the bundler/runtime later. + +- [ ] **Step 1: Write a failing validation test** + +Add a unit test that runs `SwiftToSkeleton` on a source with `from: .module("nope")` and asserts a validator (introduced below) reports an error when `nope` is absent from `config.jsModules`. Mirror the existing diagnostic-test style in `DiagnosticsTests.swift`. + +```swift +@Test func undeclaredModuleProducesDiagnostic() throws { + let referenced: Set = ["nope"] + let declared: Set = ["components"] + let missing = BridgeJSConfig.undeclaredSnippetModules(referenced: referenced, declared: declared) + #expect(missing == ["nope"]) +} +``` + +- [ ] **Step 2: Run to verify it fails** + +Run: `swift test --package-path Plugins/BridgeJS --filter undeclaredModuleProducesDiagnostic` +Expected: FAIL — no such helper. + +- [ ] **Step 3: Add the validation helper and call it in `generate`** + +In `Misc.swift` (near `BridgeJSConfig`): + +```swift +extension BridgeJSConfig { + /// Logical snippet module names referenced by `from: .module(_)` but not declared in `jsModules`. + static func undeclaredSnippetModules(referenced: Set, declared: Set) -> Set { + referenced.subtracting(declared) + } +} +``` + +In the `generate` subcommand (`BridgeJSTool.swift`), after building `skeleton`, gather the referenced logical module names from the imported skeleton's `.module(name)` entries, compare against `Set(config.jsModules.keys)`, and on any difference throw a `BridgeJSToolError`: + +```text +"@JS import references undeclared JS module(s): nope. Declare them in +bridge-js.config.json under \"jsModules\", e.g. { \"jsModules\": { \"nope\": \"JavaScript/nope.js\" } }." +``` + +- [ ] **Step 4: Run to verify it passes** + +Run: `swift test --package-path Plugins/BridgeJS --filter undeclaredModuleProducesDiagnostic` +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift Plugins/BridgeJS/Tests/BridgeJSToolTests +git commit -m "feat(bridge-js): diagnose undeclared .module references at generate time" +``` + +--- + +## Task 6: Collect and copy snippet directories transitively in PackageToJS + +**Files:** +- Create: `Plugins/PackageToJS/Sources/SnippetCollector.swift` +- Modify: `Plugins/PackageToJS/Sources/PackageToJSPlugin.swift` (invoke alongside `SkeletonCollector`) +- Modify: `Plugins/PackageToJS/Sources/PackageToJS.swift` (copy directories; feed entry names to BridgeJSLink) + +**Directory copy (fixes relative/npm/TS resolution + same-module collisions):** copy each snippet's **containing directory** preserving structure and file extensions, to a path keyed by **both** the owning Swift module and the logical module name: `snippets///`. The entry file keeps its real name; BridgeJSLink imports `./snippets///`. This preserves sibling relative imports (`./helpers.js`) **and** guarantees two logical modules in one target never clobber each other (e.g. both shipping an `index.js`). Bare/npm imports inside snippets remain the app bundler's responsibility (documented in Task 7). + +- [ ] **Step 1: Add `SnippetCollector` mirroring `SkeletonCollector`** + +Create `Plugins/PackageToJS/Sources/SnippetCollector.swift` modeled on `SkeletonCollector` (`PackageToJSPlugin.swift:703-784`), including the cross-package traversal (`:773-776`). For each visited `SwiftSourceModuleTarget`, read its `bridge-js.config.json` `jsModules`; for each `(logicalName, entryRelPath)` resolve the entry file under `target.directoryURL`, reject `.ts`/`.tsx` with a diagnostic, and record: + +```swift +struct CollectedSnippet { + let swiftModule: String // target.name — the scoping key + let moduleName: String // logical name from jsModules + let entryFileURL: URL // resolved entry file + let sourceDirURL: URL // entryFileURL.deletingLastPathComponent() + var entryFileName: String { entryFileURL.lastPathComponent } +} +``` + +Return `[CollectedSnippet]`. Decode `jsModules` via a minimal local `Decodable` to avoid a plugin→tool module dependency. + +> **Module-name uniqueness guard (F2):** the scoping key `snippets//…` assumes Swift module names are unique across the dependency graph — SwiftPM does *not* enforce that (two packages may each have a target `Models`). While collecting, track `moduleName -> Package.ID`; if the same target name appears from **two different packages**, emit a `Diagnostics.error` naming both packages (same wording as the Phase 3 discovery check). This closes the collision for snippets even if Phase 2 ships before Phase 3. + +- [ ] **Step 2: Invoke the collector and feed entry names to the linker** + +In `PackageToJSPlugin.swift` near `:201-202`, run `SnippetCollector.collectFromProduct(name: productName)` and pass the result into `PackagingPlanner` alongside `skeletons`. Build the `snippetEntryNames: [SnippetRef: String]` map (keyed by `(swiftModule, moduleName)`) and pass it into the `BridgeJSLink` constructed at `PackageToJS.swift:602` so the emitted imports use the real entry filename. + +- [ ] **Step 3: Copy snippet directories** + +In `PackageToJS.swift` (near the template-copy/`bridge-js.js` area `:597-634`), add a copy task per `CollectedSnippet` that recursively copies `sourceDirURL` → `snippets///` (preserving structure/extension), reusing the existing copy-task pattern. The destination + entry filename must match BridgeJSLink's emitted import (`./snippets///`). + +> The per-`moduleName` subdirectory is **mandatory, not a fallback** — it is what guarantees collision-freedom when one target declares multiple logical modules (each may legitimately ship its own `index.js`). `snippetImportPath` (Task 3) and this copy destination must use the identical `snippets///` shape. + +- [ ] **Step 4: Lightweight export-name validation (warning, F4)** + +Task 5 validates the module *name* is declared, but nothing checks the snippet actually **exports the symbols Swift binds to** — a typo'd JS export otherwise surfaces only at runtime as `undefined is not a function` deep inside a thunk. Add a cheap static check at collection time: scan the snippet **entry file** for top-level `export` identifiers (regex over `export function ` / `export const|let|var ` / `export { }` — no full JS parse), compare against the imported skeleton's symbol names bound to that module, and emit a **warning** (not an error — the export may come from a re-export or dynamic pattern the scan can't see) listing referenced-but-not-found names. Full type-level validation is explicitly out of scope. + +- [ ] **Step 5: Verify end-to-end on an example** + +Create/extend an example: a target with `Sources//JavaScript/components.js` (which itself `import`s a sibling `./helpers.js`) exporting `defineComponent`, `bridge-js.config.json` `{ "jsModules": { "components": "JavaScript/components.js" } }`, and Swift `@JSFunction(from: .module("components")) func defineComponent(...)`. + +Run: +```bash +swift package --package-path Examples/ --swift-sdk $SWIFT_SDK_ID js +``` +Expected: output contains `snippets//components/components.js` **and** `snippets//components/helpers.js`; `bridge-js.js` imports `./snippets//components/components.js`; the sibling import resolves; the snippet's top-level code runs at load. + +- [ ] **Step 6: Commit** + +```bash +git add Plugins/PackageToJS/Sources/SnippetCollector.swift Plugins/PackageToJS/Sources/PackageToJSPlugin.swift Plugins/PackageToJS/Sources/PackageToJS.swift Examples +git commit -m "feat(packagetojs): bundle package-owned JS snippet directories (package-scoped)" +``` + +--- + +## Task 7: Documentation + +**Files:** +- Modify: `Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/` (new "Shipping JS with a package" article) + +- [ ] **Step 1: Document the authoring flow** + +Cover: (1) put JS in `Sources//JavaScript/.js` (siblings allowed; bare/npm imports are resolved by the app bundler, not BridgeJS); (2) declare it in `bridge-js.config.json` `jsModules` (entry file path; names are per-target scoped); (3) bind from Swift with `from: .module("")`. Note: `.js`/`.mjs` only (no TS transpilation); load-time side effects run because the snippet is imported as an ESM module; bidirectional calls happen by passing Swift closures as arguments. + +- [ ] **Step 2: Commit** + +```bash +git add Sources/JavaScriptKit/Documentation.docc +git commit -m "docs(bridge-js): document shipping JS snippets with a package" +``` + +--- + +## Self-Review + +**Spec coverage:** third import source via reused `from:` axis (Tasks 1–3), authoring via existing macros + config (Tasks 2, 4), undeclared-reference diagnostic (Task 5), directory-preserving transitive bundling + package-scoped naming (Task 6), side effects + docs (Task 7). ✓ + +**First-review fixes folded in:** +- **C1** — extends BOTH `JSImportFrom` enums (`Macros.swift:12` public + skeleton) and updates `extractJSImportFrom`; reuses `from:` (no `module:` arg, no macro-impl edits). Tasks 1–2. +- **C2** — copies the snippet's whole source directory preserving structure/extension; `.js`/`.mjs` only, `.ts` rejected. Task 6. +- **C3** — generate-time validation that every referenced `.module` is declared. Task 5. +- **H1 (cross-package)** — snippet dir + JS namespace are scoped by the owning Swift module (`unified.moduleName`); cross-package `"components"` collisions are impossible. Task 3 + Task 6. +- **M1 (namespace encoding)** — `snippetNamespaceConst` encodes non-alphanumerics as `__`, so `a-b`/`a.b`/`a_b` never collide. Task 3. + +**Follow-up (F-series) fixes folded in:** +- **F2 (module-name uniqueness)** — `SnippetCollector` errors on the same target name appearing from two different packages (the `snippets//` scoping key assumes graph-wide uniqueness SwiftPM doesn't enforce). Task 6 Step 1. +- **F4 (export-name validation)** — lightweight static scan of the snippet entry's `export` identifiers vs the Swift-bound symbol names; warning on missing. Task 6 Step 4. +- **F5 (d.ts route can't target snippets)** — explicitly scoped out with a follow-up option (JSDoc `@bridgeModule` tag lowered by ts2swift); surfaced in the report's Open Questions. Context section. + +**Second-review fixes folded in:** +- **H2 (same-module path identity)** — the bundled path and import are keyed by the **full `SnippetRef`** (`snippets///`), so two logical modules in one target can't collide on a shared `index.js`. The per-`moduleName` subdirectory is mandatory, not a fallback. `snippetImportPath` now takes `moduleName:`. Task 3 Steps 1/4/6 + Task 6. +- **M1 (public RawRepresentable break)** — dropping `: String` from the public `JSImportFrom` is now flagged as an explicit source-compatibility break (changelog entry required), with an optional hand-rolled `RawRepresentable` shim if external source-compat is a hard requirement. Task 2 Step 3. + +**Placeholder scan:** Task 5 Step 3 and Task 6 Steps 1–3 reference existing patterns (`SkeletonCollector`, the copy-task mechanism, the diagnostic style) with concrete anchors rather than re-deriving them; all novel logic (both enum codecs, `extractJSImportFrom`, routing switch, namespace/scoping helpers, validation helper, config field) has complete code. + +**Type consistency:** `JSImportFrom.module(_:)` (both enums), `snippetNamespaceConst(swiftModule:moduleName:)`, `snippetImportPath(swiftModule:moduleName:entryFileName:)`, `SnippetRef`, `LinkData.referencedSnippetModules`, `snippetEntryNames`, `BridgeJSConfig.jsModules`, `undeclaredSnippetModules`, `CollectedSnippet` are defined where introduced and used consistently. The bundled path `./snippets///` is identical in Task 3 Step 4 and Task 6 Step 3. + +--- + +## Execution Handoff + +Subagent-Driven (recommended) or Inline. Execute Tasks 1→2→3 together (they interlock through the snapshot input); then 4→5 (config + validation); then 6 end-to-end. diff --git a/docs/superpowers/plans/2026-06-17-bridgejs-phase3-cross-package.md b/docs/superpowers/plans/2026-06-17-bridgejs-phase3-cross-package.md new file mode 100644 index 000000000..2c16137a4 --- /dev/null +++ b/docs/superpowers/plans/2026-06-17-bridgejs-phase3-cross-package.md @@ -0,0 +1,353 @@ +# BridgeJS Cross-Package `@JS` Composition (Phase 3) Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Let a `@JS` declaration in one Swift package reference `@JS` types exported by a *different* Swift package (e.g. an app uses a type from ElementaryUI), so multi-package apps compose without manual re-declaration. This closes the "multi-package composition" problem (#477/#508 discussion). + +**Architecture:** The type-resolution engine already supports cross-module references — `SwiftToSkeleton` consumes an `ExternalModuleIndex` built from dependency skeletons and resolves external types (`CrossModuleResolutionTests` proves it via `usedExternalModules`). Runtime composition also already works cross-package (`SkeletonCollector` in PackageToJS traverses package boundaries). The *only* missing piece is build-time **discovery**: `BridgeJSBuildPlugin.dependencySkeletons` filters out targets that are not in the current package (`:110`), so a package never sees a dependency package's skeleton. This phase lifts that filter and resolves dependency skeletons across package boundaries via their committed `Generated/JavaScript/BridgeJS.json`. + +**Tech Stack:** Swift (BridgeJS build + command plugins, core resolver), Swift Testing. + +--- + +## Context + +Independent of Phases 1 and 2. No developer-facing command change. New *expectation*: a package that exposes `@JS` types for cross-package use ships its committed `Generated/JavaScript/BridgeJS.json` (already the standard AoT recommendation for libraries). The consumer keeps running `swift package js` unchanged. + +> **Hazard (addressed by Task 6): stale committed skeleton.** Cross-package resolution reads the dependency's *committed* `BridgeJS.json`. If a dependency author edits `@JS` types but forgets to regenerate and commit, the consumer silently builds against a stale interface (wrong `abiName`/arity) — an ABI mismatch surfacing only at runtime. Task 6 adds drift detection (an input-hash stamp covering Swift + config + d.ts + dependency hashes + codegen version, plus a warning) and a CI regenerate-check so this fails loudly, not silently. + +**Verified anchors:** +- Engine already resolves external types: `CrossModuleResolutionTests.swift` (`usedExternalModules`, `.swiftStruct("Vector3D")` across modules); `ExternalModuleIndex(dependencies:)` — `ExternalModuleIndex.swift:26`. +- Build-plugin same-package filter (the blocker): `BridgeJSBuildPlugin.swift:106-116`, specifically `context.package.targets.contains(where: { $0.id == swiftTarget.id })` at `:110`, with a code comment (`:97-101`) explaining it's a discovery limitation. +- Build-plugin path uses `packageID: context.package.id` to locate the skeleton (`:123`) — must be generalized to the dependency's package. +- Command (AoT) plugin already reads dependency skeletons from committed `Generated/JavaScript/BridgeJS.json` (`BridgeJSCommandPlugin.swift:165-178`) — confirm/extend its cross-package coverage. +- PackageToJS runtime collection already crosses packages: `SkeletonCollector.visit` (`PackageToJSPlugin.swift:773-776`). + +--- + +## File Structure + +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift` — extend `dependencySkeletons` to include cross-package dependency targets and resolve their committed skeleton paths. +- **Modify** `Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift` — ensure AoT dependency-skeleton discovery walks cross-package dependencies (it already targets `Generated/JavaScript/BridgeJS.json`; verify package traversal). +- **Possibly modify** `Plugins/BridgeJS/Sources/BridgeJSPluginUtilities/PluginPaths.swift` — a helper to resolve a dependency target's committed skeleton URL given its owning package. +- **Tests**: extend `CrossModuleResolutionTests` for the cross-package shape (engine already supports it; assert the discovery wiring feeds it), plus an `Examples/` two-package fixture. + +--- + +## Task 1: Resolve a dependency target's committed skeleton URL across packages + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSPluginUtilities/PluginPaths.swift` +- Test: `Plugins/BridgeJS/Tests/BridgeJSToolTests/` (path-resolution unit test if `PluginPaths` is testable; otherwise covered by Task 3 integration) + +- [ ] **Step 1: Add a committed-skeleton path helper** + +In `PluginPaths.swift`, add a helper that, given a dependency `SwiftSourceModuleTarget`, returns the committed AoT skeleton URL: + +```swift +/// The committed (AoT) skeleton location a dependency package ships for +/// cross-package `@JS` type resolution. +static func committedSkeletonURL(targetDirectoryURL: URL) -> URL { + targetDirectoryURL + .appending(path: "Generated") + .appending(path: "JavaScript") + .appending(path: "BridgeJS.json") +} +``` + +> This mirrors the path the command plugin already reads (`BridgeJSCommandPlugin.swift:165-166`) and the `outputSkeletonURL` the tool writes (`BridgeJSTool.swift:264`). + +- [ ] **Step 2: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSPluginUtilities/PluginPaths.swift +git commit -m "feat(bridge-js): add committed-skeleton path helper for cross-package resolution" +``` + +--- + +## Task 2: Lift the same-package filter in the build plugin + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift:102-140` + +- [ ] **Step 1: Include cross-package dependency targets** + +Replace the `localTargets` filter at `:106-116` so it keeps **all** `SwiftSourceModuleTarget` recursive dependencies that have a `bridge-js.config.json`, regardless of owning package. The owning package is needed to locate the skeleton; build a `target.id -> package` map from `context.package.dependencies` (same approach `SkeletonCollector` uses at `PackageToJSPlugin.swift:766-771`). + +```swift +// Build target.id -> owning Package map across the dependency graph. +var packageByTargetID: [Target.ID: Package] = [:] +func indexTargets(of package: Package) { + for target in package.targets { packageByTargetID[target.id] = package } + for dep in package.dependencies { indexTargets(of: dep.package) } +} +indexTargets(of: context.package) + +let dependencyTargets: [(target: SwiftSourceModuleTarget, package: Package)] = + target.recursiveTargetDependencies.compactMap { dependency in + guard + let swiftTarget = dependency as? SwiftSourceModuleTarget, + FileManager.default.fileExists(atPath: pathToConfigFile(target: swiftTarget).path), + let owningPackage = packageByTargetID[swiftTarget.id] + else { return nil } + return (swiftTarget, owningPackage) + } +``` + +- [ ] **Step 2: Fix the input-file model for cross-package deps (H1)** + +**Why this matters.** The build plugin passes `--dependency-skeleton =` (the file actually *read*) but lists a **different** file as the tracked `inputFile` — currently always `skeleton.bridgeJSSwiftURL` (`BridgeJSBuildPlugin.swift:66-77`). For a **same-package** dep that's correct: the dep's `BridgeJS.swift` is an *output* of the dep's own plugin invocation, so listing it as an input creates the build-graph **ordering edge** (dep generates first). But for a **cross-package** dep: +> - its `BridgeJS.swift` is **not** produced by this package's plugin run, so a work-dir path for it is missing/stale (and the `packageID: owningPackage.id` + this package's `pluginWorkDirectoryURL` combination is nonsensical); +> - the file actually read — the committed `Generated/JavaScript/BridgeJS.json` — is **never tracked**, so edits to it don't retrigger. +> +> Fix: track the **committed skeleton itself** as the input for cross-package deps (it's a real committed file on disk, and no cross-package ordering edge is needed because the dependency package is already fully built). Keep `bridgeJSSwiftURL` as the input only for same-package ordering. + +Give `DependencySkeleton` (`:91-95`) an explicit `inputFileURL` and set it per origin: + +```swift +private struct DependencySkeleton { + let moduleName: String + let skeletonURL: URL // the file passed to --dependency-skeleton (the read input) + let inputFileURL: URL // the file tracked as a build inputFile (ordering / change-tracking) +} +``` + +**Module-name uniqueness (F2):** BridgeJS keys everything by the Swift module name — `ImportObjectBuilder` merges by `moduleName` string (`BridgeJSLink.swift:302`), Phase 2 scopes snippets by `snippets//…`, and closure thunks are named `...__...`. SwiftPM *permits* two packages to each define a target with the same name, which would silently merge/collide. A plain `seen.insert(name)` dedupe would silently drop one. **Detect and error instead:** + +```swift +var skeletons: [DependencySkeleton] = [] +var seenOwners: [String: Package.ID] = [:] // moduleName -> owning package +for (swiftTarget, owningPackage) in dependencyTargets { + if let existingOwner = seenOwners[swiftTarget.name] { + if existingOwner != owningPackage.id { + Diagnostics.error(""" + Duplicate BridgeJS module name '\(swiftTarget.name)' found in packages \ + '\(existingOwner)' and '\(owningPackage.id)'. BridgeJS keys bridge state, \ + snippets, and import objects by module name, so names must be unique across \ + the dependency graph. Rename one of the targets. + """) + } + continue // same target reached via two paths — skip + } + seenOwners[swiftTarget.name] = owningPackage.id + let skeletonURL: URL + let inputFileURL: URL + if owningPackage.id == context.package.id { + // Same package: skeleton lives in this plugin's work dir; track the generated + // BridgeJS.swift (an output of the dep's own invocation) for ordering. + skeletonURL = BridgeJSPluginPaths.skeletonURL( + targetName: swiftTarget.name, + packageID: context.package.id, + buildPluginWorkDirectoryURL: context.pluginWorkDirectoryURL + ) + inputFileURL = BridgeJSPluginPaths.bridgeJSSwiftURL( + targetName: swiftTarget.name, + packageID: context.package.id, + buildPluginWorkDirectoryURL: context.pluginWorkDirectoryURL + ) + } else { + // Cross package: read AND track the committed skeleton (a real on-disk file). + // No ordering edge needed — the dependency package is already built. + skeletonURL = BridgeJSPluginPaths.committedSkeletonURL( + targetDirectoryURL: swiftTarget.directoryURL + ) + inputFileURL = skeletonURL + } + skeletons.append(DependencySkeleton( + moduleName: swiftTarget.name, skeletonURL: skeletonURL, inputFileURL: inputFileURL + )) +} +return skeletons +``` + +> If a cross-package dependency lacks a committed skeleton, emit a clear diagnostic (mirror the command plugin's message at `BridgeJSCommandPlugin.swift:170`): "Dependency '' exposes `@JS` types across packages but has no committed Generated/JavaScript/BridgeJS.json. Run `swift package plugin bridge-js` in that package and commit the result." + +- [ ] **Step 3: Append the correct input file at the call site** + +At `BridgeJSBuildPlugin.swift:76`, replace `inputFiles.append(skeleton.bridgeJSSwiftURL)` with `inputFiles.append(skeleton.inputFileURL)`. The `--dependency-skeleton` argument keeps using `skeleton.skeletonURL.path` (`:69`). + +- [ ] **Step 4: Build to verify it compiles** + +Run: `swift build --package-path Plugins/BridgeJS` +Expected: builds. + +- [ ] **Step 5: Commit** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift +git commit -m "feat(bridge-js): discover dependency skeletons across packages with correct input tracking" +``` + +--- + +## Task 3: Verify the command (AoT) plugin crosses packages + +**Files:** +- Modify (if needed): `Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift:160-178` + +- [ ] **Step 1: Audit the AoT dependency walk** + +Read `:155-185`. It already builds `--dependency-skeleton =`. Confirm the loop iterates `recursiveTargetDependencies` (or the product graph) **including cross-package targets**, not only same-package ones. If it is restricted to `context.package`, apply the same generalization as Task 2 Step 1 (build a `target.id -> package` map and resolve `directoryURL`-based committed skeleton paths). + +- [ ] **Step 2: Ensure parity diagnostic** + +If a cross-package dependency lacks the committed skeleton, emit the same diagnostic wording as Task 2 Step 2 for a consistent developer experience. + +- [ ] **Step 3: Commit (if changed)** + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift +git commit -m "feat(bridge-js): discover dependency skeletons across packages (command plugin)" +``` + +--- + +## Task 4: Engine-level regression test for the cross-package shape + +**Files:** +- Modify: `Plugins/BridgeJS/Tests/BridgeJSToolTests/CrossModuleResolutionTests.swift` + +The resolver already supports this; this test locks the contract that a dependency skeleton loaded from another package resolves identically to a same-package one (the plugins only differ in *where they read the file from*). + +- [ ] **Step 1: Add a test asserting resolution is source-agnostic** + +```swift +@Test +func resolvesExternalTypeRegardlessOfSkeletonOrigin() throws { + // Same skeleton bytes a cross-package dependency would ship as committed BridgeJS.json. + let ui = try buildDependencySkeleton( + moduleName: "ElementaryUI", + source: """ + @JS public struct Color { + @JS public init(hex: String) { self.hex = hex } + public let hex: String + } + """ + ) + // Round-trip through JSON to simulate reading a committed skeleton file. + let encoded = try JSONEncoder().encode(ui) + let reloaded = try JSONDecoder().decode(BridgeJSSkeleton.self, from: encoded) + + let app = try resolveApp( + source: """ + import ElementaryUI + @JS public func brand() -> Color { Color(hex: "#000") } + """, + dependencies: [(moduleName: "ElementaryUI", skeleton: reloaded)] + ) + #expect(app.usedExternalModules == ["ElementaryUI"]) + let fn = try #require(app.exported?.functions.first(where: { $0.name == "brand" })) + #expect(fn.returnType == .swiftStruct("Color")) +} +``` + +> Use the existing `buildDependencySkeleton`/`resolveApp` helpers in this test file. If `BridgeJSSkeleton` isn't directly `Codable` at the top level, encode the value `buildDependencySkeleton` returns using the same encoder configuration the tool uses (`BridgeJSTool.swift:271-272`). + +- [ ] **Step 2: Run** + +Run: `swift test --package-path Plugins/BridgeJS --filter CrossModuleResolutionTests` +Expected: PASS. + +- [ ] **Step 3: Commit** + +```bash +git add Plugins/BridgeJS/Tests/BridgeJSToolTests/CrossModuleResolutionTests.swift +git commit -m "test(bridge-js): lock cross-package skeleton resolution parity" +``` + +--- + +## Task 5: Two-package integration fixture + +**Files:** +- Create: `Examples/CrossPackage/` (a library package + an app package depending on it) + +- [ ] **Step 1: Build the fixture** + +- Library package `ElementaryUIish` with a `@JS public struct` exported and committed `Generated/JavaScript/BridgeJS.json`. +- App package depending on it, with a `@JS public func` returning that struct. + +- [ ] **Step 2: Verify end-to-end** + +Run: +```bash +swift package --package-path Examples/CrossPackage/App --swift-sdk $SWIFT_SDK_ID js +``` +Expected: build succeeds; without Phase 3 the app build would fail to resolve the external type. Confirm the generated `bridge-js.d.ts` includes the composed surface. + +- [ ] **Step 3: Commit** + +```bash +git add Examples/CrossPackage +git commit -m "test(bridge-js): cross-package composition example" +``` + +--- + +## Task 6: Detect stale committed skeletons (drift guard for H2) + +**Files:** +- Modify: `Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift` (add an optional `inputHash` field) and `Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift` (compute + write it during `generate`) +- Add: a CI regenerate-check step (Makefile/CI script) and a docs note + +A dependency's committed `BridgeJS.json` can silently drift from its source. This task makes drift detectable. + +- [ ] **Step 1: Stamp the skeleton with an INPUT hash (write side) — must cover every input that affects the skeleton (M2)** + +Add an optional `public var inputHash: String?` to `BridgeJSSkeleton` (back-compatible: `decodeIfPresent`, omitted from old skeletons). In the `generate` subcommand, compute a stable hash over **all** inputs that can change `BridgeJS.json` — not just Swift sources. Hashing only Swift files would let a config-only edit silently stale the committed skeleton. Include: + +- **Swift source files** fed to `SwiftToSkeleton` (sorted by path; hash path + contents). +- **`bridge-js.config.json`** contents — `exposeToGlobal`, `identityMode`, etc. drive output (`BridgeJSTool.swift:132`, `:173-180`; `Misc.swift`). +- **TypeScript import inputs** — `bridge-js.d.ts` and `bridge-js.global.d.ts` (they generate `BridgeJS.Macros.swift`, which feeds the imported skeleton; `BridgeJSTool.swift:135-157, :164-173`). Hash the `.d.ts` contents (and/or the generated macro output). +- **Dependency skeleton identities** — the `moduleName` + each dependency's own `inputHash` (so a changed transitive dependency invalidates downstream). This makes the hash recursively sound. +- **A codegen/schema version constant** — bump it whenever the generator or skeleton schema changes, so a toolchain upgrade invalidates stale stamps even when inputs are unchanged. + +Compute as a sorted, delimited concatenation → SHA-256, set on the skeleton before writing `BridgeJS.json`. + +> Rationale anchors: config load/use at `BridgeJSTool.swift:132, :173-180`; d.ts→macros at `:135-157, :164-173`; dependency skeletons at `:125`. + +- [ ] **Step 2: Warn on drift (read side)** + +When a consumer's plugin loads a dependency's committed skeleton (Phase 3 Task 2/3), if the dependency target's *current* inputs are reachable in the build graph, recompute the `inputHash` (same input set as Step 1) and emit a **warning** (not an error — the dependency may be a prebuilt/binary distribution) when it differs from the committed `inputHash`: + +```text +"warning: dependency '' committed BridgeJS.json is stale (input hash mismatch). +Run `swift package plugin bridge-js` in that package and commit the result." +``` + +- [ ] **Step 3: Add a CI regenerate-check** + +Add a CI/Makefile target that runs `swift package plugin bridge-js` and fails if `git status --porcelain` shows changes under `Generated/` — guaranteeing committed skeletons are never stale in CI. Mirror any existing "generated code is up to date" check in the repo if present. + +- [ ] **Step 4: Tests + commit** + +Unit-test that (a) a changed Swift source, (b) a changed `bridge-js.config.json` (e.g. `exposeToGlobal` flip), and (c) a bumped codegen/schema version each produce a different `inputHash`; and assert the back-compat decode of a skeleton without `inputHash`. + +```bash +git add Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift Plugins/BridgeJS/Tests/BridgeJSToolTests Makefile +git commit -m "feat(bridge-js): stamp + drift-check committed skeletons for cross-package safety" +``` + +--- + +## Self-Review + +**Spec coverage:** cross-package type discovery + correct input tracking (Task 2 build plugin, Task 3 command plugin), path resolution (Task 1), resolution parity (Task 4), end-to-end (Task 5), stale-skeleton drift guard (Task 6). Runtime composition needs no change (already cross-package via `SkeletonCollector`). ✓ + +**Follow-up (F-series) fixes folded in:** +- **F2 (module-name uniqueness)** — discovery no longer silently dedupes by name; a duplicate module name from two different packages is a hard `Diagnostics.error` (BridgeJS keys import objects, snippets, and closure thunks by module name). Task 2 Step 2. + +**Second-review fixes folded in:** +- **H1 (cross-package input tracking)** — `DependencySkeleton` now carries a distinct `inputFileURL`: same-package deps track the generated `BridgeJS.swift` (ordering edge); cross-package deps track the **committed `BridgeJS.json` they actually read**. The call site at `BridgeJSBuildPlugin.swift:76` appends `inputFileURL`, not the bogus work-dir `bridgeJSSwiftURL`. Task 2 Steps 2–3. +- **M2 (incomplete drift hash)** — the stamp is renamed `inputHash` and now covers Swift sources **+** `bridge-js.config.json` **+** `bridge-js.d.ts`/`.global.d.ts` **+** dependency `inputHash`es **+** a codegen/schema version, so config-only or toolchain-only changes can't silently stale a committed skeleton. Task 6 Steps 1–2, 4. + +**Placeholder scan:** Task 3 is conditional ("if restricted, generalize") because the command plugin may already cross packages; Step 1 is an explicit audit with a concrete fallback referencing Task 2's code. Acceptable — it's a verify-then-apply task, not deferred design. + +**Type consistency:** `committedSkeletonURL(targetDirectoryURL:)`, `DependencySkeleton` (`moduleName`/`skeletonURL`/`inputFileURL`), `inputHash`, `packageByTargetID`, `usedExternalModules`, `resolveApp`, `buildDependencySkeleton` all reference existing or newly-defined symbols used consistently. The committed path is identical in Task 1 and the command-plugin read (`BridgeJSCommandPlugin.swift:165-166`). + +--- + +## Execution Handoff + +Subagent-Driven (recommended) or Inline. Execute Task 1→2 first, then audit Task 3, then the tests. diff --git a/docs/superpowers/plans/2026-06-17-bridgejs-phase4-per-target-modules.md b/docs/superpowers/plans/2026-06-17-bridgejs-phase4-per-target-modules.md new file mode 100644 index 000000000..01704c7c4 --- /dev/null +++ b/docs/superpowers/plans/2026-06-17-bridgejs-phase4-per-target-modules.md @@ -0,0 +1,188 @@ +# BridgeJS Per-Target Modules + Shared Runtime (Phase 4, OPTIONAL) Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. +> +> **STATUS: OPTIONAL / ARCHITECTURAL.** None of the three originally-identified problems require this phase — they ship on the existing single-link architecture via Phases 1–3. Pursue this only to gain per-target incremental rebuilds and a manual-wiring (Vite) loop. This plan is **staged with explicit design decisions and spikes**; it is intentionally not reduced to line-precise copy-paste code, because the work is a structural refactor of a 3,783-line file and the exact code falls out of the design tasks below. Each task still defines its interface, files, and acceptance test. +> +> **On "distribution" (precise wording — fixes overstatement M2):** this phase does *not* enable shipping a prebuilt JS module that composes across toolchain versions. Because the inter-module boundary is regenerated per codegen version, a consumer must have the dependency's **skeleton + snippets** present and **regenerate** the per-target JS. "Independent distribution" therefore means "ship skeleton + snippets, regenerate JS at app build" — not "ship prebuilt JS." (This is the deliberate consequence of not freezing a runtime ABI.) + +**Goal:** Generate per-target bridge modules (`bridge-js.js` per Swift target) that compose against a shared runtime helper, so targets rebuild incrementally and a manual-wiring (Vite) loop becomes possible — **while keeping the inter-module boundary an internal, codegen-version-stamped detail, NOT a frozen public ABI** (this is our one deliberate divergence from Yuta's design). Note: per-target JS is regenerated per codegen version (ship skeleton + snippets, regenerate JS), not shipped prebuilt across toolchain versions. + +**Architecture:** Split `BridgeJSLink` into (a) a shared runtime helper owning the per-instance `bjs` ABI state, and (b) per-target emission keyed on a `primary` skeleton with `dependencies` available for lookups only. The app build regenerates all per-target modules with a single codegen version, so no cross-version runtime ABI is ever frozen. Composition becomes a thin merge driven by `instantiate.js`. + +**Tech Stack:** Swift (BridgeJSLink, PackageToJS), JS runtime templates, Swift Testing + snapshot harness, Vitest for runtime behavior. + +--- + +## Context & guardrails + +**Verified anchors:** +- Shared per-instance state is isolated in one function: `generateVariableDeclarations()` — `BridgeJSLink.swift:329-358` (stacks, return scratch, decoders, `bjs`, `_exports`), referenced symbolically via `JSGlueVariableScope.reserved*`. +- The ABI builtins (`bjs[...] = function...`) are generated in `generateAddImports(...)` — `BridgeJSLink.swift:394+`. +- Emission currently iterates **all** skeletons: `collectLinkData()` (`:197, 268, 294`), `enumHelperAssignments` (`:1229`), `structHelperAssignments` (`:1245`), `renderSwiftClassWrappers` (`:1265`), `intrinsicRegistry.classNamespaces` (`:1212`). +- Current composition contract: `instantiate.js` imports `createInstantiator` from a single merged `bridge-js.js` and calls `addImports`/`setInstance`/`createExports` (`instantiate.js:18, 118, 146-181`). +- PackageToJS produces the single merged `bridge-js.js` in one `BridgeJSLink` pass — `PackageToJS.swift:597-617`. + +**Non-negotiable guardrails (the divergence):** +1. No `bridgeJSRuntimeRange`/semver ABI between independently-built modules. Per-target modules carry a **codegen version stamp**; the app build asserts all modules share one stamp and **regenerates** on mismatch. +2. The durable cross-version contract stays the **skeleton JSON schema**, versioned by its codec (extend the existing `addSkeletonFile` version handling at `BridgeJSLink.swift:43-59`). +3. Per-target modules must not read raw shared-runtime storage; they touch shared state only through a passed context object. + +--- + +## Spike findings (COMPLETED 2026-06-17) + +All three spikes were resolved by reading the code. **Verdict: the restructure is feasible with no fundamental blocker, but the dominant work is wider than the outer module split — see Spike C's "critical finding."** These findings update Tasks 2–3 below. + +### Spike A — Shared-state surface inventory ✅ + +Source of truth: `JSGlueVariableScope` (`JSGlueGen.swift:12-37`) + `generateVariableDeclarations()` (`BridgeJSLink.swift:329-358`). + +| `reserved*` symbol (JS name) | Classification | Notes | +|---|---|---| +| `swift`, `instance`, `memory` | **Runtime-owned** | Set in `setInstance` (`:1154-1155`). | +| `decodeString`, `setException` | **Runtime-owned** | Built in `setInstance` (`:1158-1175`). `decodeString` holds the **only** `sharedMemory` branch. | +| `textEncoder`, `textDecoder` | **Runtime-owned** | Module-scope read-only constants. | +| `strStack`, `i32Stack`, `i64Stack`, `f32Stack`, `f64Stack`, `ptrStack`, `taStack` | **Context (shared mutable)** | Pushed/popped by both the `bjs` builtins **and** per-target thunks (`JSGlueGen.swift:105-128`). | +| `tmpRetString`, `tmpRetBytes`, `tmpRetException`, `tmpRetOptional{Bool,Int,Float,Double,HeapObject}` | **Context (shared mutable)** | Side-channel return storage: written by `bjs` builtins, read by per-target thunks. | +| `enumHelpers`, `structHelpers` | **Context (shared, per-target-contributed)** | Each target registers + reads its own helpers. | +| `swiftClosureRegistry`, `makeClosure` | **Context (shared)** | Closure factory/registry used by per-target closure thunks. | +| `bjs`, `_exports` | **Context (shared)** | The ABI import namespace and the merged exports object. | + +**`sharedMemory`:** confirmed a single site — `BridgeJSLink.swift:1158` (the `setInstance` `decodeString` selection). It does **not** appear in any per-target thunk. Memory-mode handling moves cleanly into the runtime helper. + +### Spike B — Cross-target reference inventory ✅ + +**Purely primary (emit from the primary skeleton only):** +- Swift class wrappers — grouped by module (`renderSwiftClassWrappers :1265`). +- Closure `invoke`/`lower`/`make` functions — named `...__` (`:836, 843, 844`); collected per `unified` skeleton (`:762-766`). +- Struct/enum helper factories + assignments — per defining target. +- Imported-thunk `ImportObjectBuilder`s — per module. + +**Need `dependencies` as a lookup index during primary emission:** +- `intrinsicRegistry.classNamespaces` (`:1212`) — built from **all** skeletons' namespaced classes; a primary struct/enum helper may reference a class namespace defined in a dependency. → build from `primary + dependencies`. +- Parameter/return type rendering that references a type from another module → resolve via the dependency skeletons (the `ExternalModuleIndex` model already used at generate time). + +**Coordination wrinkles (new tasks/notes):** +- `bjs["swift_js_closure_unregister"]` is set as a no-op default (`:760`) then overridden when any module uses closures (`:828`). With separate per-target modules, the **runtime helper must own** the real implementation (or registration must be idempotent) — modules cannot each clobber it inconsistently. +- `intrinsicRegistry` helper factories: target-independent ones (closure registry/`makeClosure`) → **runtime helper**; type-specific ones (struct/enum helpers) → **per-target**. + +### Spike C — Composition shape ✅ (design validated; runnable PoC deferred) + +Current shape (`generateJavaScript :1056-1205`): `createInstantiator(options, swift)` is one closure holding all shared `let` state and returning `{ addImports, setInstance, createExports }`. The `bjs` builtins and every per-target thunk **close over that shared lexical scope** (e.g. `JSGlueGen.swift:122` emits a bare `strStack.pop()`). + +Proposed interface maps cleanly: + +| `createInstantiator` piece | Proposed home | +|---|---| +| shared `let` state (`generateVariableDeclarations`) | runtime helper `createModuleContext()` → the `context` object (stacks, `tmpRet*`, helpers, registry, `bjs`, `_exports`) | +| target-independent `bjs` builtins (push/pop/return/string) | runtime helper `createBridgeRuntime().addBuiltins(importObject, context)` | +| imported thunks + class wrappers + closure thunks (per module) | per-target `module.register(context, importObject, importsContext)` | +| `setInstance` (instance/memory/decodeString/setException; `sharedMemory @:1158`) | runtime helper `runtime.setInstance(instance)` sets `context` fields | +| `createExports` body (class defs, helper assignments, namespace init, property assignments) | per-target `module.createExports(context)` → merged via `Object.assign` | + +```ts +// runtime helper (bridge-js-runtime.js) +function createBridgeRuntime(swift, opts): { + createModuleContext(): BridgeModuleContext; // owns shared mutable ABI state + addBuiltins(importObject, context): void; // target-independent bjs.* + setInstance(instance): void; // sets context.instance/memory/decodeString/... +}; +// per-target module (Generated/JavaScript/bridge-js.js) +function createBridgeModule(): { + moduleName: string; + codegenVersion: string; // guardrail 1 stamp + register(context, importObject, importsContext): void; + createExports(context): Record; +}; +``` + +**CRITICAL FINDING (the real cost):** the heavy-lifting is **not** the outer structure — it's that per-target thunk/lowering codegen references shared state by **bare lexical name** (`strStack`, `tmpRetString`, `bjs`, `_exports`, …) via closure capture. For a thunk to live in a separate module, every such reference must go through the passed `context` (e.g. `context.strStack`) — or each `register`/`createExports` destructures the context at its top. This touches the lowering/lifting fragment generators in **`JSGlueGen.swift`** and `ImportedThunkBuilder`/`ImportObjectBuilder` pervasively. No blocker, but it is the dominant, wide edit — and exactly the internal (non-public, regenerable) contract our divergence relies on. **This is now the core of Task 3.** + +**Runnable two-module PoC: deferred.** It needs a build + sample wasm and only pays off if the restructure is greenlit. The design-level mapping above is sufficient to validate the architecture for the design discussion. When greenlit, build the PoC as Task 2.5 before committing the codegen rewrite. + +### Bottom line for the design discussion +The counter-proposal's thesis holds: per-target modules + shared runtime are achievable **without** a frozen public ABI. The cost is concentrated and predictable (context-threading through the lowering codegen), and it is exactly the surface our "regenerate per codegen version" stance keeps internal. Nothing here changes the recommendation; it sharpens the effort estimate (Task 3 is the big one). + +--- + +## Task 1: Introduce `BridgeJSLinkInput { primary; dependencies }` (no output change yet) + +**Files:** `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` + +- [ ] **Step 1: Add the input type and a `primary`-aware initializer** that defaults `primary = all, dependencies = []` so current callers are unchanged. +- [ ] **Step 2: Thread `primary` vs `all`** through `collectLinkData()` and the emission helpers per Spike B: emission loops iterate `primary`; lookup structures (`intrinsicRegistry.classNamespaces`, closure-signature collection, `ExternalModuleIndex`-style resolution) iterate `primary + dependencies`. +- [ ] **Step 3: Characterization test.** With `primary = all skeletons, dependencies = []`, assert `.link()` output is **byte-identical** to the pre-refactor snapshots. + +Run: `swift test --package-path Plugins/BridgeJS --filter BridgeJSLinkTests` +Expected: PASS with zero snapshot diffs (pure refactor). + +- [ ] **Step 4: Commit** — `refactor(bridge-js): introduce primary/dependencies link input (behavior-preserving)` + +--- + +## Task 2: Extract the shared runtime helper + +**Files:** `Plugins/BridgeJS/Sources/BridgeJSLink/` (new emitter for `bridge-js-runtime.js`), `Plugins/PackageToJS/Templates/` + +- [ ] **Step 1: Define the `BridgeModuleContext` shape** from Spike A's "Context (shared mutable)" rows — stacks (`strStack`/`i32Stack`/`i64Stack`/`f32Stack`/`f64Stack`/`ptrStack`/`taStack`), return scratch (`tmpRet*`), `enumHelpers`, `structHelpers`, `swiftClosureRegistry`, `makeClosure`, `bjs`, `_exports`, plus the runtime-owned `instance`/`memory`/`decodeString`/`setException` set later. This is the internal (regenerable, version-stamped) contract — not a public ABI. +- [ ] **Step 2: Emit `bridge-js-runtime.js`** exposing `createBridgeRuntime(swift, opts)` with `createModuleContext()` (allocates the context from Step 1), `addBuiltins(importObject, context)` (the target-independent `bjs.*` push/pop/return/string builtins from `generateAddImports`, now operating on `context.*`), and `setInstance(instance)` (sets `context.instance/memory/decodeString/setException`; the single `sharedMemory` branch from `:1158` lives here). Own the closure registry/`makeClosure` and the real `swift_js_closure_unregister` here (Spike B coordination wrinkle). +- [ ] **Step 3: Keep the legacy merged path working** by having the current `createInstantiator` build a context + delegate to the runtime helper internally (so existing `instantiate.js` keeps functioning during the transition). +- [ ] **Step 4: Vitest behavior test** — instantiate an existing example and assert exports behave identically (round-trip a string and a class method). +- [ ] **Step 5: Commit** — `refactor(bridge-js): extract shared bridge-js-runtime.js helper + context` + +--- + +## Task 3: Emit per-target modules from AoT + +**Files:** `Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift`, `Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift` + +> **This is the dominant task (Spike C critical finding).** The hard, pervasive work is rewriting the lowering/lifting codegen so per-target thunks reference shared state through the passed `context` instead of bare lexical names. + +- [ ] **Step 1: Thread `context` through the lowering primitives.** In `JSGlueGen.swift` (e.g. the bare `strStack.pop()` / `i32Stack.push(...)` at `:105-128`) and `ImportedThunkBuilder`/`ImportObjectBuilder`, route every `JSGlueVariableScope.reserved*` *Context* symbol (Spike A) through the context — either `context.strStack` references or a destructuring preamble (`const { strStack, tmpRetString, … } = context;`) at the top of each `register`/`createExports`. Add a unit test that a rendered thunk contains no bare shared-state identifier. +- [ ] **Step 2: Add a per-target emit entry** producing `Generated/JavaScript/bridge-js.js` for the `primary` skeleton (using `dependencies` for lookups), implementing the Spike C module interface (`createBridgeModule()` → `{ moduleName, codegenVersion, register, createExports }`), and writing a **codegen version stamp** (guardrail 1). +- [ ] **Step 3: Wire it into the `generate` subcommand** alongside the skeleton and the Phase-1 `.d.ts` (so a target emits skeleton + `.d.ts` + per-target `bridge-js.js` together). +- [ ] **Step 4: Snapshot per-target output** for a multi-target input; assert each target's module references only its own symbols + the shared `context`/runtime (never inlines a dependency's bridge code — guardrail 3). +- [ ] **Step 5: Commit** — `feat(bridge-js): emit per-target bridge modules from AoT` + +--- + +## Task 4: Compose per-target modules in PackageToJS + instantiate + +**Files:** `Plugins/PackageToJS/Sources/PackageToJS.swift`, `Plugins/PackageToJS/Templates/instantiate.js` + +- [ ] **Step 1: Replace the single-pass merge** (`PackageToJS.swift:597-617`) with collection of per-target modules (reuse the `SkeletonCollector` traversal to find each target's `bridge-js.js`) and a thin composition: `createBridgeRuntime` + `modules.map(register)` + `Object.assign(...modules.map(createExports))`. +- [ ] **Step 2: Version-stamp assertion** — PackageToJS verifies all collected modules share the codegen stamp; on mismatch it **regenerates**, per guardrail 1. No semver range, no compatibility matrix. **Regeneration target (F6):** dependency packages are read-only checkouts, so regenerated per-target modules are written to the **plugin work directory** (never into the checkout), and the composition step must prefer the work-dir regenerated module over the stale committed one (same shadowing model the build plugin already uses for same-package skeletons). Only if regeneration is impossible (no skeleton available) does it error with a "run bridge-js generate in " diagnostic. +- [ ] **Step 3: Keep a fallback** to the legacy single-link path behind a flag until parity is proven. +- [ ] **Step 4: End-to-end Vitest** on a multi-target example: identical observable behavior to the legacy path. +- [ ] **Step 5: Commit** — `feat(packagetojs): compose per-target bridge modules via shared runtime` + +--- + +## Task 5: Manual-wiring (Vite) ergonomics + +**Files:** docs + a `Examples/ViteManualWiring/` fixture + +- [ ] **Step 1: Document** importing per-target `bridge-js.js` + `bridge-js-runtime.js` directly in a Vite app, composing with the same thin merge PackageToJS uses. +- [ ] **Step 2: Fixture** proving a bundler resolves the per-target modules as plain ESM (no synthetic package names; subpath export or relative path). +- [ ] **Step 3: Commit** — `docs(bridge-js): manual-wiring composition guide + example` + +--- + +## Self-Review + +**Spec coverage:** primary/dependencies split (Task 1), shared runtime (Task 2), per-target emission (Task 3), thin composition + version stamping instead of frozen ABI (Task 4), manual-wiring (Task 5). Guardrails 1–3 are enforced in Tasks 3–4. ✓ + +**Follow-up (F-series) fix folded in:** F6 — stamp-mismatch regeneration writes to the **plugin work directory** (dependency checkouts are read-only) and composition prefers the regenerated module over the stale committed one. Task 4 Step 2. ✓ + +**Placeholder scan:** This plan intentionally specifies interfaces + acceptance tests rather than full code, and front-loads the uncertainty into Spikes A–C. That is appropriate for an architectural refactor and is explicitly flagged at the top; it is not hidden deferral. Before executing Tasks 1–4, the spikes must produce concrete outputs (state table, reference inventory, interface sketch + PoC). + +**Type consistency:** `BridgeJSLinkInput`, `createBridgeRuntime`, `createModuleContext`, `createBridgeModule`, `register`, `createExports`, and the codegen version stamp are named consistently across tasks and match the Spike C interface. + +**Relationship to Yuta's design:** Tasks 1–4 are the same structural moves Yuta proposes. The **only** divergence lives in Task 3 Step 1 and Task 4 Step 2 (codegen-version stamp + regenerate, instead of `bridgeJSRuntimeRange` semver) and guardrails 1–3. Everything else aligns. + +--- + +## Execution Handoff + +Do the spikes first. Then Subagent-Driven (recommended) per task with snapshot/Vitest parity gates between tasks. Keep the legacy path until Task 4 parity is proven. From 96479bd18ca8f0d64d62ea6aa0e8a650c85f9d1f Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 10 Aug 2026 15:32:57 +0200 Subject: [PATCH 2/6] BridgeJS: Tests and fixtures for generic imports --- .../BridgeJSCodegenTests.swift | 3 + .../BridgeJSToolTests/BridgeJSLinkTests.swift | 120 +++ .../CodegenTestSupport.swift | 51 + .../GenericCodecExpressionTests.swift | 41 + .../GenericExportDiagnosticsTests.swift | 65 ++ .../GenericImportDiagnosticsTests.swift | 214 ++++ .../GenericMethodOnlyModuleCodegenTests.swift | 39 + .../Inputs/MacroSwift/GenericImports.swift | 74 ++ .../BridgeJSCodegenTests/Alias.swift | 34 +- .../BridgeJSCodegenTests/AliasInClosure.swift | 32 +- .../BridgeJSCodegenTests/ArrayTypes.swift | 34 +- .../BridgeJSCodegenTests/Async.swift | 34 +- .../AsyncAssociatedValueEnum.swift | 32 +- .../ClassWithNestedTypes.swift | 33 +- .../DefaultParameters.swift | 34 +- .../DictionaryTypes.swift | 32 +- .../BridgeJSCodegenTests/DocComments.swift | 33 +- .../BridgeJSCodegenTests/EnumAlias.swift | 32 +- .../EnumAssociatedValue.swift | 42 +- .../EnumAssociatedValueImport.swift | 32 +- .../BridgeJSCodegenTests/EnumCase.swift | 35 +- .../BridgeJSCodegenTests/EnumCaseImport.swift | 32 +- .../EnumNamespace.Global.swift | 35 +- .../BridgeJSCodegenTests/EnumNamespace.swift | 35 +- .../BridgeJSCodegenTests/EnumRawType.swift | 43 +- .../BridgeJSCodegenTests/GenericImports.json | 669 +++++++++++++ .../BridgeJSCodegenTests/GenericImports.swift | 520 ++++++++++ .../ImportedTypeInExportedInterface.swift | 32 +- .../BridgeJSCodegenTests/JSNameOverride.swift | 33 +- .../BridgeJSCodegenTests/NestedType.swift | 33 +- .../BridgeJSCodegenTests/Protocol.swift | 35 +- .../StaticFunctions.Global.swift | 33 +- .../StaticFunctions.swift | 33 +- .../StaticProperties.Global.swift | 32 +- .../StaticProperties.swift | 32 +- .../StructWithNestedTypes.swift | 38 +- .../BridgeJSCodegenTests/SwiftClosure.swift | 36 +- .../BridgeJSCodegenTests/SwiftStruct.swift | 40 +- .../SwiftStructImports.swift | 32 +- .../BridgeJSCodegenTests/UnsafePointer.swift | 32 +- .../BridgeJSLinkTests/GenericImports.d.ts | 88 ++ .../BridgeJSLinkTests/GenericImports.js | 936 ++++++++++++++++++ .../Generated/BridgeJS.swift | 614 ++++++++++++ .../Generated/JavaScript/BridgeJS.json | 778 +++++++++++++++ .../ImportGenericAPIs.swift | 280 ++++++ Tests/prelude.mjs | 32 + 46 files changed, 5519 insertions(+), 30 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/CodegenTestSupport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericCodecExpressionTests.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericExportDiagnosticsTests.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js create mode 100644 Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index 60b2fd485..6d2f3d453 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -141,6 +141,9 @@ import Testing swiftParts.append(s) } } + if let typeRegistration = GenericTypeRegistrationCodegen().render(for: skeleton) { + swiftParts.append(typeRegistration) + } let combinedSwift = swiftParts .map { $0.trimmingCharacters(in: .newlines) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index 642debedc..23ffb3c6d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -139,6 +139,126 @@ import Testing try snapshot(bridgeJSLink: bridgeJSLink, name: "MixedModules") } + private func linkedJS(forFixture input: String) throws -> String { + let url = Self.inputsDirectory.appendingPathComponent(input) + let name = url.deletingPathExtension().lastPathComponent + let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) + let importSwift = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + importSwift.addSourceFile(sourceFile, inputFilePath: "\(name).swift") + let importResult = try importSwift.finalize() + var bridgeJSLink = BridgeJSLink(sharedMemory: false) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + let unifiedData = try encoder.encode(importResult) + try bridgeJSLink.addSkeletonFile(data: unifiedData) + return try bridgeJSLink.link().0 + } + + @Test + func genericRuntimeIsGatedToGenericBuilds() throws { + let genericJS = try linkedJS(forFixture: "GenericImports.swift") + #expect(genericJS.contains("__bjs_codecByTypeId")) + #expect(genericJS.contains("__bjs_primitiveCodecs")) + #expect(genericJS.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) + #expect(genericJS.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + // Eager registration hook: called by the instantiate.js template right + // after WASI initialization (the lazy guard remains as a fallback). + #expect(genericJS.contains("afterInitialize: () => {")) + + // Modules with @JS types but no generic declarations still emit a Swift + // registration export (their types may be used by a dependent module's + // generic function), so the link layer must install a no-op hook for the + // wasm import — but the generic runtime itself must be omitted. The + // shared codec runtime (combinators + primitive codecs) gates + // independently: it is emitted because the fixture bridges an optional + // struct through the container stack ABI. + let nonGenericJS = try linkedJS(forFixture: "SwiftStructImports.swift") + #expect(!nonGenericJS.contains("__bjs_codecByTypeId")) + #expect(nonGenericJS.contains("__bjs_optionalCodec(structHelpers.Point)")) + #expect(nonGenericJS.contains("__bjs_primitiveCodecs")) + #expect(nonGenericJS.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function() {};")) + #expect(!nonGenericJS.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + // Without the generic runtime the hook is not emitted at all; the + // instantiate template calls it with optional chaining. + #expect(!nonGenericJS.contains("afterInitialize: () => {")) + + // Builds that bridge no containers at all pay nothing for the shared + // codec runtime either. + let containerFreeJS = try linkedJS(forFixture: "PrimitiveParameters.swift") + #expect(!containerFreeJS.contains("__bjs_arrayCodec")) + #expect(!containerFreeJS.contains("__bjs_optionalCodec")) + #expect(!containerFreeJS.contains("__bjs_dictCodec")) + #expect(!containerFreeJS.contains("__bjs_primitiveCodecs")) + #expect(!containerFreeJS.contains("__bjs_stringCodec")) + } + + @Test + func sameTypeNameAcrossModulesLinksWithHandleIdentity() throws { + // Type identity is pointer-based (each type owns a BridgeJSTypeHandle), + // so two modules defining a same-named @JS type must link fine: each + // module registers its own handle IDs against its own codec array. + let structSource = """ + @JS public struct Point { + public var x: Int + @JS public init(x: Int) { self.x = x } + } + """ + let first = try makeSkeleton( + structSource + """ + + @JSFunction func identity(_ value: T) throws(JSException) -> T + """, + moduleName: "FirstModule" + ) + let second = try makeSkeleton(structSource, moduleName: "SecondModule") + let bridgeJSLink = BridgeJSLink(skeletons: [first, second], sharedMemory: false) + let js = try bridgeJSLink.link().outputJs + #expect(js.contains("bjs[\"bjs_FirstModule_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("bjs[\"bjs_SecondModule_register_type_handles\"] = function(base, count) {")) + } + + @Test + func moduleWithoutGenericsStillRegistersItsTypeCodecs() throws { + // A module cannot know whether a dependent module will pass its types to + // a generic function, so a module with @JS types but no generic + // declaration of its own still registers a codec for each of them, and + // the linked glue drives every module's registration export. This is + // what lets a type defined in Core be the generic argument of a generic + // import declared in App. + let core = try makeSkeleton( + """ + @JS public struct Vector3D { + public var x: Int + @JS public init(x: Int) { self.x = x } + } + """, + moduleName: "Core" + ) + let app = try makeSkeleton( + """ + @JSFunction func identity(_ value: T) throws(JSException) -> T + """, + moduleName: "App" + ) + + // Core declares nothing imported at all, yet still registers its types. + #expect(core.imported == nil) + let coreEntries = try #require(core.typeRegistrationEntries) + #expect(coreEntries.contains { $0.swiftName == "Vector3D" }) + + let js = try BridgeJSLink(skeletons: [core, app], sharedMemory: false).link().outputJs + #expect(js.contains("instance.exports[\"bjs_Core_register_type_handles\"]();")) + #expect(js.contains("instance.exports[\"bjs_App_register_type_handles\"]();")) + // `lower(v)` is unique to a codec literal in a registration array; + // `structHelpers.Vector3D` on its own is emitted for every @JS struct. + #expect(js.contains("structHelpers.Vector3D.lower(v);")) + } + @Test func perClassIdentityModeFromAnnotation() throws { let url = Self.inputsDirectory.appendingPathComponent("IdentityModeClass.swift") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/CodegenTestSupport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CodegenTestSupport.swift new file mode 100644 index 000000000..b855982b1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CodegenTestSupport.swift @@ -0,0 +1,51 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSLink +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +func makeSkeleton( + _ source: String, + moduleName: String = "TestModule", + dependencies: [(moduleName: String, skeleton: BridgeJSSkeleton)] = [] +) throws -> BridgeJSSkeleton { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: moduleName, + exposeToGlobal: false, + externalModuleIndex: ExternalModuleIndex(dependencies: dependencies) + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "\(moduleName).swift") + return try swiftAPI.finalize() +} + +func expectDiagnostic( + source: String, + moduleName: String = "App", + contains message: String, + sourceLocation: Testing.SourceLocation = #_sourceLocation +) { + do { + _ = try makeSkeleton(source, moduleName: moduleName) + Issue.record("Expected diagnostic but resolution succeeded", sourceLocation: sourceLocation) + } catch let error as BridgeJSCoreDiagnosticError { + let combined = error.diagnostics.map(\.diagnostic.message).joined(separator: "\n") + #expect(combined.contains(message), sourceLocation: sourceLocation) + } catch { + Issue.record("Unexpected error: \(error)", sourceLocation: sourceLocation) + } +} + +func linkSource(_ source: String, moduleName: String = "TestModule") throws -> (js: String, dts: String) { + let skeleton = try makeSkeleton(source, moduleName: moduleName) + var bridgeJSLink = BridgeJSLink(sharedMemory: false) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys] + let unifiedData = try encoder.encode(skeleton) + try bridgeJSLink.addSkeletonFile(data: unifiedData) + let result = try bridgeJSLink.link() + return (result.outputJs, result.outputDts) +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericCodecExpressionTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericCodecExpressionTests.swift new file mode 100644 index 000000000..d0666f89f --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericCodecExpressionTests.swift @@ -0,0 +1,41 @@ +import Testing + +@testable import BridgeJSLink +@testable import BridgeJSSkeleton + +/// The codec a generic call site instantiates for each supported wrapped form +/// of a generic parameter (`T`, `[T]`, `T?`, `[String: T]`). +@Suite struct GenericCodecExpressionTests { + @Test func bareGenericUsesTheElementCodecDirectly() { + #expect(GenericJSCodegen.genericCodecExpression(type: .generic("T"), codec: "c") == "c") + } + + @Test func wrappedGenericsInstantiateTheSharedCombinators() { + #expect( + GenericJSCodegen.genericCodecExpression(type: .array(.generic("T")), codec: "c") + == "__bjs_arrayCodec(c)" + ) + #expect( + GenericJSCodegen.genericCodecExpression(type: .dictionary(.generic("T")), codec: "c") + == "__bjs_dictCodec(c)" + ) + } + + /// The optional combinator carries the null-vs-undefined flavour in its + /// second argument, so the generic path must not drop `JSOptionalKind`. + @Test func optionalGenericPreservesTheOptionalKind() { + #expect( + GenericJSCodegen.genericCodecExpression(type: .nullable(.generic("T"), .null), codec: "c") + == "__bjs_optionalCodec(c)" + ) + #expect( + GenericJSCodegen.genericCodecExpression(type: .nullable(.generic("T"), .undefined), codec: "c") + == "__bjs_optionalCodec(c, true)" + ) + } + + @Test func nonGenericTypesHaveNoGenericCodec() { + #expect(GenericJSCodegen.genericCodecExpression(type: .string, codec: "c") == nil) + #expect(GenericJSCodegen.genericCodecExpression(type: .array(.integer(.int)), codec: "c") == nil) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericExportDiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericExportDiagnosticsTests.swift new file mode 100644 index 000000000..61e1e8a84 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericExportDiagnosticsTests.swift @@ -0,0 +1,65 @@ +import Testing + +@testable import BridgeJSCore + +@Suite struct GenericExportDiagnosticsTests { + + @Test + func genericExportedFunctionRejected() { + expectDiagnostic( + source: """ + @JS public func identity(_ value: T) -> T { value } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func genericMethodOnExportedClassRejected() { + expectDiagnostic( + source: """ + @JS final class Box { + @JS init() {} + @JS func wrap(_ value: T) -> T { value } + } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func genericMethodOnExportedStructRejected() { + expectDiagnostic( + source: """ + @JS struct Pair { + @JS init() {} + @JS func first(_ value: T) -> T { value } + } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func genericStaticMethodOnExportedEnumRejected() { + expectDiagnostic( + source: """ + @JS enum Factory { + case primary + @JS static func one(_ value: T) -> T { value } + } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } + + @Test + func unconstrainedGenericExportedFunctionRejected() { + expectDiagnostic( + source: """ + @JS public func identity(_ value: T) -> T { value } + """, + contains: "Generic parameters on exported @JS functions are not supported yet" + ) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift new file mode 100644 index 000000000..fc91eea7d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericImportDiagnosticsTests.swift @@ -0,0 +1,214 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +@Suite struct GenericImportDiagnosticsTests { + + @Test + func genericParameterRequiresBridgeableConstraint() { + expectDiagnostic( + source: """ + @JSFunction func identity(_ value: T) throws(JSException) -> T + """, + contains: "Generic parameter 'T' must be constrained to 'BridgedSwiftGenericBridgeable'" + ) + } + + @Test + func genericWhereClauseUnsupported() { + expectDiagnostic( + source: """ + @JSFunction func identity(_ value: T) throws(JSException) -> T where T: Sendable + """, + contains: "'where' clauses are not supported on @JSFunction" + ) + } + + @Test + func asyncGenericImportUnsupported() { + expectDiagnostic( + source: """ + @JSFunction func identityAsync(_ value: T) async throws(JSException) -> T + """, + contains: "Generic @JSFunction declarations cannot be 'async' yet." + ) + } + + @Test + func genericImportedMethodIsParsed() throws { + let skeleton = try makeSkeleton( + """ + @JSClass struct Box { + @JSFunction func member(_ value: T) throws(JSException) -> T + } + """, + moduleName: "App" + ) + let imported = try #require(skeleton.imported) + let types = imported.children.flatMap { $0.types } + let box = try #require(types.first { $0.name == "Box" }) + let method = try #require(box.methods.first { $0.name == "member" }) + #expect(method.genericParameters == ["T"]) + } + + @Test + func genericImportedConstructorIsParsed() throws { + let skeleton = try makeSkeleton( + """ + @JSClass struct Box { + @JSFunction init(_ value: T) throws(JSException) + } + """, + moduleName: "App" + ) + let imported = try #require(skeleton.imported) + let types = imported.children.flatMap { $0.types } + let box = try #require(types.first { $0.name == "Box" }) + let constructor = try #require(box.constructor) + #expect(constructor.genericParameters == ["T"]) + #expect(constructor.parameters.map(\.type) == [.generic("T")]) + } + + @Test + func genericImportedConstructorUnconstrainedParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: T) throws(JSException) + } + """, + contains: + "Generic parameter 'T' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with @JSFunction." + ) + } + + @Test + func genericImportedConstructorUnusedTypeParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: Int) throws(JSException) + } + """, + contains: + "The generic parameter 'T' must be used in a parameter of a generic @JSFunction initializer." + ) + } + + @Test + func genericImportedConstructorAsyncIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: T) async throws(JSException) + } + """, + contains: "Generic @JSFunction declarations cannot be 'async' yet." + ) + } + + @Test + func genericImportedConstructorUnsupportedWrapperFormIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction init(_ value: [[T]]) throws(JSException) + } + """, + contains: "may only be used as a bare type" + ) + } + + @Test(arguments: [ + ("[[T]]", "@JSFunction func f(_ v: [[T]]) throws(JSException)"), + ("[T?]", "@JSFunction func f(_ v: [T?]) throws(JSException)"), + ("T??", "@JSFunction func f(_ v: T??) throws(JSException)"), + ("[Int: T]", "@JSFunction func f(_ v: [Int: T]) throws(JSException)"), + ]) + func unsupportedGenericWrapperFormsInParameter(label: String, source: String) { + expectDiagnostic( + source: source, + contains: "may only be used as a bare type" + ) + } + + @Test(arguments: [ + ("[[T]]", "@JSFunction func f(_ v: T) throws(JSException) -> [[T]]"), + ("[T?]", "@JSFunction func f(_ v: T) throws(JSException) -> [T?]"), + ("T??", "@JSFunction func f(_ v: T) throws(JSException) -> T??"), + ("[Int: T]", "@JSFunction func f(_ v: T) throws(JSException) -> [Int: T]"), + ]) + func unsupportedGenericWrapperFormsInReturn(label: String, source: String) { + expectDiagnostic( + source: source, + contains: "may only be used as a bare type" + ) + } + + @Test + func genericImportedMethodAsyncIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction func member(_ value: T) async throws(JSException) -> T + } + """, + contains: "Generic @JSFunction declarations cannot be 'async' yet." + ) + } + + @Test + func genericImportedMethodUnconstrainedParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction func member(_ value: T) throws(JSException) -> T + } + """, + contains: + "Generic parameter 'T' must be constrained to 'BridgedSwiftGenericBridgeable' to be used with @JSFunction." + ) + } + + @Test + func genericImportedFunctionUnusedTypeParamIsRejected() { + expectDiagnostic( + source: """ + @JSFunction func unused() throws(JSException) -> Int + """, + contains: + "The generic parameter 'T' must be used in a parameter or return type of a generic @JSFunction declaration." + ) + } + + @Test + func genericImportedMethodUnusedTypeParamIsRejected() { + expectDiagnostic( + source: """ + @JSClass struct Box { + @JSFunction func member() throws(JSException) -> Int + } + """, + contains: + "The generic parameter 'T' must be used in a parameter or return type of a generic @JSFunction declaration." + ) + } + + @Test + func genericImportedReturnOnlyTypeParamIsAllowed() throws { + let skeleton = try makeSkeleton( + """ + @JSFunction func make() throws(JSException) -> T + """, + moduleName: "App" + ) + let imported = try #require(skeleton.imported) + let functions = imported.children.flatMap { $0.functions } + let function = try #require(functions.first { $0.name == "make" }) + #expect(function.genericParameters == ["T"]) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift new file mode 100644 index 000000000..7cb690678 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift @@ -0,0 +1,39 @@ +import Testing + +@Suite struct GenericMethodOnlyModuleCodegenTests { + @Test + func importMethodOnlyEmitsJSRuntimeInfrastructure() throws { + // A module with generic imports but no exported @JS types still needs a + // populated codec table for the primitives, so it registers them itself. + let js = try linkSource( + """ + @JSClass struct OnlyConsumer { + @JSFunction func identity(_ value: T) throws(JSException) -> T + } + """ + ).js + #expect(js.contains("const __bjs_codecByTypeId = new Map();")) + #expect(js.contains("function __bjs_codecForTypeId(typeId) {")) + #expect(js.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + } + + @Test + func importConstructorOnlyEmitsJSRuntimeInfrastructure() throws { + // A generic initializer alone must switch the generic runtime on: its + // thunk calls __bjs_codecForTypeId, so a module whose only generic + // declaration is an initializer would otherwise emit a call to a + // function that was never defined. + let js = try linkSource( + """ + @JSClass struct OnlyBoxed { + @JSFunction init(_ value: T) throws(JSException) + } + """ + ).js + #expect(js.contains("const __bjs_codecByTypeId = new Map();")) + #expect(js.contains("function __bjs_codecForTypeId(typeId) {")) + #expect(js.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift new file mode 100644 index 000000000..5fd3d0226 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/GenericImports.swift @@ -0,0 +1,74 @@ +@JS +struct GenericPoint { + var x: Int + var y: Int +} + +@JS enum GenericColor { + case red + case green +} + +@JS enum GenericMode: String { + case light + case dark +} + +@JS enum GenericTagged { + case number(value: Int) + case text(value: String) +} + +@JS final class GenericImportBox { + @JS var value: Int + @JS init(value: Int) { + self.value = value + } + @JS func get() -> Int { + value + } +} + +@JSFunction func genericRoundTrip(_ value: T) throws(JSException) -> T + +@JSFunction func genericParse(_ json: String) throws(JSException) -> T + +@JSFunction func importGenericCombine( + _ a: T, + _ b: U +) throws(JSException) -> U + +@JSFunction func importGenericCaseDistinct( + _ a: T, + _ b: t +) throws(JSException) -> T + +@JSFunction func importGenericArray(_ values: [T]) throws(JSException) -> [T] + +@JSFunction func importGenericOptional(_ value: T?) throws(JSException) -> T? + +@JSFunction func importGenericDictionary( + _ values: [String: T] +) throws(JSException) -> [String: T] + +// A generic parameter alongside another parameter that pushes onto the shared +// stacks: both are lowered in reverse declaration order. +@JSFunction func importGenericAfterOptionalArray( + _ values: [Int]?, + _ value: T +) throws(JSException) -> T + +@JSClass struct GenericPairFactory { + @JSFunction init( + _ tag: String, + _ first: T, + _ second: U + ) throws(JSException) +} + +@JSClass struct GenericConsumer { + @JSFunction init(_ value: T) throws(JSException) + @JSFunction func accept(_ value: T) throws(JSException) + @JSFunction func identity(_ value: T) throws(JSException) -> T + @JSFunction static func box(_ value: T) throws(JSException) -> T +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift index 42b97761c..7fc853579 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift @@ -406,4 +406,36 @@ func _$Surface_label_get(_ self: JSObject) throws(JSException) -> String { throw error } return String.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PolygonReference.bridgeJSTypeID, + TagReference.bridgeJSTypeID, + InnerTag.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift index b91db4857..9d9c40502 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift @@ -191,4 +191,34 @@ extension PolygonReference: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = PolygonReference.bridgeJSMakeTypeHandle() } -extension Polygon: _BridgedSwiftAlias, _BridgedSwiftStackType {} \ No newline at end of file +extension Polygon: _BridgedSwiftAlias, _BridgedSwiftStackType {} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PolygonReference.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift index cf5208f5d..af2ddb544 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift @@ -655,4 +655,36 @@ func _$importProcessBooleans(_ values: [Bool]) throws(JSException) -> [Bool] { throw error } return [Bool].bridgeJSLiftReturn() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Status.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift index e4efe4596..bb51829d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift @@ -725,4 +725,36 @@ func _$Promise_resolve_SD14AsyncDirectionO(_ promise: JSObject, _ value: [String let promiseValue = promise.bridgeJSLowerParameter() promise_resolve_TestModule_SD14AsyncDirectionO(promiseValue) if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + AsyncPoint.bridgeJSTypeID, + AsyncDirection.bridgeJSTypeID, + AsyncTheme.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift index 5e56f12ad..8ea2e5449 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift @@ -117,4 +117,34 @@ func _$Promise_resolve_Sq18AsyncPayloadResultO(_ promise: JSObject, _ value: Opt let promiseValue = promise.bridgeJSLowerParameter() promise_resolve_TestModule_Sq18AsyncPayloadResultO(promiseValue, valueIsSome, valueCaseId) if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + AsyncPayloadResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift index 62511b41c..b8736635d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift @@ -182,4 +182,35 @@ extension Account.Credentials: BridgedSwiftGenericBridgeable { extension Account.Role: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Account.Role.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Account.Credentials.bridgeJSTypeID, + Account.Role.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift index cca403b68..4f343476a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift @@ -648,4 +648,36 @@ extension MathOperations: BridgedSwiftGenericBridgeable { extension Status: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Status.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Config.bridgeJSTypeID, + MathOperations.bridgeJSTypeID, + Status.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift index d57ec170c..090e93eb0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift @@ -172,4 +172,34 @@ func _$importMirrorDictionary(_ values: [String: Double]) throws(JSException) -> throw error } return [String: Double].bridgeJSLiftReturn() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Counters.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift index 042771659..03dfba96a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift @@ -322,4 +322,35 @@ extension Point: BridgedSwiftGenericBridgeable { extension Color: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Color.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + Color.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift index 6db98303e..812ece23e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift @@ -55,4 +55,34 @@ extension ColorBox: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = ColorBox.bridgeJSMakeTypeHandle() } -extension Color: _BridgedSwiftAlias, _BridgedSwiftStackType {} \ No newline at end of file +extension Color: _BridgedSwiftAlias, _BridgedSwiftStackType {} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + ColorBox.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift index 0fa414bfe..875d6f601 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift @@ -675,4 +675,44 @@ extension AllTypesResult: BridgedSwiftGenericBridgeable { extension OptionalAllTypesResult: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = OptionalAllTypesResult.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ComplexResult.bridgeJSTypeID, + Utilities.Result.bridgeJSTypeID, + NetworkingResult.bridgeJSTypeID, + APIOptionalResult.bridgeJSTypeID, + Precision.bridgeJSTypeID, + CardinalDirection.bridgeJSTypeID, + TypedPayloadResult.bridgeJSTypeID, + AllTypesResult.bridgeJSTypeID, + OptionalAllTypesResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift index fcf201eb8..5e597d6ae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift @@ -113,4 +113,34 @@ func _$PayloadSignalControls_roundTripOptional(_ self: JSObject, _ signal: Optio throw error } return Optional.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PayloadSignal.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift index a3f1f62dd..c8ea2699f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift @@ -243,4 +243,37 @@ extension TSDirection: BridgedSwiftGenericBridgeable { extension PublicStatus: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = PublicStatus.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Status.bridgeJSTypeID, + TSDirection.bridgeJSTypeID, + PublicStatus.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift index adef86c78..9bab304a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift @@ -98,4 +98,34 @@ func _$SignalControls_current(_ self: JSObject) throws(JSException) -> Signal { throw error } return Signal.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Signal.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift index 9b2fda572..2801e1788 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift @@ -374,4 +374,37 @@ extension Configuration.Port: BridgedSwiftGenericBridgeable { extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Networking.API.Method.bridgeJSTypeID, + Configuration.LogLevel.bridgeJSTypeID, + Configuration.Port.bridgeJSTypeID, + Internal.SupportedMethod.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift index 9b2fda572..2801e1788 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift @@ -374,4 +374,37 @@ extension Configuration.Port: BridgedSwiftGenericBridgeable { extension Internal.SupportedMethod: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Internal.SupportedMethod.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Networking.API.Method.bridgeJSTypeID, + Configuration.LogLevel.bridgeJSTypeID, + Configuration.Port.bridgeJSTypeID, + Internal.SupportedMethod.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift index 72f481c2d..e91f1b231 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift @@ -538,4 +538,45 @@ func _$returnsFeatureFlag() throws(JSException) -> FeatureFlag { throw error } return FeatureFlag.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Theme.bridgeJSTypeID, + TSTheme.bridgeJSTypeID, + FeatureFlag.bridgeJSTypeID, + HttpStatus.bridgeJSTypeID, + TSHttpStatus.bridgeJSTypeID, + Priority.bridgeJSTypeID, + FileSize.bridgeJSTypeID, + UserId.bridgeJSTypeID, + TokenId.bridgeJSTypeID, + SessionId.bridgeJSTypeID, + Precision.bridgeJSTypeID, + Ratio.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json new file mode 100644 index 000000000..c7f3e98ae --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.json @@ -0,0 +1,669 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_GenericImportBox_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "isFinal" : true, + "methods" : [ + { + "abiName" : "bjs_GenericImportBox_get", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "get", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "GenericImportBox", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericImportBox" + } + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "red" + }, + { + "associatedValues" : [ + + ], + "name" : "green" + } + ], + "emitStyle" : "const", + "name" : "GenericColor", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericColor", + "tsFullPath" : "GenericColor" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "light" + }, + { + "associatedValues" : [ + + ], + "name" : "dark" + } + ], + "emitStyle" : "const", + "name" : "GenericMode", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericMode", + "tsFullPath" : "GenericMode" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "label" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "number" + }, + { + "associatedValues" : [ + { + "label" : "value", + "type" : { + "string" : { + + } + } + } + ], + "name" : "text" + } + ], + "emitStyle" : "const", + "name" : "GenericTagged", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericTagged", + "tsFullPath" : "GenericTagged" + } + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "methods" : [ + + ], + "name" : "GenericPoint", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "x", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "y", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericPoint" + } + ] + }, + "imported" : { + "children" : [ + { + "functions" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "genericRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "genericParse", + "parameters" : [ + { + "name" : "json", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T", + "U" + ], + "name" : "importGenericCombine", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "U" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "U" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T", + "t" + ], + "name" : "importGenericCaseDistinct", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "t" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericOptional", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericDictionary", + "parameters" : [ + { + "name" : "values", + "type" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "importGenericAfterOptionalArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "nullable" : { + "_0" : { + "array" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + }, + "_1" : "null" + } + } + }, + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "types" : [ + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "genericParameters" : [ + "T", + "U" + ], + "parameters" : [ + { + "name" : "tag", + "type" : { + "string" : { + + } + } + }, + { + "name" : "first", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "second", + "type" : { + "generic" : { + "_0" : "U" + } + } + } + ] + }, + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "GenericPairFactory", + "setters" : [ + + ], + "staticMethods" : [ + + ] + }, + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "genericParameters" : [ + "T" + ], + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ] + }, + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "accept", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "identity", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "name" : "GenericConsumer", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "box", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ] + } + ] + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift new file mode 100644 index 000000000..044fd0e57 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift @@ -0,0 +1,520 @@ +extension GenericColor: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> GenericColor { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> GenericColor { + return GenericColor(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .red + case 1: + self = .green + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .red: + return 0 + case .green: + return 1 + } + } +} + +extension GenericMode: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension GenericTagged: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> GenericTagged { + switch caseId { + case 0: + return .number(value: Int.bridgeJSStackPop()) + case 1: + return .text(value: String.bridgeJSStackPop()) + default: + fatalError("Unknown GenericTagged case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .number(let value): + value.bridgeJSStackPush() + return Int32(0) + case .text(let value): + value.bridgeJSStackPush() + return Int32(1) + } + } +} + +extension GenericPoint: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericPoint { + let y = Int.bridgeJSStackPop() + let x = Int.bridgeJSStackPop() + return GenericPoint(x: x, y: y) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.x.bridgeJSStackPush() + self.y.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_GenericPoint(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_GenericPoint())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_GenericPoint") +fileprivate func _bjs_struct_lower_GenericPoint_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_GenericPoint_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_GenericPoint(_ objectId: Int32) -> Void { + return _bjs_struct_lower_GenericPoint_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_GenericPoint") +fileprivate func _bjs_struct_lift_GenericPoint_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_GenericPoint_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_GenericPoint() -> Int32 { + return _bjs_struct_lift_GenericPoint_extern() +} + +@_expose(wasm, "bjs_GenericImportBox_init") +@_cdecl("bjs_GenericImportBox_init") +public func _bjs_GenericImportBox_init(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = GenericImportBox(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_get") +@_cdecl("bjs_GenericImportBox_get") +public func _bjs_GenericImportBox_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = GenericImportBox.bridgeJSLiftParameter(_self).get() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_value_get") +@_cdecl("bjs_GenericImportBox_value_get") +public func _bjs_GenericImportBox_value_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = GenericImportBox.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_value_set") +@_cdecl("bjs_GenericImportBox_value_set") +public func _bjs_GenericImportBox_value_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + GenericImportBox.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GenericImportBox_deinit") +@_cdecl("bjs_GenericImportBox_deinit") +public func _bjs_GenericImportBox_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension GenericImportBox: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_GenericImportBox_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_GenericImportBox_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericImportBox_wrap") +fileprivate func _bjs_GenericImportBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_GenericImportBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_GenericImportBox_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_GenericImportBox_wrap_extern(pointer) +} + +extension GenericPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericPoint.bridgeJSMakeTypeHandle() +} + +extension GenericImportBox: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericImportBox.bridgeJSMakeTypeHandle() +} + +extension GenericColor: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericColor.bridgeJSMakeTypeHandle() +} + +extension GenericMode: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericMode.bridgeJSMakeTypeHandle() +} + +extension GenericTagged: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericTagged.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_genericRoundTrip") +fileprivate func bjs_genericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_genericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_genericRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_genericRoundTrip_extern(_generic0TypeId) +} + +func _$genericRoundTrip(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_genericRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_genericParse") +fileprivate func bjs_genericParse_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_genericParse_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_genericParse(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_genericParse_extern(jsonBytes, jsonLength, _generic0TypeId) +} + +func _$genericParse(_ json: String) throws(JSException) -> T { + json.bridgeJSWithLoweredParameter { (jsonBytes, jsonLength) in + bjs_genericParse(jsonBytes, jsonLength, T.bridgeJSTypeID) + } + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericCombine") +fileprivate func bjs_importGenericCombine_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericCombine_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericCombine(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + return bjs_importGenericCombine_extern(_generic0TypeId, _generic1TypeId) +} + +func _$importGenericCombine(_ a: T, _ b: U) throws(JSException) -> U { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_importGenericCombine(T.bridgeJSTypeID, U.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return U.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericCaseDistinct") +fileprivate func bjs_importGenericCaseDistinct_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericCaseDistinct_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericCaseDistinct(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + return bjs_importGenericCaseDistinct_extern(_generic0TypeId, _generic1TypeId) +} + +func _$importGenericCaseDistinct(_ a: T, _ b: t) throws(JSException) -> T { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_importGenericCaseDistinct(T.bridgeJSTypeID, t.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericArray") +fileprivate func bjs_importGenericArray_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericArray_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericArray(_ _generic0TypeId: Int32) -> Void { + return bjs_importGenericArray_extern(_generic0TypeId) +} + +func _$importGenericArray(_ values: [T]) throws(JSException) -> [T] { + let _ = values.bridgeJSLowerParameter() + bjs_importGenericArray(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericOptional") +fileprivate func bjs_importGenericOptional_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericOptional_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericOptional(_ _generic0TypeId: Int32) -> Void { + return bjs_importGenericOptional_extern(_generic0TypeId) +} + +func _$importGenericOptional(_ value: Optional) throws(JSException) -> Optional { + value.bridgeJSStackPush() + bjs_importGenericOptional(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericDictionary") +fileprivate func bjs_importGenericDictionary_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericDictionary_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericDictionary(_ _generic0TypeId: Int32) -> Void { + return bjs_importGenericDictionary_extern(_generic0TypeId) +} + +func _$importGenericDictionary(_ values: [String: T]) throws(JSException) -> [String: T] { + let _ = values.bridgeJSLowerParameter() + bjs_importGenericDictionary(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [String: T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_importGenericAfterOptionalArray") +fileprivate func bjs_importGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_importGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_importGenericAfterOptionalArray(_ values: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_importGenericAfterOptionalArray_extern(values, _generic0TypeId) +} + +func _$importGenericAfterOptionalArray(_ values: Optional<[Int]>, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let valuesIsSome = values.bridgeJSLowerParameter() + bjs_importGenericAfterOptionalArray(valuesIsSome, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericPairFactory_init") +fileprivate func bjs_GenericPairFactory_init_extern(_ tagBytes: Int32, _ tagLength: Int32, _ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Int32 +#else +fileprivate func bjs_GenericPairFactory_init_extern(_ tagBytes: Int32, _ tagLength: Int32, _ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericPairFactory_init(_ tagBytes: Int32, _ tagLength: Int32, _ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Int32 { + return bjs_GenericPairFactory_init_extern(tagBytes, tagLength, _generic0TypeId, _generic1TypeId) +} + +func _$GenericPairFactory_init(_ tag: String, _ first: T, _ second: U) throws(JSException) -> JSObject { + let ret0 = tag.bridgeJSWithLoweredParameter { (tagBytes, tagLength) in + second.bridgeJSStackPush() + first.bridgeJSStackPush() + let ret = bjs_GenericPairFactory_init(tagBytes, tagLength, T.bridgeJSTypeID, U.bridgeJSTypeID) + return ret + } + let ret = ret0 + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_init") +fileprivate func bjs_GenericConsumer_init_extern(_ _generic0TypeId: Int32) -> Int32 +#else +fileprivate func bjs_GenericConsumer_init_extern(_ _generic0TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_init(_ _generic0TypeId: Int32) -> Int32 { + return bjs_GenericConsumer_init_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_box_static") +fileprivate func bjs_GenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_GenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_box_static(_ _generic0TypeId: Int32) -> Void { + return bjs_GenericConsumer_box_static_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_accept") +fileprivate func bjs_GenericConsumer_accept_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_GenericConsumer_accept_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_accept(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_GenericConsumer_accept_extern(self, _generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_GenericConsumer_identity") +fileprivate func bjs_GenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_GenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_GenericConsumer_identity(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_GenericConsumer_identity_extern(self, _generic0TypeId) +} + +func _$GenericConsumer_init(_ value: T) throws(JSException) -> JSObject { + value.bridgeJSStackPush() + let ret = bjs_GenericConsumer_init(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$GenericConsumer_box(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_GenericConsumer_box_static(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +func _$GenericConsumer_accept(_ self: JSObject, _ value: T) throws(JSException) -> Void { + value.bridgeJSStackPush() + let selfValue = self.bridgeJSLowerParameter() + bjs_GenericConsumer_accept(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$GenericConsumer_identity(_ self: JSObject, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let selfValue = self.bridgeJSLowerParameter() + bjs_GenericConsumer_identity(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + GenericPoint.bridgeJSTypeID, + GenericImportBox.bridgeJSTypeID, + GenericColor.bridgeJSTypeID, + GenericMode.bridgeJSTypeID, + GenericTagged.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift index 0e36253b7..dfec6b6a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift @@ -126,4 +126,34 @@ func _$Foo_init() throws(JSException) -> JSObject { throw error } return JSObject.bridgeJSLiftReturn(ret) -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + FooContainer.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift index 745843e34..5f767abdb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift @@ -356,4 +356,35 @@ extension RenamedVector: BridgedSwiftGenericBridgeable { extension RenamedEnumMembers: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = RenamedEnumMembers.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + RenamedVector.bridgeJSTypeID, + RenamedEnumMembers.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift index bc910951f..ca1c98a75 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift @@ -184,4 +184,35 @@ extension User.Stats: BridgedSwiftGenericBridgeable { extension Player.Stats: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Player.Stats.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + User.Stats.bridgeJSTypeID, + Player.Stats.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index a92716d44..2ef680b8a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -1059,4 +1059,37 @@ extension Result: BridgedSwiftGenericBridgeable { extension Priority: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Priority.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Direction.bridgeJSTypeID, + ExampleEnum.bridgeJSTypeID, + Result.bridgeJSTypeID, + Priority.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index 1f33a0b1d..18e91616c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -215,4 +215,35 @@ extension Calculator: BridgedSwiftGenericBridgeable { extension APIResult: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Calculator.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index 1f33a0b1d..18e91616c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -215,4 +215,35 @@ extension Calculator: BridgedSwiftGenericBridgeable { extension APIResult: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = APIResult.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Calculator.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift index 2c6aa9add..75c4382dd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift @@ -342,4 +342,34 @@ fileprivate func _bjs_PropertyClass_wrap_extern(_ pointer: UnsafeMutableRawPoint extension PropertyEnum: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = PropertyEnum.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PropertyEnum.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift index 2c6aa9add..75c4382dd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift @@ -342,4 +342,34 @@ fileprivate func _bjs_PropertyClass_wrap_extern(_ pointer: UnsafeMutableRawPoint extension PropertyEnum: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = PropertyEnum.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PropertyEnum.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift index b557b423f..1b8a69739 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift @@ -274,4 +274,40 @@ extension Widget.Variant: BridgedSwiftGenericBridgeable { extension Widget.Layout.Alignment: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Widget.Layout.Alignment.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Shape.bridgeJSTypeID, + Widget.bridgeJSTypeID, + Widget.Layout.bridgeJSTypeID, + Widget.Bounds.bridgeJSTypeID, + Shape.Kind.bridgeJSTypeID, + Widget.Variant.bridgeJSTypeID, + Widget.Layout.Alignment.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index cde864d3c..bad3ba0e1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -2740,4 +2740,38 @@ func _$Promise_resolve_9APIResultO(_ promise: JSObject, _ value: APIResult) thro let promiseValue = promise.bridgeJSLowerParameter() promise_resolve_TestModule_9APIResultO(promiseValue, valueCaseId) if let error = _swift_js_take_exception() { throw error } -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Animal.bridgeJSTypeID, + Direction.bridgeJSTypeID, + Theme.bridgeJSTypeID, + HttpStatus.bridgeJSTypeID, + APIResult.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 3414b158d..7aca6afd5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -666,4 +666,42 @@ extension Vector2D: BridgedSwiftGenericBridgeable { extension Precision: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Precision.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + DataPoint.bridgeJSTypeID, + Address.bridgeJSTypeID, + Person.bridgeJSTypeID, + Session.bridgeJSTypeID, + Measurement.bridgeJSTypeID, + ConfigStruct.bridgeJSTypeID, + Container.bridgeJSTypeID, + Vector2D.bridgeJSTypeID, + Precision.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift index 2eb0e70b7..a5c5d9fd8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift @@ -92,4 +92,34 @@ func _$roundTripOptional(_ point: Optional) throws(JSException) -> Option throw error } return Optional.bridgeJSLiftReturn() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + Point.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift index 93abd19e8..615608687 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift @@ -181,4 +181,34 @@ public func _bjs_roundTripPointerFields() -> Void { extension PointerFields: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = PointerFields.bridgeJSMakeTypeHandle() -} \ No newline at end of file +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + PointerFields.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts new file mode 100644 index 000000000..fc8b4b868 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.d.ts @@ -0,0 +1,88 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export const GenericColorValues: { + readonly Red: 0; + readonly Green: 1; +}; +export type GenericColorTag = typeof GenericColorValues[keyof typeof GenericColorValues]; + +export const GenericModeValues: { + readonly Light: "light"; + readonly Dark: "dark"; +}; +export type GenericModeTag = typeof GenericModeValues[keyof typeof GenericModeValues]; + +export const GenericTaggedValues: { + readonly Tag: { + readonly Number: 0; + readonly Text: 1; + }; +}; + +export type GenericTaggedTag = + { tag: typeof GenericTaggedValues.Tag.Number; value: number } | { tag: typeof GenericTaggedValues.Tag.Text; value: string } + +export interface GenericPoint { + x: number; + y: number; +} +export type GenericColorObject = typeof GenericColorValues; + +export type GenericModeObject = typeof GenericModeValues; + +export type GenericTaggedObject = typeof GenericTaggedValues; + +/// Represents a Swift heap object like a class instance or an actor instance. +export interface SwiftHeapObject { + /// Release the heap object. + /// + /// Note: Calling this method will release the heap object and it will no longer be accessible. + release(): void; +} +export interface GenericImportBox extends SwiftHeapObject { + get(): number; + value: number; +} +export interface GenericPairFactory { +} +export interface GenericConsumer { + accept(value: T): void; + identity(value: T): T; +} +export type Exports = { + GenericColor: GenericColorObject + GenericMode: GenericModeObject + GenericTagged: GenericTaggedObject + GenericImportBox: { + new(value: number): GenericImportBox; + }, +} +export type Imports = { + genericRoundTrip(value: T): T; + genericParse(json: string): T; + importGenericCombine(a: T, b: U): U; + importGenericCaseDistinct(a: T, b: t): T; + importGenericArray(values: T[]): T[]; + importGenericOptional(value: T | null): T | null; + importGenericDictionary(values: Record): Record; + importGenericAfterOptionalArray(values: number[] | null, value: T): T; + GenericPairFactory: { + new(tag: string, first: T, second: U): GenericPairFactory; + } + GenericConsumer: { + new(value: T): GenericConsumer; + box(value: T): T; + } +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + afterInitialize?: () => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js new file mode 100644 index 000000000..3ac1ea77e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -0,0 +1,936 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export const GenericColorValues = { + Red: 0, + Green: 1, +}; + +export const GenericModeValues = { + Light: "light", + Dark: "dark", +}; + +export const GenericTaggedValues = { + Tag: { + Number: 0, + Text: 1, + }, +}; +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + const __bjs_codecByTypeId = new Map(); + let __bjs_typeHandlesRegistered = false; + function __bjs_registerTypeHandles() { + if (__bjs_typeHandlesRegistered) { + return; + } + __bjs_typeHandlesRegistered = true; + instance.exports["bjs_TestModule_register_type_handles"](); + } + function __bjs_codecForTypeId(typeId) { + __bjs_registerTypeHandles(); + const codec = __bjs_codecByTypeId.get(typeId); + if (!codec) { + throw new Error("BridgeJS: no codec registered for type ID " + typeId); + } + return codec; + } + + let _exports = null; + let bjs = null; + function __bjs_arrayCodec(elementCodec) { + return { + lower(value) { + for (let i = 0; i < value.length; i++) { + elementCodec.lower(value[i]); + } + i32Stack.push(value.length); + }, + lift() { + const count = i32Stack.pop(); + if (count === -1) { + return taStack.pop(); + } + const result = new Array(count); + for (let i = count - 1; i >= 0; i--) { + result[i] = elementCodec.lift(); + } + return result; + }, + }; + } + function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { + return { + lower(value) { + const isSome = isUndefinedOr ? value !== undefined : value != null; + if (isSome) { + elementCodec.lower(value); + i32Stack.push(1); + } else { + i32Stack.push(0); + } + }, + lift() { + if (i32Stack.pop() === 0) { + return isUndefinedOr ? undefined : null; + } + return elementCodec.lift(); + }, + }; + } + function __bjs_dictCodec(valueCodec) { + return { + lower(value) { + const keys = Object.keys(value); + for (let i = 0; i < keys.length; i++) { + __bjs_stringCodec.lower(keys[i]); + valueCodec.lower(value[keys[i]]); + } + i32Stack.push(keys.length); + }, + lift() { + const count = i32Stack.pop(); + const result = {}; + for (let i = 0; i < count; i++) { + const value = valueCodec.lift(); + const key = __bjs_stringCodec.lift(); + result[key] = value; + } + return result; + }, + }; + } + function __bjs_enumCodec(helper) { + return { + lower(value) { + i32Stack.push(helper.lower(value)); + }, + lift() { + return helper.lift(i32Stack.pop()); + }, + }; + } + + const __bjs_stringCodec = { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return string; + }, + }; + const __bjs_primitiveCodecs = { + Bool: { + lower: (v) => { + i32Stack.push(v ? 1 : 0); + }, + lift: () => { + const bool = i32Stack.pop() !== 0; + return bool; + }, + }, + Int: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + Int8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt8: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt16: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return int; + }, + }, + UInt32: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + UInt: { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const int = i32Stack.pop() >>> 0; + return int; + }, + }, + Int64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + UInt64: { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const int = i64Stack.pop(); + return int; + }, + }, + Float: { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const f32 = f32Stack.pop(); + return f32; + }, + }, + Double: { + lower: (v) => { + f64Stack.push(v); + }, + lift: () => { + const f64 = f64Stack.pop(); + return f64; + }, + }, + String: __bjs_stringCodec, + JSValue: { + lower: (v) => { + const [vKind, vPayload1, vPayload2] = __bjs_jsValueLower(v); + i32Stack.push(vKind); + i32Stack.push(vPayload1); + f64Stack.push(vPayload2); + }, + lift: () => { + const jsValuePayload2 = f64Stack.pop(); + const jsValuePayload1 = i32Stack.pop(); + const jsValueKind = i32Stack.pop(); + const jsValue = __bjs_jsValueLift(jsValueKind, jsValuePayload1, jsValuePayload2); + return jsValue; + }, + }, + }; + + function __bjs_jsValueLower(value) { + let kind; + let payload1; + let payload2; + if (value === null) { + kind = 4; + payload1 = 0; + payload2 = 0; + } else { + switch (typeof value) { + case "boolean": + kind = 0; + payload1 = value ? 1 : 0; + payload2 = 0; + break; + case "number": + kind = 2; + payload1 = 0; + payload2 = value; + break; + case "string": + kind = 1; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "undefined": + kind = 5; + payload1 = 0; + payload2 = 0; + break; + case "object": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "function": + kind = 3; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "symbol": + kind = 7; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + case "bigint": + kind = 8; + payload1 = swift.memory.retain(value); + payload2 = 0; + break; + default: + throw new TypeError("Unsupported JSValue type"); + } + } + return [kind, payload1, payload2]; + } + function __bjs_jsValueLift(kind, payload1, payload2) { + let jsValue; + switch (kind) { + case 0: + jsValue = payload1 !== 0; + break; + case 1: + jsValue = swift.memory.getObject(payload1); + break; + case 2: + jsValue = payload2; + break; + case 3: + jsValue = swift.memory.getObject(payload1); + break; + case 4: + jsValue = null; + break; + case 5: + jsValue = undefined; + break; + case 7: + jsValue = swift.memory.getObject(payload1); + break; + case 8: + jsValue = swift.memory.getObject(payload1); + break; + default: + throw new TypeError("Unsupported JSValue kind " + kind); + } + return jsValue; + } + + const __bjs_createGenericPointHelpers = () => ({ + lower: (value) => { + i32Stack.push((value.x | 0)); + i32Stack.push((value.y | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + const int1 = i32Stack.pop(); + return { x: int1, y: int }; + } + }); + const __bjs_createGenericTaggedValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case GenericTaggedValues.Tag.Number: { + i32Stack.push((value.value | 0)); + return GenericTaggedValues.Tag.Number; + } + case GenericTaggedValues.Tag.Text: { + const bytes = textEncoder.encode(value.value); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return GenericTaggedValues.Tag.Text; + } + default: throw new Error("Unknown GenericTaggedValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case GenericTaggedValues.Tag.Number: { + const int = i32Stack.pop(); + return { tag: GenericTaggedValues.Tag.Number, value: int }; + } + case GenericTaggedValues.Tag.Text: { + const string = strStack.pop(); + return { tag: GenericTaggedValues.Tag.Text, value: string }; + } + default: throw new Error("Unknown GenericTaggedValues tag returned from Swift: " + String(tag)); + } + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + const imports = options.getImports(importsContext); + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr >>> 0); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + return swift.memory.retain(decodeString(ptr, len)); + } + bjs["swift_js_init_memory_with_result"] = function(ptr, len) { + const target = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); + target.set(tmpRetBytes); + tmpRetBytes = undefined; + } + bjs["swift_js_throw"] = function(id) { + tmpRetException = swift.memory.retainByRef(id); + } + bjs["swift_js_retain"] = function(id) { + return swift.memory.retainByRef(id); + } + bjs["swift_js_release"] = function(id) { + swift.memory.release(id); + } + bjs["swift_js_push_i32"] = function(v) { + i32Stack.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + f32Stack.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + f64Stack.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const value = decodeString(ptr, len); + strStack.push(value); + } + bjs["swift_js_pop_i32"] = function() { + return i32Stack.pop(); + } + bjs["swift_js_pop_f32"] = function() { + return f32Stack.pop(); + } + bjs["swift_js_pop_f64"] = function() { + return f64Stack.pop(); + } + bjs["swift_js_push_pointer"] = function(pointer) { + ptrStack.push(pointer); + } + bjs["swift_js_pop_pointer"] = function() { + return ptrStack.pop(); + } + bjs["swift_js_push_i64"] = function(v) { + i64Stack.push(v); + } + bjs["swift_js_pop_i64"] = function() { + return i64Stack.pop(); + } + const taCtors = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; + bjs["swift_js_push_typed_array"] = function(kind, ptr, count) { + const Ctor = taCtors[kind]; + const byteLen = count * Ctor.BYTES_PER_ELEMENT; + const copy = memory.buffer.slice(ptr, ptr + byteLen); + taStack.push(Array.from(new Ctor(copy))); + } + bjs["swift_js_struct_lower_GenericPoint"] = function(objectId) { + structHelpers.GenericPoint.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_GenericPoint"] = function() { + const value = structHelpers.GenericPoint.lift(); + return swift.memory.retain(value); + } + bjs["bjs_TestModule_register_type_handles"] = function(base, count) { + const codecs = [ + __bjs_primitiveCodecs.Bool, + __bjs_primitiveCodecs.Int, + __bjs_primitiveCodecs.Int8, + __bjs_primitiveCodecs.UInt8, + __bjs_primitiveCodecs.Int16, + __bjs_primitiveCodecs.UInt16, + __bjs_primitiveCodecs.Int32, + __bjs_primitiveCodecs.UInt32, + __bjs_primitiveCodecs.UInt, + __bjs_primitiveCodecs.Int64, + __bjs_primitiveCodecs.UInt64, + __bjs_primitiveCodecs.Float, + __bjs_primitiveCodecs.Double, + __bjs_primitiveCodecs.String, + __bjs_primitiveCodecs.JSValue, + ].concat([ + { + lower: (v) => { + structHelpers.GenericPoint.lower(v); + }, + lift: () => { + const struct = structHelpers.GenericPoint.lift(); + return struct; + }, + }, + { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['GenericImportBox'].__construct(ptr); + return obj; + }, + }, + { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }, + { + lower: (v) => { + const bytes = textEncoder.encode(v); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const rawValue = strStack.pop(); + return rawValue; + }, + }, + { + lower: (v) => { + const caseId = enumHelpers.GenericTagged.lower(v); + i32Stack.push(caseId); + }, + lift: () => { + const enumValue = enumHelpers.GenericTagged.lift(i32Stack.pop()); + return enumValue; + }, + }, + ]); + if (count !== codecs.length) { + throw new Error("BridgeJS: type handle registration mismatch for module 'TestModule'"); + } + const typeIds = new Int32Array(memory.buffer, base >>> 0, count >>> 0); + for (let i = 0; i < count; i++) { + __bjs_codecByTypeId.set(typeIds[i], codecs[i]); + } + } + const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); + bjs["swift_js_make_promise"] = function() { + let resolve, reject; + const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); + promise[__bjs_promiseSettlers] = { resolve, reject }; + return swift.memory.retain(promise); + } + bjs["swift_js_return_optional_bool"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalBool = null; + } else { + tmpRetOptionalBool = value !== 0; + } + } + bjs["swift_js_return_optional_int"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalInt = null; + } else { + tmpRetOptionalInt = value | 0; + } + } + bjs["swift_js_return_optional_float"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalFloat = null; + } else { + tmpRetOptionalFloat = Math.fround(value); + } + } + bjs["swift_js_return_optional_double"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalDouble = null; + } else { + tmpRetOptionalDouble = value; + } + } + bjs["swift_js_return_optional_string"] = function(isSome, ptr, len) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = decodeString(ptr, len); + } + } + bjs["swift_js_return_optional_object"] = function(isSome, objectId) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = swift.memory.getObject(objectId); + } + } + bjs["swift_js_return_optional_heap_object"] = function(isSome, pointer) { + if (isSome === 0) { + tmpRetOptionalHeapObject = null; + } else { + tmpRetOptionalHeapObject = pointer; + } + } + bjs["swift_js_get_optional_int_presence"] = function() { + return tmpRetOptionalInt != null ? 1 : 0; + } + bjs["swift_js_get_optional_int_value"] = function() { + const value = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return value; + } + bjs["swift_js_get_optional_string"] = function() { + const str = tmpRetString; + tmpRetString = undefined; + if (str == null) { + return -1; + } else { + const bytes = textEncoder.encode(str); + tmpRetBytes = bytes; + return bytes.length; + } + } + bjs["swift_js_get_optional_float_presence"] = function() { + return tmpRetOptionalFloat != null ? 1 : 0; + } + bjs["swift_js_get_optional_float_value"] = function() { + const value = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; + return value; + } + bjs["swift_js_get_optional_double_presence"] = function() { + return tmpRetOptionalDouble != null ? 1 : 0; + } + bjs["swift_js_get_optional_double_value"] = function() { + const value = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; + return value; + } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } + bjs["swift_js_closure_unregister"] = function(funcRef) {} + // Wrapper functions for module: TestModule + if (!importObject["TestModule"]) { + importObject["TestModule"] = {}; + } + importObject["TestModule"]["bjs_GenericImportBox_wrap"] = function(pointer) { + const obj = _exports['GenericImportBox'].__construct(pointer); + return swift.memory.retain(obj); + }; + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_genericRoundTrip"] = function bjs_genericRoundTrip(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = imports.genericRoundTrip(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_genericParse"] = function bjs_genericParse(jsonBytes, jsonCount, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const string = decodeString(jsonBytes, jsonCount); + let ret = imports.genericParse(string); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericCombine"] = function bjs_importGenericCombine(tTypeId, uTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const codecU = __bjs_codecForTypeId(uTypeId); + const a = codecT.lift(); + const b = codecU.lift(); + let ret = imports.importGenericCombine(a, b); + codecU.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericCaseDistinct"] = function bjs_importGenericCaseDistinct(tTypeId, tTypeId1) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const codect = __bjs_codecForTypeId(tTypeId1); + const a = codecT.lift(); + const b = codect.lift(); + let ret = imports.importGenericCaseDistinct(a, b); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericArray"] = function bjs_importGenericArray(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const values = __bjs_arrayCodec(codecT).lift(); + let ret = imports.importGenericArray(values); + __bjs_arrayCodec(codecT).lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericOptional"] = function bjs_importGenericOptional(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = __bjs_optionalCodec(codecT).lift(); + let ret = imports.importGenericOptional(value); + __bjs_optionalCodec(codecT).lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericDictionary"] = function bjs_importGenericDictionary(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const values = __bjs_dictCodec(codecT).lift(); + let ret = imports.importGenericDictionary(values); + __bjs_dictCodec(codecT).lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_importGenericAfterOptionalArray"] = function bjs_importGenericAfterOptionalArray(values, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + let optResult; + if (values) { + const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + optResult = arrayResult; + } else { + optResult = null; + } + const value = codecT.lift(); + let ret = imports.importGenericAfterOptionalArray(optResult, value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_GenericPairFactory_init"] = function bjs_GenericPairFactory_init(tagBytes, tagCount, tTypeId, uTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const codecU = __bjs_codecForTypeId(uTypeId); + const string = decodeString(tagBytes, tagCount); + const first = codecT.lift(); + const second = codecU.lift(); + return swift.memory.retain(new imports.GenericPairFactory(string, first, second)); + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_GenericConsumer_init"] = function bjs_GenericConsumer_init(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + return swift.memory.retain(new imports.GenericConsumer(value)); + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_GenericConsumer_box_static"] = function bjs_GenericConsumer_box_static(tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = imports.GenericConsumer.box(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + TestModule["bjs_GenericConsumer_accept"] = function bjs_GenericConsumer_accept(self, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + swift.memory.getObject(self).accept(value); + } catch (error) { + setException(error); + } + } + TestModule["bjs_GenericConsumer_identity"] = function bjs_GenericConsumer_identity(self, tTypeId) { + try { + const codecT = __bjs_codecForTypeId(tTypeId); + const value = codecT.lift(); + let ret = swift.memory.getObject(self).identity(value); + codecT.lower(ret); + } catch (error) { + setException(error); + } + } + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + decodeString = (ptr, len) => { const bytes = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); return textDecoder.decode(bytes); } + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + afterInitialize: () => { + __bjs_registerTypeHandles(); + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.hasReleased) { + return; + } + state.hasReleased = true; + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + }); + + /// Represents a Swift heap object like a class instance or an actor instance. + class SwiftHeapObject { + static __wrap(pointer, deinit, prototype, identityCache) { + pointer = pointer >>> 0; + const makeFresh = (identityMap) => { + const obj = Object.create(prototype); + const state = { pointer, deinit, hasReleased: false, identityMap }; + obj.pointer = pointer; + obj.__swiftHeapObjectState = state; + swiftHeapObjectFinalizationRegistry.register(obj, state, state); + if (identityMap) { + identityMap.set(pointer, new WeakRef(obj)); + } + return obj; + }; + + if (!identityCache) { + return makeFresh(null); + } + + const cached = identityCache.get(pointer)?.deref(); + if (cached && !cached.__swiftHeapObjectState.hasReleased) { + deinit(pointer); + return cached; + } + if (identityCache.has(pointer)) { + identityCache.delete(pointer); + } + + return makeFresh(identityCache); + } + + release() { + const state = this.__swiftHeapObjectState; + if (state.hasReleased) { + return; + } + state.hasReleased = true; + swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + } + } + class GenericImportBox extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_GenericImportBox_deinit, GenericImportBox.prototype, null); + } + + constructor(value) { + const ret = instance.exports.bjs_GenericImportBox_init(value); + return GenericImportBox.__construct(ret); + } + get() { + const ret = instance.exports.bjs_GenericImportBox_get(this.pointer); + return ret; + } + get value() { + const ret = instance.exports.bjs_GenericImportBox_value_get(this.pointer); + return ret; + } + set value(value) { + instance.exports.bjs_GenericImportBox_value_set(this.pointer, value); + } + } + const GenericPointHelpers = __bjs_createGenericPointHelpers(); + structHelpers.GenericPoint = GenericPointHelpers; + + const GenericTaggedHelpers = __bjs_createGenericTaggedValuesHelpers(); + enumHelpers.GenericTagged = GenericTaggedHelpers; + + const exports = { + GenericColor: GenericColorValues, + GenericMode: GenericModeValues, + GenericTagged: GenericTaggedValues, + GenericImportBox, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 156f044d2..9c7cc6d2a 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -5991,6 +5991,75 @@ extension ImportedPayloadSignal: _BridgedSwiftAssociatedValueEnum { } } +extension GenericRTColor: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> GenericRTColor { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> GenericRTColor { + return GenericRTColor(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .red + case 1: + self = .green + case 2: + self = .blue + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .red: + return 0 + case .green: + return 1 + case .blue: + return 2 + } + } +} + +extension GenericRTMode: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension GenericRTLevel: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension GenericRTOutcome: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> GenericRTOutcome { + switch caseId { + case 0: + return .ok(code: Int.bridgeJSStackPop()) + case 1: + return .fail(message: String.bridgeJSStackPop()) + default: + fatalError("Unknown GenericRTOutcome case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .ok(let code): + code.bridgeJSStackPush() + return Int32(0) + case .fail(let message): + message.bridgeJSStackPush() + return Int32(1) + } + } +} + @_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt") @_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt") public func _bjs_IntegerTypesSupportExports_static_roundTripInt(_ v: Int32) -> Int32 { @@ -6779,6 +6848,102 @@ public func _bjs_NestedTypeHost_Label_static_untitled() -> Void { #endif } +extension GenericRTPoint: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericRTPoint { + let y = Int.bridgeJSStackPop() + let x = Int.bridgeJSStackPop() + return GenericRTPoint(x: x, y: y) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.x.bridgeJSStackPush() + self.y.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_GenericRTPoint(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_GenericRTPoint())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_GenericRTPoint") +fileprivate func _bjs_struct_lower_GenericRTPoint_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_GenericRTPoint_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_GenericRTPoint(_ objectId: Int32) -> Void { + return _bjs_struct_lower_GenericRTPoint_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_GenericRTPoint") +fileprivate func _bjs_struct_lift_GenericRTPoint_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_GenericRTPoint_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_GenericRTPoint() -> Int32 { + return _bjs_struct_lift_GenericRTPoint_extern() +} + +extension GenericRTNamespace.Metadata: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericRTNamespace.Metadata { + let count = Int.bridgeJSStackPop() + let label = String.bridgeJSStackPop() + return GenericRTNamespace.Metadata(label: label, count: count) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.label.bridgeJSStackPush() + self.count.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_GenericRTNamespace_Metadata(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_GenericRTNamespace_Metadata())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_GenericRTNamespace_Metadata") +fileprivate func _bjs_struct_lower_GenericRTNamespace_Metadata_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_GenericRTNamespace_Metadata_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_GenericRTNamespace_Metadata(_ objectId: Int32) -> Void { + return _bjs_struct_lower_GenericRTNamespace_Metadata_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_GenericRTNamespace_Metadata") +fileprivate func _bjs_struct_lift_GenericRTNamespace_Metadata_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_GenericRTNamespace_Metadata_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_GenericRTNamespace_Metadata() -> Int32 { + return _bjs_struct_lift_GenericRTNamespace_Metadata_extern() +} + extension Point: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Point { let y = Int.bridgeJSStackPop() @@ -13206,6 +13371,80 @@ fileprivate func _bjs_NestedTypeHost_wrap_extern(_ pointer: UnsafeMutableRawPoin return _bjs_NestedTypeHost_wrap_extern(pointer) } +@_expose(wasm, "bjs_ImportGenericBox_init") +@_cdecl("bjs_ImportGenericBox_init") +public func _bjs_ImportGenericBox_init(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ImportGenericBox(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_get") +@_cdecl("bjs_ImportGenericBox_get") +public func _bjs_ImportGenericBox_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = ImportGenericBox.bridgeJSLiftParameter(_self).get() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_value_get") +@_cdecl("bjs_ImportGenericBox_value_get") +public func _bjs_ImportGenericBox_value_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = ImportGenericBox.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_value_set") +@_cdecl("bjs_ImportGenericBox_value_set") +public func _bjs_ImportGenericBox_value_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + ImportGenericBox.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ImportGenericBox_deinit") +@_cdecl("bjs_ImportGenericBox_deinit") +public func _bjs_ImportGenericBox_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension ImportGenericBox: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_ImportGenericBox_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ImportGenericBox_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericBox_wrap") +fileprivate func _bjs_ImportGenericBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_ImportGenericBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_ImportGenericBox_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_ImportGenericBox_wrap_extern(pointer) +} + @_expose(wasm, "bjs_JSNameRenamedClass_init") @_cdecl("bjs_JSNameRenamedClass_init") public func _bjs_JSNameRenamedClass_init(_ value: Int32) -> UnsafeMutableRawPointer { @@ -13624,6 +13863,14 @@ extension NestedTypeHost.Label: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedTypeHost.Label.bridgeJSMakeTypeHandle() } +extension GenericRTPoint: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTPoint.bridgeJSMakeTypeHandle() +} + +extension GenericRTNamespace.Metadata: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTNamespace.Metadata.bridgeJSMakeTypeHandle() +} + extension Point: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Point.bridgeJSMakeTypeHandle() } @@ -13720,6 +13967,10 @@ extension PriorityReference: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = PriorityReference.bridgeJSMakeTypeHandle() } +extension ImportGenericBox: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = ImportGenericBox.bridgeJSMakeTypeHandle() +} + extension Severity: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Severity.bridgeJSMakeTypeHandle() } @@ -13840,6 +14091,22 @@ extension ImportedPayloadSignal: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = ImportedPayloadSignal.bridgeJSMakeTypeHandle() } +extension GenericRTColor: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTColor.bridgeJSMakeTypeHandle() +} + +extension GenericRTMode: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTMode.bridgeJSMakeTypeHandle() +} + +extension GenericRTLevel: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTLevel.bridgeJSMakeTypeHandle() +} + +extension GenericRTOutcome: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTOutcome.bridgeJSMakeTypeHandle() +} + extension OptionalAllTypesResult: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = OptionalAllTypesResult.bridgeJSMakeTypeHandle() } @@ -17057,6 +17324,346 @@ func _$jsJoinStringThenStackParams(_ s: String, _ a: Optional<[Int]>, _ b: [Int] return String.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericRoundTrip") +fileprivate func bjs_jsGenericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericRoundTrip(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_jsGenericRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericRoundTripClass") +fileprivate func bjs_jsGenericRoundTripClass_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericRoundTripClass_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericRoundTripClass(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericRoundTripClass_extern(_generic0TypeId) +} + +func _$jsGenericRoundTripClass(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_jsGenericRoundTripClass(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericParsePoint") +fileprivate func bjs_jsGenericParsePoint_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericParsePoint_extern(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericParsePoint(_ jsonBytes: Int32, _ jsonLength: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericParsePoint_extern(jsonBytes, jsonLength, _generic0TypeId) +} + +func _$jsGenericParsePoint(_ json: String) throws(JSException) -> T { + json.bridgeJSWithLoweredParameter { (jsonBytes, jsonLength) in + bjs_jsGenericParsePoint(jsonBytes, jsonLength, T.bridgeJSTypeID) + } + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsImportPickFirst") +fileprivate func bjs_jsImportPickFirst_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsImportPickFirst_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsImportPickFirst(_ _generic0TypeId: Int32) -> Void { + return bjs_jsImportPickFirst_extern(_generic0TypeId) +} + +func _$jsImportPickFirst(_ a: T, _ b: T) throws(JSException) -> T { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_jsImportPickFirst(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsImportMakeInt") +fileprivate func bjs_jsImportMakeInt_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsImportMakeInt_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsImportMakeInt(_ _generic0TypeId: Int32) -> Void { + return bjs_jsImportMakeInt_extern(_generic0TypeId) +} + +func _$jsImportMakeInt() throws(JSException) -> T { + bjs_jsImportMakeInt(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsImportCombineSecond") +fileprivate func bjs_jsImportCombineSecond_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void +#else +fileprivate func bjs_jsImportCombineSecond_extern(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsImportCombineSecond(_ _generic0TypeId: Int32, _ _generic1TypeId: Int32) -> Void { + return bjs_jsImportCombineSecond_extern(_generic0TypeId, _generic1TypeId) +} + +func _$jsImportCombineSecond(_ a: T, _ b: U) throws(JSException) -> U { + b.bridgeJSStackPush() + a.bridgeJSStackPush() + bjs_jsImportCombineSecond(T.bridgeJSTypeID, U.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return U.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericArrayRoundTrip") +fileprivate func bjs_jsGenericArrayRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericArrayRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericArrayRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericArrayRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericArrayRoundTrip(_ values: [T]) throws(JSException) -> [T] { + let _ = values.bridgeJSLowerParameter() + bjs_jsGenericArrayRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericOptionalRoundTrip") +fileprivate func bjs_jsGenericOptionalRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericOptionalRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericOptionalRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericOptionalRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericOptionalRoundTrip(_ value: Optional) throws(JSException) -> Optional { + value.bridgeJSStackPush() + bjs_jsGenericOptionalRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericDictRoundTrip") +fileprivate func bjs_jsGenericDictRoundTrip_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericDictRoundTrip_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericDictRoundTrip(_ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericDictRoundTrip_extern(_generic0TypeId) +} + +func _$jsGenericDictRoundTrip(_ values: [String: T]) throws(JSException) -> [String: T] { + let _ = values.bridgeJSLowerParameter() + bjs_jsGenericDictRoundTrip(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return [String: T].bridgeJSLiftReturn() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericAfterOptionalArray") +fileprivate func bjs_jsGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Int32 +#else +fileprivate func bjs_jsGenericAfterOptionalArray_extern(_ values: Int32, _ _generic0TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericAfterOptionalArray(_ values: Int32, _ _generic0TypeId: Int32) -> Int32 { + return bjs_jsGenericAfterOptionalArray_extern(values, _generic0TypeId) +} + +func _$jsGenericAfterOptionalArray(_ values: Optional<[Int]>, _ value: T) throws(JSException) -> String { + value.bridgeJSStackPush() + let valuesIsSome = values.bridgeJSLowerParameter() + let ret = bjs_jsGenericAfterOptionalArray(valuesIsSome, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return String.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsGenericThrowOrRoundTrip") +fileprivate func bjs_jsGenericThrowOrRoundTrip_extern(_ shouldThrow: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_jsGenericThrowOrRoundTrip_extern(_ shouldThrow: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsGenericThrowOrRoundTrip(_ shouldThrow: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_jsGenericThrowOrRoundTrip_extern(shouldThrow, _generic0TypeId) +} + +func _$jsGenericThrowOrRoundTrip(_ shouldThrow: Bool, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let shouldThrowValue = shouldThrow.bridgeJSLowerParameter() + bjs_jsGenericThrowOrRoundTrip(shouldThrowValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericConsumer_init") +fileprivate func bjs_ImportGenericConsumer_init_extern() -> Int32 +#else +fileprivate func bjs_ImportGenericConsumer_init_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericConsumer_init() -> Int32 { + return bjs_ImportGenericConsumer_init_extern() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericConsumer_box_static") +fileprivate func bjs_ImportGenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ImportGenericConsumer_box_static_extern(_ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericConsumer_box_static(_ _generic0TypeId: Int32) -> Void { + return bjs_ImportGenericConsumer_box_static_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericConsumer_identity") +fileprivate func bjs_ImportGenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ImportGenericConsumer_identity_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericConsumer_identity(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_ImportGenericConsumer_identity_extern(self, _generic0TypeId) +} + +func _$ImportGenericConsumer_init() throws(JSException) -> JSObject { + let ret = bjs_ImportGenericConsumer_init() + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$ImportGenericConsumer_box(_ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + bjs_ImportGenericConsumer_box_static(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +func _$ImportGenericConsumer_identity(_ self: JSObject, _ value: T) throws(JSException) -> T { + value.bridgeJSStackPush() + let selfValue = self.bridgeJSLowerParameter() + bjs_ImportGenericConsumer_identity(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericBoxed_init") +fileprivate func bjs_ImportGenericBoxed_init_extern(_ _generic0TypeId: Int32) -> Int32 +#else +fileprivate func bjs_ImportGenericBoxed_init_extern(_ _generic0TypeId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericBoxed_init(_ _generic0TypeId: Int32) -> Int32 { + return bjs_ImportGenericBoxed_init_extern(_generic0TypeId) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ImportGenericBoxed_unwrap") +fileprivate func bjs_ImportGenericBoxed_unwrap_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void +#else +fileprivate func bjs_ImportGenericBoxed_unwrap_extern(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ImportGenericBoxed_unwrap(_ self: Int32, _ _generic0TypeId: Int32) -> Void { + return bjs_ImportGenericBoxed_unwrap_extern(self, _generic0TypeId) +} + +func _$ImportGenericBoxed_init(_ value: T) throws(JSException) -> JSObject { + value.bridgeJSStackPush() + let ret = bjs_ImportGenericBoxed_init(T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return JSObject.bridgeJSLiftReturn(ret) +} + +func _$ImportGenericBoxed_unwrap(_ self: JSObject) throws(JSException) -> T { + let selfValue = self.bridgeJSLowerParameter() + bjs_ImportGenericBoxed_unwrap(selfValue, T.bridgeJSTypeID) + if let error = _swift_js_take_exception() { + throw error + } + return T.bridgeJSStackPop() +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsTranslatePoint") fileprivate func bjs_jsTranslatePoint_extern(_ dx: Int32, _ dy: Int32) -> Void @@ -18459,6 +19066,8 @@ public func _bjs_BridgeJSRuntimeTests_register_type_handles() { NestedStructGroupA.Metadata.bridgeJSTypeID, NestedStructGroupB.Metadata.bridgeJSTypeID, NestedTypeHost.Label.bridgeJSTypeID, + GenericRTPoint.bridgeJSTypeID, + GenericRTNamespace.Metadata.bridgeJSTypeID, Point.bridgeJSTypeID, PointerFields.bridgeJSTypeID, DataPoint.bridgeJSTypeID, @@ -18483,6 +19092,7 @@ public func _bjs_BridgeJSRuntimeTests_register_type_handles() { TagReference.bridgeJSTypeID, TagHolderReference.bridgeJSTypeID, PriorityReference.bridgeJSTypeID, + ImportGenericBox.bridgeJSTypeID, Severity.bridgeJSTypeID, Shape.bridgeJSTypeID, InnerTag.bridgeJSTypeID, @@ -18513,6 +19123,10 @@ public func _bjs_BridgeJSRuntimeTests_register_type_handles() { NestedTypeHost.Variant.bridgeJSTypeID, LightColor.bridgeJSTypeID, ImportedPayloadSignal.bridgeJSTypeID, + GenericRTColor.bridgeJSTypeID, + GenericRTMode.bridgeJSTypeID, + GenericRTLevel.bridgeJSTypeID, + GenericRTOutcome.bridgeJSTypeID, OptionalAllTypesResult.bridgeJSTypeID, APIOptionalResult.bridgeJSTypeID, ] diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 6748d7c16..8622b1cc9 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -4844,6 +4844,70 @@ ], "swiftCallName" : "NestedTypeHost" }, + { + "constructor" : { + "abiName" : "bjs_ImportGenericBox_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "isFinal" : true, + "methods" : [ + { + "abiName" : "bjs_ImportGenericBox_get", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "get", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "ImportGenericBox", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "ImportGenericBox" + }, { "constructor" : { "abiName" : "bjs_JSNameRenamedClass_init", @@ -10347,6 +10411,152 @@ { "cases" : [ + ], + "emitStyle" : "const", + "name" : "GenericRTNamespace", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTNamespace", + "tsFullPath" : "GenericRTNamespace" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "red" + }, + { + "associatedValues" : [ + + ], + "name" : "green" + }, + { + "associatedValues" : [ + + ], + "name" : "blue" + } + ], + "emitStyle" : "const", + "name" : "GenericRTColor", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTColor", + "tsFullPath" : "GenericRTColor" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "light" + }, + { + "associatedValues" : [ + + ], + "name" : "dark" + } + ], + "emitStyle" : "const", + "name" : "GenericRTMode", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTMode", + "tsFullPath" : "GenericRTMode" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "low", + "rawValue" : "1" + }, + { + "associatedValues" : [ + + ], + "name" : "high", + "rawValue" : "9" + } + ], + "emitStyle" : "const", + "name" : "GenericRTLevel", + "rawType" : "Int", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTLevel", + "tsFullPath" : "GenericRTLevel" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "label" : "code", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "ok" + }, + { + "associatedValues" : [ + { + "label" : "message", + "type" : { + "string" : { + + } + } + } + ], + "name" : "fail" + } + ], + "emitStyle" : "const", + "name" : "GenericRTOutcome", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "GenericRTOutcome", + "tsFullPath" : "GenericRTOutcome" + }, + { + "cases" : [ + ], "emitStyle" : "const", "name" : "IntegerTypesSupportExports", @@ -18472,6 +18682,82 @@ { "methods" : [ + ], + "name" : "GenericRTPoint", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "x", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "y", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericRTPoint" + }, + { + "methods" : [ + + ], + "name" : "Metadata", + "namespace" : [ + "GenericRTNamespace" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "label", + "namespace" : [ + "GenericRTNamespace" + ], + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "count", + "namespace" : [ + "GenericRTNamespace" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "GenericRTNamespace.Metadata" + }, + { + "methods" : [ + ], "name" : "Point", "properties" : [ @@ -23779,6 +24065,498 @@ ] }, + { + "functions" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericRoundTripClass", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericParsePoint", + "parameters" : [ + { + "name" : "json", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsImportPickFirst", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsImportMakeInt", + "parameters" : [ + + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T", + "U" + ], + "name" : "jsImportCombineSecond", + "parameters" : [ + { + "name" : "a", + "type" : { + "generic" : { + "_0" : "T" + } + } + }, + { + "name" : "b", + "type" : { + "generic" : { + "_0" : "U" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "U" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericArrayRoundTrip", + "parameters" : [ + { + "name" : "values", + "type" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericOptionalRoundTrip", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "generic" : { + "_0" : "T" + } + }, + "_1" : "null" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericDictRoundTrip", + "parameters" : [ + { + "name" : "values", + "type" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "generic" : { + "_0" : "T" + } + } + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericAfterOptionalArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "nullable" : { + "_0" : { + "array" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + }, + "_1" : "null" + } + } + }, + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "jsGenericThrowOrRoundTrip", + "parameters" : [ + { + "name" : "shouldThrow", + "type" : { + "bool" : { + + } + } + }, + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "types" : [ + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "parameters" : [ + + ] + }, + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "identity", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "name" : "ImportGenericConsumer", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "box", + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ] + }, + { + "accessLevel" : "internal", + "constructor" : { + "accessLevel" : "internal", + "genericParameters" : [ + "T" + ], + "parameters" : [ + { + "name" : "value", + "type" : { + "generic" : { + "_0" : "T" + } + } + } + ] + }, + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "genericParameters" : [ + "T" + ], + "name" : "unwrap", + "parameters" : [ + + ], + "returnType" : { + "generic" : { + "_0" : "T" + } + } + } + ], + "name" : "ImportGenericBoxed", + "setters" : [ + + ], + "staticMethods" : [ + + ] + } + ] + }, { "functions" : [ { diff --git a/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift new file mode 100644 index 000000000..bfd63839f --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/ImportGenericAPIs.swift @@ -0,0 +1,280 @@ +import Testing +import JavaScriptKit + +@JS struct GenericRTPoint { + var x: Int + var y: Int +} + +@JS enum GenericRTNamespace { + @JS struct Metadata { + var label: String + var count: Int + } +} + +@JS enum GenericRTColor { + case red + case green + case blue +} + +@JS enum GenericRTMode: String { + case light + case dark +} + +@JS enum GenericRTLevel: Int { + case low = 1 + case high = 9 +} + +@JS enum GenericRTOutcome { + case ok(code: Int) + case fail(message: String) +} + +@JS final class ImportGenericBox { + @JS var value: Int + @JS init(value: Int) { + self.value = value + } + @JS func get() -> Int { + value + } +} + +@JSFunction func jsGenericRoundTrip(_ value: T) throws(JSException) -> T +@JSFunction func jsGenericRoundTripClass(_ value: T) throws(JSException) -> T +@JSFunction func jsGenericParsePoint(_ json: String) throws(JSException) -> T +@JSFunction func jsImportPickFirst(_ a: T, _ b: T) throws(JSException) -> T +@JSFunction func jsImportMakeInt() throws(JSException) -> T +@JSFunction func jsImportCombineSecond( + _ a: T, + _ b: U +) throws(JSException) -> U +@JSFunction func jsGenericArrayRoundTrip(_ values: [T]) throws(JSException) -> [T] +@JSFunction func jsGenericOptionalRoundTrip(_ value: T?) throws(JSException) -> T? +@JSFunction func jsGenericDictRoundTrip( + _ values: [String: T] +) throws(JSException) -> [String: T] +@JSFunction func jsGenericAfterOptionalArray( + _ values: [Int]?, + _ value: T +) throws(JSException) -> String + +@JSClass struct ImportGenericConsumer { + @JSFunction init() throws(JSException) + @JSFunction func identity(_ value: T) throws(JSException) -> T + @JSFunction static func box(_ value: T) throws(JSException) -> T +} + +@JSFunction func jsGenericThrowOrRoundTrip( + _ shouldThrow: Bool, + _ value: T +) throws(JSException) -> T + +@JSClass struct ImportGenericBoxed { + @JSFunction init(_ value: T) throws(JSException) + @JSFunction func unwrap() throws(JSException) -> T +} + +@Suite struct ImportGenericAPITests { + @Test func genericRoundTripScalars() throws { + #expect(try jsGenericRoundTrip(42) == 42) + #expect(try jsGenericRoundTrip(-7) == -7) + #expect(try jsGenericRoundTrip(3.5) == 3.5) + #expect(try jsGenericRoundTrip(Float(1.25)) == Float(1.25)) + #expect(try jsGenericRoundTrip(true) == true) + #expect(try jsGenericRoundTrip(false) == false) + #expect(try jsGenericRoundTrip("hello") == "hello") + #expect(try jsGenericRoundTrip("") == "") + } + + @Test func genericRoundTripNumerics() throws { + #expect(try jsGenericRoundTrip(Int8(-5)) == Int8(-5)) + #expect(try jsGenericRoundTrip(Int8.min) == Int8.min) + #expect(try jsGenericRoundTrip(Int8.max) == Int8.max) + #expect(try jsGenericRoundTrip(UInt8(200)) == UInt8(200)) + #expect(try jsGenericRoundTrip(UInt8.max) == UInt8.max) + #expect(try jsGenericRoundTrip(Int16(-1000)) == Int16(-1000)) + #expect(try jsGenericRoundTrip(UInt16(60000)) == UInt16(60000)) + #expect(try jsGenericRoundTrip(Int32(-123456)) == Int32(-123456)) + #expect(try jsGenericRoundTrip(UInt32(3_000_000_000)) == UInt32(3_000_000_000)) + #expect(try jsGenericRoundTrip(UInt32.max) == UInt32.max) + #expect(try jsGenericRoundTrip(UInt(42)) == UInt(42)) + #expect(try jsGenericRoundTrip(UInt(4_000_000_000)) == UInt(4_000_000_000)) + #expect(try jsGenericRoundTrip(Int64(-9_000_000_000)) == Int64(-9_000_000_000)) + #expect(try jsGenericRoundTrip(Int64.min) == Int64.min) + #expect(try jsGenericRoundTrip(Int64.max) == Int64.max) + #expect(try jsGenericRoundTrip(UInt64(18_000_000_000_000_000_000)) == UInt64(18_000_000_000_000_000_000)) + #expect(try jsGenericRoundTrip(UInt64.max) == UInt64.max) + } + + @Test func genericRoundTripJSValue() throws { + let number = try jsGenericRoundTrip(JSValue.number(3.5)) + #expect(number.number == 3.5) + let string = try jsGenericRoundTrip(JSValue.string("hi")) + #expect(string.string == "hi") + let boolean = try jsGenericRoundTrip(JSValue.boolean(true)) + #expect(boolean.boolean == true) + #expect(try jsGenericRoundTrip(JSValue.null).isNull) + #expect(try jsGenericRoundTrip(JSValue.undefined).isUndefined) + let object = JSObject.global.Object.function!.new() + object.tag = 7 + let roundTripped = try jsGenericRoundTrip(JSValue.object(object)) + #expect(roundTripped.object?.tag.number == 7) + } + + @Test func genericWrappedRoundTrip() throws { + #expect(try jsGenericArrayRoundTrip([1, 2, 3]) == [1, 2, 3]) + #expect(try jsGenericArrayRoundTrip(["a", "b"]) == ["a", "b"]) + #expect(try jsGenericArrayRoundTrip([Int]()) == []) + #expect(try jsGenericOptionalRoundTrip(Optional.some(7)) == 7) + #expect(try jsGenericOptionalRoundTrip(Optional.none) == nil) + #expect(try jsGenericOptionalRoundTrip(Optional.some("hi")) == "hi") + let outcome = try jsGenericOptionalRoundTrip(Optional.some(.ok(code: 5))) + guard case .some(.ok(let code)) = outcome else { + Issue.record("expected .ok") + return + } + #expect(code == 5) + #expect(try jsGenericOptionalRoundTrip(Optional.none) == nil) + #expect(try jsGenericDictRoundTrip(["x": 1, "y": 2]) == ["x": 1, "y": 2]) + #expect(try jsGenericDictRoundTrip([String: String]()) == [:]) + } + + @Test func genericRoundTripEnums() throws { + #expect(try jsGenericRoundTrip(GenericRTColor.red) == .red) + #expect(try jsGenericRoundTrip(GenericRTColor.blue) == .blue) + #expect(try jsGenericRoundTrip(GenericRTMode.dark) == .dark) + #expect(try jsGenericRoundTrip(GenericRTMode.light).rawValue == "light") + #expect(try jsGenericRoundTrip(GenericRTLevel.high) == .high) + let outcome = try jsGenericRoundTrip(GenericRTOutcome.ok(code: 42)) + guard case .ok(let code) = outcome else { + Issue.record("expected .ok") + return + } + #expect(code == 42) + let failure = try jsGenericRoundTrip(GenericRTOutcome.fail(message: "boom")) + guard case .fail(let message) = failure else { + Issue.record("expected .fail") + return + } + #expect(message == "boom") + } + + @Test func genericRoundTripStruct() throws { + let point = try jsGenericRoundTrip(GenericRTPoint(x: 1, y: 2)) + #expect(point.x == 1) + #expect(point.y == 2) + } + + @Test func genericRoundTripNestedStruct() throws { + let metadata = try jsGenericRoundTrip(GenericRTNamespace.Metadata(label: "alpha", count: 7)) + #expect(metadata.label == "alpha") + #expect(metadata.count == 7) + } + + @Test func genericParse() throws { + let point: GenericRTPoint = try jsGenericParsePoint("{\"x\": 10, \"y\": 20}") + #expect(point.x == 10) + #expect(point.y == 20) + let n: Int = try jsGenericParsePoint("42") + #expect(n == 42) + let string: String = try jsGenericParsePoint("\"hi\"") + #expect(string == "hi") + } + + @Test func genericPickFirstMultiUse() throws { + #expect(try jsImportPickFirst(10, 20) as Int == 10) + #expect(try jsImportPickFirst("a", "b") as String == "a") + let firstPoint = try jsImportPickFirst(GenericRTPoint(x: 1, y: 2), GenericRTPoint(x: 3, y: 4)) + #expect(firstPoint.x == 1) + #expect(firstPoint.y == 2) + } + + @Test func genericMakeReturnOnly() throws { + let made: Int = try jsImportMakeInt() + #expect(made == 123) + } + + @Test func genericCombineSecondMultiParameter() throws { + #expect(try jsImportCombineSecond(7, "hello") as String == "hello") + #expect(try jsImportCombineSecond("x", 9) as Int == 9) + let point = try jsImportCombineSecond(42, GenericRTPoint(x: 5, y: 6)) + #expect(point.x == 5) + #expect(point.y == 6) + } + + @Test func genericRoundTripHeapObjectClass() throws { + let box = ImportGenericBox(value: 314) + #expect(box.get() == 314) + let sameBox = try jsGenericRoundTripClass(box) + #expect(sameBox.get() == 314) + sameBox.value = 271 + #expect(box.get() == 271) + } + + @Test func genericMixedConsecutiveCalls() throws { + #expect(try jsGenericRoundTrip(1) == 1) + #expect(try jsGenericRoundTrip("two") == "two") + #expect(try jsGenericRoundTrip(3.0) == 3.0) + let p = try jsGenericRoundTrip(GenericRTPoint(x: 4, y: 5)) + #expect(p.x == 4) + #expect(p.y == 5) + } + + @Test func importGenericInstanceMethod() throws { + let consumer = try ImportGenericConsumer() + #expect(try consumer.identity(42) == 42) + #expect(try consumer.identity(-7) == -7) + #expect(try consumer.identity("hi") == "hi") + #expect(try consumer.identity(true) == true) + #expect(try consumer.identity(false) == false) + let point = try consumer.identity(GenericRTPoint(x: 3, y: 4)) + #expect(point.x == 3) + #expect(point.y == 4) + } + + /// A generic parameter shares the stacks with any other stack-lowered + /// parameter, so both have to arrive in declaration order. + @Test func genericAlongsideOptionalArray() throws { + #expect(try jsGenericAfterOptionalArray([1, 2], 42) == "[1,2]|42") + #expect(try jsGenericAfterOptionalArray([1, 2], GenericRTPoint(x: 3, y: 4)) == #"[1,2]|{"x":3,"y":4}"#) + #expect(try jsGenericAfterOptionalArray(nil, "x") == #"null|"x""#) + } + + @Test func genericImportPropagatesJSException() throws { + #expect(try jsGenericThrowOrRoundTrip(false, 42) == 42) + #expect(try jsGenericThrowOrRoundTrip(false, GenericRTPoint(x: 1, y: 2)).x == 1) + do { + let _: Int = try jsGenericThrowOrRoundTrip(true, 0) + Issue.record("Expected exception") + } catch { + #expect(error.description.contains("TestError")) + } + // A throwing generic call must not strand its argument on the shared + // stack: the next call has to read its own value back. + #expect(try jsGenericThrowOrRoundTrip(false, GenericRTPoint(x: 7, y: 8)).y == 8) + } + + @Test func importGenericConstructor() throws { + let boxedInt = try ImportGenericBoxed(42) + #expect(try boxedInt.unwrap() == 42) + let boxedText = try ImportGenericBoxed("boxed") + #expect(try boxedText.unwrap() == "boxed") + let boxedPoint = try ImportGenericBoxed(GenericRTPoint(x: 1, y: 2)) + let point: GenericRTPoint = try boxedPoint.unwrap() + #expect(point.x == 1) + #expect(point.y == 2) + } + + @Test func importGenericStaticMethod() throws { + #expect(try ImportGenericConsumer.box(7) == 7) + #expect(try ImportGenericConsumer.box("s") == "s") + #expect(try ImportGenericConsumer.box(true) == true) + let color = try ImportGenericConsumer.box(GenericRTColor.green) + #expect(color == .green) + } +} diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 9ca873301..b7e21e821 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -161,6 +161,38 @@ export async function setupOptions(options, context) { jsJoinOptionalStructThenArray: joinStackParams, jsJoinEnumThenArray: joinStackParams, jsJoinStringThenStackParams: joinStackParams, + jsGenericRoundTrip: (v) => v, + jsGenericRoundTripClass: (v) => v, + jsGenericParsePoint: (json) => JSON.parse(json), + jsImportPickFirst: (a, b) => a, + jsImportMakeInt: () => 123, + jsImportCombineSecond: (a, b) => b, + jsGenericThrowOrRoundTrip: (shouldThrow, v) => { + if (shouldThrow) { + throw new Error("TestError"); + } + return v; + }, + jsGenericArrayRoundTrip: (v) => v, + jsGenericOptionalRoundTrip: (v) => v, + jsGenericDictRoundTrip: (v) => v, + jsGenericAfterOptionalArray: (a, b) => `${JSON.stringify(a)}|${JSON.stringify(b)}`, + ImportGenericConsumer: class { + identity(value) { + return value; + } + static box(value) { + return value; + } + }, + ImportGenericBoxed: class { + constructor(value) { + this.value = value; + } + unwrap() { + return this.value; + } + }, roundTripArrayMembers: (value) => { return value; }, From db10037a8d5013eb0fa5bf66db735c863ec1ea51 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 11 Aug 2026 14:42:03 +0200 Subject: [PATCH 3/6] BridgeJS: Register core generic type handles from JavaScriptKit Every module's generated registration function listed the 15 core type handles before its own types, and every module's JS registration hook repeated the 15 primitive codec entries. The core types are owned by the library, not by any module, so define their registration once. `_bjs_core_register_type_handles` in JavaScriptKit exposes the core handle buffer under `bjs_core_register_type_handles`; because JavaScriptKit is linked into every BridgeJS binary, exactly one definition exists in the final wasm. The link step emits the matching `bjs[...]` hook once per linked bundle instead of once per module, and drives it before the per-module hooks. Generated per-module registration now carries only that module's own `@JS` types, so a module that merely uses generics emits no registration function at all. The ordering contract is still enforced on both sides: each hook checks the codec array length against the count Swift pushed, and a new build-time test checks the library's core list against `BridgeType.genericBridgeablePrimitives`, which the link step uses to build the core codec array. --- Benchmarks/Sources/Generated/BridgeJS.swift | 15 --- .../PlayBridgeJS/Generated/BridgeJS.swift | 15 --- .../Sources/BridgeJSCore/ExportSwift.swift | 4 + .../Sources/BridgeJSLink/BridgeJSLink.swift | 94 +++++++++++++------ .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 25 +++-- .../BridgeJSToolTests/BridgeJSLinkTests.swift | 7 +- .../CoreTypeRegistrationContractTests.swift | 48 ++++++++++ .../GenericMethodOnlyModuleCodegenTests.swift | 34 ++++++- .../BridgeJSCodegenTests/Alias.swift | 15 --- .../BridgeJSCodegenTests/AliasInClosure.swift | 15 --- .../BridgeJSCodegenTests/ArrayTypes.swift | 15 --- .../BridgeJSCodegenTests/Async.swift | 15 --- .../AsyncAssociatedValueEnum.swift | 15 --- .../ClassWithNestedTypes.swift | 15 --- .../DefaultParameters.swift | 15 --- .../DictionaryTypes.swift | 15 --- .../BridgeJSCodegenTests/DocComments.swift | 15 --- .../BridgeJSCodegenTests/EnumAlias.swift | 15 --- .../EnumAssociatedValue.swift | 15 --- .../EnumAssociatedValueImport.swift | 15 --- .../BridgeJSCodegenTests/EnumCase.swift | 15 --- .../BridgeJSCodegenTests/EnumCaseImport.swift | 15 --- .../EnumNamespace.Global.swift | 15 --- .../BridgeJSCodegenTests/EnumNamespace.swift | 15 --- .../BridgeJSCodegenTests/EnumRawType.swift | 15 --- .../BridgeJSCodegenTests/GenericImports.swift | 15 --- .../ImportedTypeInExportedInterface.swift | 15 --- .../BridgeJSCodegenTests/JSNameOverride.swift | 15 --- .../BridgeJSCodegenTests/NestedType.swift | 15 --- .../BridgeJSCodegenTests/Protocol.swift | 15 --- .../StaticFunctions.Global.swift | 15 --- .../StaticFunctions.swift | 15 --- .../StaticProperties.Global.swift | 15 --- .../StaticProperties.swift | 15 --- .../StructWithNestedTypes.swift | 15 --- .../BridgeJSCodegenTests/SwiftClosure.swift | 15 --- .../BridgeJSCodegenTests/SwiftStruct.swift | 15 --- .../SwiftStructImports.swift | 15 --- .../BridgeJSCodegenTests/UnsafePointer.swift | 15 --- .../__Snapshots__/BridgeJSLinkTests/Alias.js | 1 + .../BridgeJSLinkTests/AliasInClosure.js | 1 + .../BridgeJSLinkTests/ArrayTypes.js | 1 + .../__Snapshots__/BridgeJSLinkTests/Async.js | 1 + .../AsyncAssociatedValueEnum.js | 1 + .../BridgeJSLinkTests/AsyncImport.js | 1 + .../BridgeJSLinkTests/AsyncStaticImport.js | 1 + .../BridgeJSLinkTests/ClassWithNestedTypes.js | 1 + .../BridgeJSLinkTests/DefaultParameters.js | 1 + .../BridgeJSLinkTests/DictionaryTypes.js | 1 + .../BridgeJSLinkTests/DocComments.js | 1 + .../BridgeJSLinkTests/EnumAlias.js | 1 + .../BridgeJSLinkTests/EnumAssociatedValue.js | 1 + .../EnumAssociatedValueImport.js | 1 + .../BridgeJSLinkTests/EnumCase.js | 1 + .../BridgeJSLinkTests/EnumCaseImport.js | 1 + .../BridgeJSLinkTests/EnumNamespace.Global.js | 1 + .../BridgeJSLinkTests/EnumNamespace.js | 1 + .../BridgeJSLinkTests/EnumRawType.js | 1 + .../BridgeJSLinkTests/FixedWidthIntegers.js | 1 + .../BridgeJSLinkTests/GenericImports.js | 17 +++- .../BridgeJSLinkTests/GlobalGetter.js | 1 + .../BridgeJSLinkTests/GlobalThisImports.js | 1 + .../IdentityModeClass.ConfigPointer.js | 1 + .../IdentityModeClass.PerClass.js | 1 + .../BridgeJSLinkTests/IdentityModeClass.js | 1 + .../BridgeJSLinkTests/ImportArray.js | 1 + .../ImportedTypeInExportedInterface.js | 1 + .../BridgeJSLinkTests/InvalidPropertyNames.js | 1 + .../BridgeJSLinkTests/JSClass.js | 1 + .../JSClassStaticFunctions.js | 1 + .../BridgeJSLinkTests/JSImportBareModule.js | 1 + .../JSImportBareModuleFallback.js | 1 + .../BridgeJSLinkTests/JSImportModule.js | 1 + .../BridgeJSLinkTests/JSNameOverride.js | 1 + .../BridgeJSLinkTests/JSTypedArrayTypes.js | 1 + .../BridgeJSLinkTests/JSValue.js | 1 + .../BridgeJSLinkTests/MixedGlobal.js | 1 + .../BridgeJSLinkTests/MixedModules.js | 1 + .../BridgeJSLinkTests/MixedPrivate.js | 1 + .../BridgeJSLinkTests/Namespaces.Global.js | 1 + .../BridgeJSLinkTests/Namespaces.js | 1 + .../BridgeJSLinkTests/NestedType.js | 1 + .../BridgeJSLinkTests/Optionals.js | 1 + .../BridgeJSLinkTests/PrimitiveParameters.js | 1 + .../BridgeJSLinkTests/PrimitiveReturn.js | 1 + .../BridgeJSLinkTests/PropertyTypes.js | 1 + .../BridgeJSLinkTests/Protocol.js | 1 + .../BridgeJSLinkTests/ProtocolInClosure.js | 1 + .../StaticFunctions.Global.js | 1 + .../BridgeJSLinkTests/StaticFunctions.js | 1 + .../StaticProperties.Global.js | 1 + .../BridgeJSLinkTests/StaticProperties.js | 1 + .../BridgeJSLinkTests/StringParameter.js | 1 + .../BridgeJSLinkTests/StringReturn.js | 1 + .../StructWithNestedTypes.js | 1 + .../BridgeJSLinkTests/SwiftClass.js | 1 + .../BridgeJSLinkTests/SwiftClosure.js | 1 + .../BridgeJSLinkTests/SwiftClosureImports.js | 1 + .../BridgeJSLinkTests/SwiftStruct.js | 1 + .../BridgeJSLinkTests/SwiftStructImports.js | 1 + .../SwiftTypedClosureAccess.js | 1 + .../__Snapshots__/BridgeJSLinkTests/Throws.js | 1 + .../BridgeJSLinkTests/UnsafePointer.js | 1 + .../VoidParameterVoidReturn.js | 1 + Plugins/PackageToJS/Templates/instantiate.js | 3 + .../JavaScriptKit/BridgeJSIntrinsics.swift | 50 ++++++++++ .../Generated/BridgeJS.swift | 15 --- .../Generated/BridgeJS.swift | 15 --- 108 files changed, 301 insertions(+), 570 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/CoreTypeRegistrationContractTests.swift diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index 81888845b..5e3e11db8 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -2275,21 +2275,6 @@ fileprivate func _bjs_Benchmarks_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_Benchmarks_register_type_handles") public func _bjs_Benchmarks_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, SimpleStruct.bridgeJSTypeID, Address.bridgeJSTypeID, Person.bridgeJSTypeID, diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index dff715c64..328ae0610 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift @@ -295,21 +295,6 @@ fileprivate func _bjs_PlayBridgeJS_register_type_handles_extern(_ base: UnsafePo @_expose(wasm, "bjs_PlayBridgeJS_register_type_handles") public func _bjs_PlayBridgeJS_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, PlayBridgeJSOutput.bridgeJSTypeID, PlayBridgeJSDiagnostic.bridgeJSTypeID, PlayBridgeJSResult.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index e4d0f5b02..1508363c2 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -908,6 +908,10 @@ struct GenericConformanceCodegen { /// registered type's `bridgeJSTypeID` into a buffer, in the canonical order of /// `BridgeJSSkeleton.typeRegistrationEntries`, and passes it to the JS import /// hook of the same name, which pairs the IDs with its codec array by index. +/// +/// Only the module's own `@JS` types are listed; the core (primitive) handles are +/// registered once by the JavaScriptKit library itself +/// (`_bjs_core_register_type_handles`). public struct GenericTypeRegistrationCodegen { public init() {} diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 13c323f2c..f7429f3d8 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -355,6 +355,11 @@ public struct BridgeJSLink { declarations.append(" return;") declarations.append(" }") declarations.append(" __bjs_typeHandlesRegistered = true;") + // The core (primitive) handles live in the JavaScriptKit library, so + // they are registered once here rather than by every module. + declarations.append( + " \(JSGlueVariableScope.reservedInstance).exports[\"\(ABINameGenerator.coreTypeRegistrationFunctionName)\"]();" + ) for skeleton in skeletons { guard skeleton.typeRegistrationEntries != nil else { continue } let name = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) @@ -433,53 +438,88 @@ public struct BridgeJSLink { ) } + /// Writes the body shared by every registration hook: verify the codec array + /// lines up with the buffer Swift pushed, then pair IDs with codecs by index. + /// + /// The count check is the enforcement point of the ordering contract: the + /// Swift side and the JS side derive their lists from the same declaration + /// order, so a divergence shows up here instead of as a silent mismatch. + private func writeTypeHandleRegistrationBody( + into printer: CodeFragmentPrinter, + mismatchDescription: String + ) { + printer.write("if (count !== codecs.length) {") + printer.indent { + printer.write( + "throw new Error(\"BridgeJS: type handle registration mismatch for \(mismatchDescription)\");" + ) + } + printer.write("}") + printer.write( + "const typeIds = new Int32Array(\(JSGlueVariableScope.reservedMemory).buffer, base >>> 0, count >>> 0);" + ) + printer.write("for (let i = 0; i < count; i++) {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedCodecByTypeId).set(typeIds[i], codecs[i]);") + } + printer.write("}") + } + + /// Installs the `bjs_core_register_type_handles` hook. The core handles are + /// owned by the JavaScriptKit library rather than by generated code, so the + /// wasm import exists in every binary that links JavaScriptKit and the hook + /// is always installed; without generics anywhere in the build it is a no-op + /// and the registration export is never called. + private func generateCoreTypeRegistrationHook(into printer: CodeFragmentPrinter) throws { + let hookName = ABINameGenerator.coreTypeRegistrationFunctionName + guard hasGenerics else { + printer.write("bjs[\"\(hookName)\"] = function() {};") + return + } + try ContainerCodecJS.registerPrimitiveCodecs(context: makeCodecPrintContext(printer: printer)) + printer.write("bjs[\"\(hookName)\"] = function(base, count) {") + printer.indent { + // Same canonical order as `_bjs_core_register_type_handles` in the + // JavaScriptKit library. + printer.write("const codecs = [") + printer.indent { + for primitive in BridgeType.genericBridgeablePrimitives { + printer.write("\(JSGlueVariableScope.reservedPrimitiveCodecs).\(primitive.token),") + } + } + printer.write("];") + writeTypeHandleRegistrationBody(into: printer, mismatchDescription: "core types") + } + printer.write("}") + } + /// Installs the per-module `bjs__register_type_handles` import /// hooks. A module with a registration function always carries the wasm /// import, so a hook is always installed; without generics anywhere in the /// build it is a no-op and the registration export is never called. private func generateTypeRegistrationHooks(into printer: CodeFragmentPrinter) throws { + try generateCoreTypeRegistrationHook(into: printer) for skeleton in skeletons { - guard skeleton.typeRegistrationEntries != nil else { continue } + guard let moduleEntries = skeleton.typeRegistrationEntries else { continue } let hookName = ABINameGenerator.typeRegistrationFunctionName(moduleName: skeleton.moduleName) guard hasGenerics else { printer.write("bjs[\"\(hookName)\"] = function() {};") continue } - // The hooks resolve type IDs against the shared primitive codec table. - try ContainerCodecJS.registerPrimitiveCodecs(context: makeCodecPrintContext(printer: printer)) - let moduleEntries = skeleton.exported?.genericBridgeableTypeEntries ?? [] printer.write("bjs[\"\(hookName)\"] = function(base, count) {") try printer.indent { - // Same canonical order as the Swift registration function: - // primitives first, then the module's own types. + // Same order as the module's Swift registration function. printer.write("const codecs = [") - printer.indent { - for primitive in BridgeType.genericBridgeablePrimitives { - printer.write("\(JSGlueVariableScope.reservedPrimitiveCodecs).\(primitive.token),") - } - } - printer.write("].concat([") try printer.indent { for entry in moduleEntries { try appendGenericCodecLiteral(type: entry.bridgeType, into: printer) } } - printer.write("]);") - printer.write("if (count !== codecs.length) {") - printer.indent { - printer.write( - "throw new Error(\"BridgeJS: type handle registration mismatch for module '\(skeleton.moduleName)'\");" - ) - } - printer.write("}") - printer.write( - "const typeIds = new Int32Array(\(JSGlueVariableScope.reservedMemory).buffer, base >>> 0, count >>> 0);" + printer.write("];") + writeTypeHandleRegistrationBody( + into: printer, + mismatchDescription: "module '\(skeleton.moduleName)'" ) - printer.write("for (let i = 0; i < count; i++) {") - printer.indent { - printer.write("\(JSGlueVariableScope.reservedCodecByTypeId).set(typeIds[i], codecs[i]);") - } - printer.write("}") } printer.write("}") } diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 2cea16fb4..641105d12 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -32,6 +32,13 @@ public struct ABINameGenerator { "bjs_\(moduleName)_register_type_handles" } + /// Name of the core type-handle registration function. Unlike the per-module + /// ones, this is defined once in the JavaScriptKit library (see + /// `_bjs_core_register_type_handles` in `BridgeJSIntrinsics.swift`) so the + /// primitive handles exist exactly once in the final binary and the JS glue + /// registers their codecs once per linked bundle. + public static let coreTypeRegistrationFunctionName = "bjs_core_register_type_handles" + /// Generates ABI name using standardized namespace + context pattern public static func generateABIName( baseName: String, @@ -383,17 +390,17 @@ extension ExportedSkeleton { extension BridgeJSSkeleton { /// The ordered list of types this module registers type handles for, or - /// `nil` when it emits no registration function. Primitive handles are - /// library singletons, so every module re-registering them writes the same - /// ID-to-codec pair, and a pure-import build still gets a populated table. + /// `nil` when it emits no registration function. + /// + /// Only the module's own `@JS` types appear here: the core (primitive) + /// handles are owned by the JavaScriptKit library, which registers them once + /// for the whole binary via ``ABINameGenerator/coreTypeRegistrationFunctionName``. + /// A module that only *uses* generics therefore needs no registration + /// function of its own. public var typeRegistrationEntries: [GenericBridgeableTypeEntry]? { let exportedEntries = exported?.genericBridgeableTypeEntries ?? [] - let hasGenericImports = imported?.hasGenericDeclarations ?? false - guard !exportedEntries.isEmpty || hasGenericImports else { return nil } - let primitives = BridgeType.genericBridgeablePrimitives.map { - GenericBridgeableTypeEntry(swiftName: $0.token, bridgeType: $0.type) - } - return primitives + exportedEntries + guard !exportedEntries.isEmpty else { return nil } + return exportedEntries } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index 23ffb3c6d..6cc9162ca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -251,9 +251,14 @@ import Testing let coreEntries = try #require(core.typeRegistrationEntries) #expect(coreEntries.contains { $0.swiftName == "Vector3D" }) + // App exports no @JS types, so it owns no handles: only the core + // (library-owned) registration and Core's own registration run. + #expect(app.typeRegistrationEntries == nil) + let js = try BridgeJSLink(skeletons: [core, app], sharedMemory: false).link().outputJs + #expect(js.contains("instance.exports[\"bjs_core_register_type_handles\"]();")) #expect(js.contains("instance.exports[\"bjs_Core_register_type_handles\"]();")) - #expect(js.contains("instance.exports[\"bjs_App_register_type_handles\"]();")) + #expect(!js.contains("bjs_App_register_type_handles")) // `lower(v)` is unique to a codec literal in a registration array; // `structHelpers.Vector3D` on its own is emitted for every @JS struct. #expect(js.contains("structHelpers.Vector3D.lower(v);")) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/CoreTypeRegistrationContractTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CoreTypeRegistrationContractTests.swift new file mode 100644 index 000000000..c3995126b --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CoreTypeRegistrationContractTests.swift @@ -0,0 +1,48 @@ +import Foundation +import Testing + +@testable import BridgeJSSkeleton + +/// The core (primitive) generic type handles are registered by the JavaScriptKit +/// library itself, not by generated code, so the ordering contract between the +/// Swift buffer and the JS codec array spans two repositories' worth of source: +/// `_bjs_core_register_type_handles` in `Sources/JavaScriptKit/BridgeJSIntrinsics.swift` +/// and `BridgeType.genericBridgeablePrimitives` here. +/// +/// The generated glue checks the *count* at registration time; this test checks +/// the *order* at build time so a reordering cannot silently mis-pair codecs. +@Suite struct CoreTypeRegistrationContractTests { + private static var repositoryRoot: URL { + URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() // BridgeJSToolTests + .deletingLastPathComponent() // Tests + .deletingLastPathComponent() // BridgeJS + .deletingLastPathComponent() // Plugins + .deletingLastPathComponent() // + } + + @Test + func coreTypeHandleOrderMatchesGenericBridgeablePrimitives() throws { + let intrinsics = Self.repositoryRoot + .appendingPathComponent("Sources/JavaScriptKit/BridgeJSIntrinsics.swift") + let source = try String(contentsOf: intrinsics, encoding: .utf8) + + let beginMarker = "// BEGIN bjs_core_type_handles" + let endMarker = "// END bjs_core_type_handles" + guard let begin = source.range(of: beginMarker), let end = source.range(of: endMarker) else { + Issue.record("Could not find the core type handle list markers in \(intrinsics.path)") + return + } + + let names = + source[begin.upperBound.. String? in + let trimmed = line.trimmingCharacters(in: .whitespaces) + guard trimmed.hasSuffix(".bridgeJSTypeID,") else { return nil } + return String(trimmed.dropLast(".bridgeJSTypeID,".count)) + } + + #expect(names == BridgeType.genericBridgeablePrimitives.map(\.token)) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift index 7cb690678..e76f2861b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/GenericMethodOnlyModuleCodegenTests.swift @@ -3,8 +3,10 @@ import Testing @Suite struct GenericMethodOnlyModuleCodegenTests { @Test func importMethodOnlyEmitsJSRuntimeInfrastructure() throws { - // A module with generic imports but no exported @JS types still needs a - // populated codec table for the primitives, so it registers them itself. + // A module with generic imports but no exported @JS types needs a + // populated codec table, but it owns none of the entries: the core + // handles come from the JavaScriptKit library's own registration, so the + // module emits no registration function of its own. let js = try linkSource( """ @JSClass struct OnlyConsumer { @@ -14,8 +16,9 @@ import Testing ).js #expect(js.contains("const __bjs_codecByTypeId = new Map();")) #expect(js.contains("function __bjs_codecForTypeId(typeId) {")) - #expect(js.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) - #expect(js.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + #expect(js.contains("bjs[\"bjs_core_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("instance.exports[\"bjs_core_register_type_handles\"]();")) + #expect(!js.contains("bjs_TestModule_register_type_handles")) } @Test @@ -33,7 +36,28 @@ import Testing ).js #expect(js.contains("const __bjs_codecByTypeId = new Map();")) #expect(js.contains("function __bjs_codecForTypeId(typeId) {")) + #expect(js.contains("bjs[\"bjs_core_register_type_handles\"] = function(base, count) {")) + #expect(js.contains("instance.exports[\"bjs_core_register_type_handles\"]();")) + #expect(!js.contains("bjs_TestModule_register_type_handles")) + } + + @Test + func exportedTypesStillRegisterTheirOwnHandlesOnly() throws { + // A module that exports @JS types registers exactly those, without + // repeating the core entries the library already owns. + let js = try linkSource( + """ + @JS struct Point { + var x: Int + @JS init(x: Int) { self.x = x } + } + @JSClass struct Consumer { + @JSFunction func identity(_ value: T) throws(JSException) -> T + } + """ + ).js #expect(js.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function(base, count) {")) - #expect(js.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) + // The primitive entries appear exactly once, in the core hook. + #expect(js.components(separatedBy: "__bjs_primitiveCodecs.Bool,").count - 1 == 1) } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift index 7fc853579..4483de428 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Alias.swift @@ -415,21 +415,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, PolygonReference.bridgeJSTypeID, TagReference.bridgeJSTypeID, InnerTag.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift index 9d9c40502..0a208bf70 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AliasInClosure.swift @@ -200,21 +200,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, PolygonReference.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift index af2ddb544..94b8eb208 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift @@ -664,21 +664,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Point.bridgeJSTypeID, Direction.bridgeJSTypeID, Status.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift index bb51829d7..81c8c1c56 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift @@ -734,21 +734,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, AsyncPoint.bridgeJSTypeID, AsyncDirection.bridgeJSTypeID, AsyncTheme.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift index 8ea2e5449..6776998bc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift @@ -126,21 +126,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, AsyncPayloadResult.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift index b8736635d..c9c291317 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ClassWithNestedTypes.swift @@ -191,21 +191,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Account.Credentials.bridgeJSTypeID, Account.Role.bridgeJSTypeID, ] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift index 4f343476a..e2e74e532 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift @@ -657,21 +657,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Config.bridgeJSTypeID, MathOperations.bridgeJSTypeID, Status.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift index 090e93eb0..2990eeabe 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift @@ -181,21 +181,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Counters.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift index 03dfba96a..fab694b18 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DocComments.swift @@ -331,21 +331,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Point.bridgeJSTypeID, Color.bridgeJSTypeID, ] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift index 812ece23e..5689b143f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAlias.swift @@ -64,21 +64,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, ColorBox.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift index 875d6f601..4ca3236f8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift @@ -684,21 +684,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Point.bridgeJSTypeID, APIResult.bridgeJSTypeID, ComplexResult.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift index 5e597d6ae..2c275a7a3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift @@ -122,21 +122,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, PayloadSignal.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift index c8ea2699f..dab981312 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift @@ -252,21 +252,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Direction.bridgeJSTypeID, Status.bridgeJSTypeID, TSDirection.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift index 9bab304a9..6ed293525 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift @@ -107,21 +107,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Signal.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift index 2801e1788..9d6908bcc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift @@ -383,21 +383,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Networking.API.Method.bridgeJSTypeID, Configuration.LogLevel.bridgeJSTypeID, Configuration.Port.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift index 2801e1788..9d6908bcc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift @@ -383,21 +383,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Networking.API.Method.bridgeJSTypeID, Configuration.LogLevel.bridgeJSTypeID, Configuration.Port.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift index e91f1b231..2dbb21422 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift @@ -547,21 +547,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Theme.bridgeJSTypeID, TSTheme.bridgeJSTypeID, FeatureFlag.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift index 044fd0e57..7714c498e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GenericImports.swift @@ -492,21 +492,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, GenericPoint.bridgeJSTypeID, GenericImportBox.bridgeJSTypeID, GenericColor.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift index dfec6b6a0..b9fddf706 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift @@ -135,21 +135,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, FooContainer.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift index 5f767abdb..8e01bca22 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift @@ -365,21 +365,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, RenamedVector.bridgeJSTypeID, RenamedEnumMembers.bridgeJSTypeID, ] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift index ca1c98a75..9e1b0e0f6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift @@ -193,21 +193,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, User.Stats.bridgeJSTypeID, Player.Stats.bridgeJSTypeID, ] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index 2ef680b8a..7c2db9a98 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -1068,21 +1068,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Direction.bridgeJSTypeID, ExampleEnum.bridgeJSTypeID, Result.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index 18e91616c..2d5a93c54 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -224,21 +224,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Calculator.bridgeJSTypeID, APIResult.bridgeJSTypeID, ] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index 18e91616c..2d5a93c54 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -224,21 +224,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Calculator.bridgeJSTypeID, APIResult.bridgeJSTypeID, ] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift index 75c4382dd..721c5335a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift @@ -351,21 +351,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, PropertyEnum.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift index 75c4382dd..721c5335a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift @@ -351,21 +351,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, PropertyEnum.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift index 1b8a69739..8fc6db1a7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StructWithNestedTypes.swift @@ -283,21 +283,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Shape.bridgeJSTypeID, Widget.bridgeJSTypeID, Widget.Layout.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index bad3ba0e1..f349f0c40 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -2749,21 +2749,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Animal.bridgeJSTypeID, Direction.bridgeJSTypeID, Theme.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 7aca6afd5..b4e54961c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -675,21 +675,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, DataPoint.bridgeJSTypeID, Address.bridgeJSTypeID, Person.bridgeJSTypeID, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift index a5c5d9fd8..4e9899470 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift @@ -101,21 +101,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, Point.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift index 615608687..69011da18 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.swift @@ -190,21 +190,6 @@ fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePoin @_expose(wasm, "bjs_TestModule_register_type_handles") public func _bjs_TestModule_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, PointerFields.bridgeJSTypeID, ] typeIds.withUnsafeBufferPointer { buffer in diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js index d8a23090a..c9c09bd97 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js @@ -449,6 +449,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js index cb130421b..fa9095cd8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AliasInClosure.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index 39c0507c1..86a84490e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -448,6 +448,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 497c71bf8..4b3e0c3ed 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -444,6 +444,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.AsyncPoint.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js index 8e09e38d9..5671e4898 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js @@ -239,6 +239,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js index fa50b23f2..96c0d11e8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js @@ -221,6 +221,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js index c359886b3..47dd161a2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js @@ -220,6 +220,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js index db3288037..30d0522c0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Account_Credentials.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index 16505d112..ac3a508da 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -472,6 +472,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.MathOperations.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 78e1d4c54..2ddf3e217 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -438,6 +438,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Counters.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js index 53cd64917..65323aace 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js index 43ff590b4..d8bc06fcf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAlias.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 814736050..b98b2af7e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -1064,6 +1064,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js index a31c96450..bc0df916b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index 169ade160..838e3062b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js index fa128130a..b4e67b6b8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index 859703175..0a691374b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index 81c1eacd9..03f0a8d9a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index ac8dc0ff5..92e1868c7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -492,6 +492,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js index a009f8d71..56a31b784 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js index 3ac1ea77e..ec7fb161d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -51,6 +51,7 @@ export async function createInstantiator(options, swift) { return; } __bjs_typeHandlesRegistered = true; + instance.exports["bjs_core_register_type_handles"](); instance.exports["bjs_TestModule_register_type_handles"](); } function __bjs_codecForTypeId(typeId) { @@ -501,7 +502,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.GenericPoint.lift(); return swift.memory.retain(value); } - bjs["bjs_TestModule_register_type_handles"] = function(base, count) { + bjs["bjs_core_register_type_handles"] = function(base, count) { const codecs = [ __bjs_primitiveCodecs.Bool, __bjs_primitiveCodecs.Int, @@ -518,7 +519,17 @@ export async function createInstantiator(options, swift) { __bjs_primitiveCodecs.Double, __bjs_primitiveCodecs.String, __bjs_primitiveCodecs.JSValue, - ].concat([ + ]; + if (count !== codecs.length) { + throw new Error("BridgeJS: type handle registration mismatch for core types"); + } + const typeIds = new Int32Array(memory.buffer, base >>> 0, count >>> 0); + for (let i = 0; i < count; i++) { + __bjs_codecByTypeId.set(typeIds[i], codecs[i]); + } + } + bjs["bjs_TestModule_register_type_handles"] = function(base, count) { + const codecs = [ { lower: (v) => { structHelpers.GenericPoint.lower(v); @@ -569,7 +580,7 @@ export async function createInstantiator(options, swift) { return enumValue; }, }, - ]); + ]; if (count !== codecs.length) { throw new Error("BridgeJS: type handle registration mismatch for module 'TestModule'"); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js index b1d830768..adb70913c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js index 6f43c2d9c..760a6b50c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js index 83f53d8a6..1e1d14696 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js index bb6f36902..c85aee3af 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js index bb6f36902..c85aee3af 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index bf1707b56..77cde8a89 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -417,6 +417,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 8974e3722..e3fbdba8d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -472,6 +472,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.FooContainer.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js index 8d1ac2698..e8fe5ec10 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js index 08215f159..15b48d4b9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js index a38b0a391..5eaba3c8f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.js index 1c995923a..6d1b1b6fb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModule.js @@ -112,6 +112,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.js index 038374240..9428698be 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportBareModuleFallback.js @@ -109,6 +109,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.js index e03dcbab4..aacf5e61a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSImportModule.js @@ -109,6 +109,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js index 026acf3f4..7d11a24ff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js @@ -135,6 +135,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.RenamedVector.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js index 5c713cc78..f02f6bcf2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index f39091a1f..136167f2a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -417,6 +417,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index 39ecf8d99..5db38dde5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index 62d7651e8..66818952b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index 69bfe5ff1..a732808a6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index fcb6dd88d..ef10ff9b9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -416,6 +416,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index ef083c4d7..bb4fce7a6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -416,6 +416,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index e03b09221..ad0c75942 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -145,6 +145,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Player_Stats.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 0a4fcc28c..7d073e02a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -417,6 +417,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js index 46d57d793..d4480a65c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js index bb4e8552d..e9b298fb2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index 61560134a..beb9417df 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index e2c711f8f..c28ceeb31 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -473,6 +473,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js index 01f9fe0e1..eed26c581 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 8f783865e..88fb0c321 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 4841e3350..7c614f070 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -150,6 +150,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 189db1f0e..e2a9093b6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index a5a003a1c..f442745e5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -111,6 +111,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js index 2c3da5f26..ebddbefd2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js index 057bf9658..d2dfa204f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js index 3270abd58..06873bf26 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js @@ -193,6 +193,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Widget_Bounds.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index be63f59be..92ef435fb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index bebe9179d..e208ff35c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -551,6 +551,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Animal.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index d03915f87..96c78dd22 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -221,6 +221,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index c16b674ae..ad8d4e29d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -662,6 +662,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Vector2D.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index 9d613c8a9..e9add7027 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -435,6 +435,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js index 66d6494fd..500a005a3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js @@ -131,6 +131,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js index 6ff126525..58ff6a85a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index 704dbb021..ecc14e5ae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -130,6 +130,7 @@ export async function createInstantiator(options, swift) { const value = structHelpers.PointerFields.lift(); return swift.memory.retain(value); } + bjs["bjs_core_register_type_handles"] = function() {}; bjs["bjs_TestModule_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js index 3c75771c5..81b09eaf4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js @@ -107,6 +107,7 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["bjs_core_register_type_handles"] = function() {}; const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); bjs["swift_js_make_promise"] = function() { let resolve, reject; diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 6181afe48..62aa724bf 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -70,6 +70,9 @@ async function createInstantiator(options, swift) { swift_js_closure_unregister: unexpectedBjsCall, swift_js_push_typed_array: unexpectedBjsCall, swift_js_make_promise: unexpectedBjsCall, + // Imported unconditionally by JavaScriptKit's core type-handle + // registration export, which is only invoked by BridgeJS glue. + bjs_core_register_type_handles: unexpectedBjsCall, }; }, /** @param {WebAssembly.Instance} instance */ diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index b15e07b5d..71f7fffce 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -1013,6 +1013,56 @@ extension JSValue: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = JSValue.bridgeJSMakeTypeHandle() } +// MARK: Core generic type-handle registration +// +// Every `BridgedSwiftGenericBridgeable` type publishes its runtime type ID to the +// JS glue, which pairs the IDs with the codec array it emitted in the same order. +// The core types below are owned by this library, so their registration lives +// here once for the whole binary instead of being copied into every module's +// generated registration function; generated per-module registration only carries +// that module's own `@JS` types. +// +// The order is the ABI contract with the JS side: it must match +// `BridgeType.genericBridgeablePrimitives` in +// `Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift`, from which +// the link step builds the core codec array. `CoreTypeRegistrationContractTests` +// checks the two lists stay in sync at build time, and the generated JS verifies +// the count at registration time. +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_core_register_type_handles") +private func _bjs_core_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +/// Publishes the core (primitive) BridgeJS type handles to the JS glue. +/// +/// Called by the generated glue once per instance, before any module's own +/// registration function. Not intended to be called from user code. +@_expose(wasm, "bjs_core_register_type_handles") +public func _bjs_core_register_type_handles() { + // BEGIN bjs_core_type_handles + let typeIds: [Int32] = [ + Bool.bridgeJSTypeID, + Int.bridgeJSTypeID, + Int8.bridgeJSTypeID, + UInt8.bridgeJSTypeID, + Int16.bridgeJSTypeID, + UInt16.bridgeJSTypeID, + Int32.bridgeJSTypeID, + UInt32.bridgeJSTypeID, + UInt.bridgeJSTypeID, + Int64.bridgeJSTypeID, + UInt64.bridgeJSTypeID, + Float.bridgeJSTypeID, + Double.bridgeJSTypeID, + String.bridgeJSTypeID, + JSValue.bridgeJSTypeID, + ] + // END bjs_core_type_handles + typeIds.withUnsafeBufferPointer { buffer in + _bjs_core_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif + /// A protocol that Swift heap objects exposed to JavaScript via `@JS class` must conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. diff --git a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift index deedc1ccf..91638a428 100644 --- a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift @@ -378,21 +378,6 @@ fileprivate func _bjs_BridgeJSGlobalTests_register_type_handles_extern(_ base: U @_expose(wasm, "bjs_BridgeJSGlobalTests_register_type_handles") public func _bjs_BridgeJSGlobalTests_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, GlobalNetworking.API.CallMethod.bridgeJSTypeID, GlobalConfiguration.PublicLogLevel.bridgeJSTypeID, GlobalConfiguration.AvailablePort.bridgeJSTypeID, diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 9c7cc6d2a..c70de88dc 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -19047,21 +19047,6 @@ fileprivate func _bjs_BridgeJSRuntimeTests_register_type_handles_extern(_ base: @_expose(wasm, "bjs_BridgeJSRuntimeTests_register_type_handles") public func _bjs_BridgeJSRuntimeTests_register_type_handles() { let typeIds: [Int32] = [ - Bool.bridgeJSTypeID, - Int.bridgeJSTypeID, - Int8.bridgeJSTypeID, - UInt8.bridgeJSTypeID, - Int16.bridgeJSTypeID, - UInt16.bridgeJSTypeID, - Int32.bridgeJSTypeID, - UInt32.bridgeJSTypeID, - UInt.bridgeJSTypeID, - Int64.bridgeJSTypeID, - UInt64.bridgeJSTypeID, - Float.bridgeJSTypeID, - Double.bridgeJSTypeID, - String.bridgeJSTypeID, - JSValue.bridgeJSTypeID, JSCoordinate.bridgeJSTypeID, NestedStructGroupA.Metadata.bridgeJSTypeID, NestedStructGroupB.Metadata.bridgeJSTypeID, From 7f70e5c08570c070bc819febd699bcd25210713a Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 11 Aug 2026 14:51:19 +0200 Subject: [PATCH 4/6] BridgeJS: Hoist stack codecs into named module-scope helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two sites described the same stack ABI twice. Container element positions without a named codec emitted a local `const elemCodec = {lower, lift}` literal, re-declared at every lower/lift site, and the generic type-handle registration emitted an anonymous `{lower, lift}` literal per module type. Emit one named `{lower, lift}` helper per type shape at module scope instead, next to the combinators and the primitive codec table, and have both the element positions and the registration table reference it. Helpers for `@JS` structs and associated-value enums delegate to the existing `structHelpers`/`enumHelpers` entries rather than re-emitting their marshalling; the thin adapter is what lets a helper be a module-scope const even though those tables are populated later, in `createExports`. The associated-value enum combinator is gone: its adapter is now the type's helper. Composed codecs (`[T]`, `T?`, `[String: T]` and their nestings) are hoisted the same way and deduplicated across the whole glue, so a generated thunk no longer builds a codec on every call — previously each call ran e.g. `__bjs_dictCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lower(...)`. Helper names derived from type names are qualified with the declaring module, and composed names inherit that qualification from their element, so two modules declaring same-named `@JS` types cannot mint the same identifier. --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 86 ++- .../Sources/BridgeJSLink/JSGlueGen.swift | 204 ++++++-- .../BridgeJSLink/JSIntrinsicRegistry.swift | 39 ++ .../BridgeJSToolTests/BridgeJSLinkTests.swift | 9 +- .../NamedCodecHelperTests.swift | 105 ++++ .../__Snapshots__/BridgeJSLinkTests/Alias.js | 89 ++-- .../BridgeJSLinkTests/ArrayTypes.js | 488 +++++++----------- .../__Snapshots__/BridgeJSLinkTests/Async.js | 88 ++-- .../BridgeJSLinkTests/DefaultParameters.js | 55 +- .../BridgeJSLinkTests/DictionaryTypes.js | 100 ++-- .../BridgeJSLinkTests/EnumAssociatedValue.js | 217 ++++---- .../BridgeJSLinkTests/EnumRawType.js | 53 +- .../BridgeJSLinkTests/GenericImports.js | 107 ++-- .../BridgeJSLinkTests/ImportArray.js | 27 +- .../ImportedTypeInExportedInterface.js | 110 +--- .../BridgeJSLinkTests/JSValue.js | 25 +- .../BridgeJSLinkTests/Namespaces.Global.js | 34 +- .../BridgeJSLinkTests/Namespaces.js | 34 +- .../BridgeJSLinkTests/Optionals.js | 93 ++-- .../BridgeJSLinkTests/Protocol.js | 151 +----- .../BridgeJSLinkTests/SwiftClosure.js | 27 +- .../BridgeJSLinkTests/SwiftStruct.js | 103 ++-- .../BridgeJSLinkTests/SwiftStructImports.js | 23 +- 23 files changed, 1039 insertions(+), 1228 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index f7429f3d8..15d34eb2b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -420,22 +420,13 @@ public struct BridgeJSLink { ) } - /// Emits a `{ lower, lift }` codec literal for one bridgeable type. - /// `prefix` is prepended to the opening brace (e.g. an assignment) and - /// `suffix` is appended to the closing brace (e.g. `","` in an array). - private func appendGenericCodecLiteral( - type: BridgeType, - into printer: CodeFragmentPrinter, - prefix: String = "", - suffix: String = "," - ) throws { - try ContainerCodecJS.writeCodecLiteral( - type: type, - into: printer, - context: makeCodecPrintContext(printer: printer), - prefix: prefix, - suffix: suffix - ) + /// Returns the module-scope codec helper for one bridgeable type, declaring + /// it if this is the first reference. + /// + /// The registration table and the container combinators' element positions + /// go through the same helper, so a type's stack ABI is described once. + private func genericCodecReference(type: BridgeType, into printer: CodeFragmentPrinter) throws -> String { + try ContainerCodecJS.codecExpression(for: type, context: makeCodecPrintContext(printer: printer)) } /// Writes the body shared by every registration hook: verify the codec array @@ -509,10 +500,13 @@ public struct BridgeJSLink { printer.write("bjs[\"\(hookName)\"] = function(base, count) {") try printer.indent { // Same order as the module's Swift registration function. + let codecNames = try moduleEntries.map { + try genericCodecReference(type: $0.bridgeType, into: printer) + } printer.write("const codecs = [") - try printer.indent { - for entry in moduleEntries { - try appendGenericCodecLiteral(type: entry.bridgeType, into: printer) + printer.indent { + for name in codecNames { + printer.write("\(name),") } } printer.write("];") @@ -1303,6 +1297,18 @@ public struct BridgeJSLink { printer.nextLine() } + // The named codec helpers come after the intrinsics because they are + // built out of the combinators and the primitive codec table, and + // before everything that uses them: they are hoisted here so that no + // call site ever composes a codec. Helpers that delegate to the + // `structHelpers` / `enumHelpers` tables only read those tables when + // called, so declaring them ahead of the tables being populated is + // fine. + if intrinsicRegistry.hasNamedCodecs { + printer.write(lines: intrinsicRegistry.emitNamedCodecLines()) + printer.nextLine() + } + printer.write(lines: bodyPrinter.lines) } printer.indent() @@ -1406,12 +1412,54 @@ public struct BridgeJSLink { } } } + intrinsicRegistry.typeOwnerModules = collectTypeOwnerModules() let data = try collectLinkData() let outputJs = try generateJavaScript(data: data) let outputDts = generateTypeScript(data: data) return (outputJs, outputDts) } + /// Maps every type name a `BridgeType` can carry to the module that declares + /// it, so identifiers minted from type names can be module-qualified. + /// + /// A name declared by two modules is a pre-existing ambiguity in the + /// skeleton format (`BridgeType` carries only the name), so the first + /// declaration wins, which keeps the output deterministic. + private func collectTypeOwnerModules() -> [String: String] { + var result: [String: String] = [:] + func record(_ name: String, _ moduleName: String) { + if result[name] == nil { + result[name] = moduleName + } + } + for unified in skeletons { + let moduleName = unified.moduleName + if let skeleton = unified.exported { + for structDef in skeleton.structs { + record(structDef.name, moduleName) + record(structDef.abiName, moduleName) + } + for klass in skeleton.classes { + record(klass.name, moduleName) + record(klass.abiName, moduleName) + } + for enumDef in skeleton.enums { + record(enumDef.name, moduleName) + record(enumDef.abiName, moduleName) + } + for protocolDef in skeleton.protocols { + record(protocolDef.name, moduleName) + } + } + for file in unified.imported?.children ?? [] { + for type in file.types { + record(type.name, moduleName) + } + } + } + return result + } + private func enumHelperAssignments() -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 8da83fa18..f8b5d08a6 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -102,6 +102,17 @@ final class JSGlueVariableScope { try intrinsicRegistry.register(name: name, build: build) } + /// Registers a module-scope `{ lower, lift }` codec helper shared by every + /// site that needs a codec for the same type shape. + func registerNamedCodec(_ name: String, build: (CodeFragmentPrinter) throws -> Void) rethrows { + try intrinsicRegistry.registerNamedCodec(name: name, build: build) + } + + /// The module declaring `typeName`, when the link step knows it. + func moduleName(declaringType typeName: String) -> String? { + intrinsicRegistry.typeOwnerModules[typeName] + } + func makeChildScope() -> JSGlueVariableScope { JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry) } @@ -197,7 +208,9 @@ enum ContainerCodecJS { static let arrayCodec = "__bjs_arrayCodec" static let optionalCodec = "__bjs_optionalCodec" static let dictCodec = "__bjs_dictCodec" - static let enumCodec = "__bjs_enumCodec" + + /// Prefix of the module-scope codec helper `const`s. + static let namedCodecPrefix = "__bjs_codec_" private static let combinatorIntrinsicName = "containerCodecCombinators" private static let primitiveCodecIntrinsicName = "containerPrimitiveCodecs" @@ -271,18 +284,6 @@ enum ContainerCodecJS { " },", " };", "}", - // Adapts an associated-value enum helper (whose lower returns the case - // tag and whose lift takes it) to the plain stack codec protocol. - "function \(enumCodec)(helper) {", - " return {", - " lower(value) {", - " \(i32).push(helper.lower(value));", - " },", - " lift() {", - " return helper.lift(\(i32).pop());", - " },", - " };", - "}", ] } @@ -365,50 +366,145 @@ enum ContainerCodecJS { printer.write("}\(suffix)") } - /// Returns a JS expression evaluating to the `{ lower, lift }` codec for - /// one element type, registering the shared codec runtime as needed. May - /// write supporting statements (a local codec literal) to the context's - /// printer for element shapes without a named shared codec. + /// A codec that is reachable by name from module scope. + /// + /// `token` is the stable, module-qualified spelling of the type shape; codec + /// names for compositions are derived from their elements' tokens, so the + /// whole naming scheme inherits module qualification from its leaves. + struct NamedCodec { + let expression: String + let token: String + } + + /// Returns a JS expression evaluating to the `{ lower, lift }` codec for one + /// element type, registering the shared codec runtime as needed. + /// + /// Every codec is a module-scope `const`, so a call site never builds one: + /// the same type shape resolves to the same helper wherever it appears, + /// including the generic type-handle registration table. static func codecExpression( for elementType: BridgeType, context: IntrinsicJSFragment.PrintCodeContext ) throws -> String { + try namedCodec(for: elementType, context: context).expression + } + + static func namedCodec( + for elementType: BridgeType, + context: IntrinsicJSFragment.PrintCodeContext + ) throws -> NamedCodec { registerCombinators(scope: context.scope) try registerPrimitiveCodecs(context: context) let type = elementType.unaliased switch type { case .array(let element): - return "\(arrayCodec)(\(try codecExpression(for: element, context: context)))" + let element = try namedCodec(for: element, context: context) + return composedCodec( + token: "Array_\(element.token)", + factory: "\(arrayCodec)(\(element.expression))", + context: context + ) case .dictionary(let value): - return "\(dictCodec)(\(try codecExpression(for: value, context: context)))" + let value = try namedCodec(for: value, context: context) + return composedCodec( + token: "Dict_\(value.token)", + factory: "\(dictCodec)(\(value.expression))", + context: context + ) case .nullable(let wrapped, let kind): - let element = try codecExpression(for: wrapped, context: context) - return optionalCodecExpression(elementCodec: element, kind: kind) + let wrapped = try namedCodec(for: wrapped, context: context) + let prefix = kind == .null ? "Optional" : "UndefinedOr" + return composedCodec( + token: "\(prefix)_\(wrapped.token)", + factory: optionalCodecExpression(elementCodec: wrapped.expression, kind: kind), + context: context + ) case .string, .rawValueEnum(_, .string): - return JSGlueVariableScope.reservedStringCodec - case .swiftStruct(let fullName): - // `@JS` struct helpers already expose the codec protocol. - let base = fullName.replacingOccurrences(of: ".", with: "_") - return "\(JSGlueVariableScope.reservedStructHelpers).\(base)" - case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - return "\(enumCodec)(\(JSGlueVariableScope.reservedEnumHelpers).\(base))" + // A string-backed raw value enum bridges exactly as its raw value. + return NamedCodec(expression: JSGlueVariableScope.reservedStringCodec, token: "String") default: if let token = BridgeType.genericBridgeablePrimitives.first(where: { $0.type == type })?.token { - return "\(JSGlueVariableScope.reservedPrimitiveCodecs).\(token)" + return NamedCodec( + expression: "\(JSGlueVariableScope.reservedPrimitiveCodecs).\(token)", + token: token + ) } - // Element shapes without a named shared codec (case enums, non-string - // raw-value enums, JSObject, Swift heap objects, ...) get a local - // codec literal built from the same element stack fragments. - let codecVar = context.scope.variable("elemCodec") + return try leafCodec(for: type, context: context) + } + } + + /// Declares (once) a module-scope `const` holding a container combinator + /// instantiated with an already-declared element codec. + private static func composedCodec( + token: String, + factory: String, + context: IntrinsicJSFragment.PrintCodeContext + ) -> NamedCodec { + let name = "\(namedCodecPrefix)\(token)" + context.scope.registerNamedCodec(name) { printer in + printer.write("const \(name) = \(factory);") + } + return NamedCodec(expression: name, token: token) + } + + /// Declares (once) a module-scope `const` holding the codec for a type that + /// is not a container: primitives are handled by the shared table, so this + /// covers `@JS` structs, enums, classes, `JSObject`, protocols and friends. + /// + /// The body comes from ``writeCodecLiteral``, the same emitter the generic + /// type-handle registration uses, so both reference one helper per type. + private static func leafCodec( + for type: BridgeType, + context: IntrinsicJSFragment.PrintCodeContext + ) throws -> NamedCodec { + let token = leafToken(for: type, scope: context.scope) + let name = "\(namedCodecPrefix)\(token)" + // The helper lives at module scope, outside `createExports`, so exported + // Swift classes are not in lexical scope here and must be reached + // through `_exports`. + let hoistedContext = context.with(\.hasDirectAccessToSwiftClass, false) + try context.scope.registerNamedCodec(name) { printer in try writeCodecLiteral( type: type, - into: context.printer, - context: context, - prefix: "const \(codecVar) = ", + into: printer, + context: hoistedContext, + prefix: "const \(name) = ", suffix: ";" ) - return codecVar + } + return NamedCodec(expression: name, token: token) + } + + /// The module-qualified token identifying a non-container type shape. + /// + /// Types declared by a `@JS` module are qualified with the declaring module + /// so two modules declaring the same type name do not mint the same helper. + private static func leafToken(for type: BridgeType, scope: JSGlueVariableScope) -> String { + func sanitized(_ name: String) -> String { + String(name.map { $0.isLetter || $0.isNumber || $0 == "_" ? $0 : "_" }) + } + func qualified(_ name: String) -> String { + let base = sanitized(name) + guard let module = scope.moduleName(declaringType: name) ?? scope.moduleName(declaringType: base) else { + return base + } + return "\(sanitized(module))_\(base)" + } + switch type { + case .jsObject(nil): + return "JSObject" + case .jsObject(let name?): + return qualified(name) + case .swiftStruct(let name), + .swiftHeapObject(let name), + .swiftProtocol(let name), + .caseEnum(let name), + .rawValueEnum(let name, _), + .associatedValueEnum(let name), + .namespaceEnum(let name): + return qualified(name) + default: + return sanitized(type.mangleTypeName) } } } @@ -2033,8 +2129,8 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: ["arr"], printCode: { arguments, context in - let element = try ContainerCodecJS.codecExpression(for: elementType, context: context) - context.printer.write("\(ContainerCodecJS.arrayCodec)(\(element)).lower(\(arguments[0]));") + let codec = try ContainerCodecJS.codecExpression(for: .array(elementType), context: context) + context.printer.write("\(codec).lower(\(arguments[0]));") return [] } ) @@ -2045,8 +2141,8 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: ["dict"], printCode: { arguments, context in - let value = try ContainerCodecJS.codecExpression(for: valueType, context: context) - context.printer.write("\(ContainerCodecJS.dictCodec)(\(value)).lower(\(arguments[0]));") + let codec = try ContainerCodecJS.codecExpression(for: .dictionary(valueType), context: context) + context.printer.write("\(codec).lower(\(arguments[0]));") return [] } ) @@ -2057,11 +2153,9 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: [], printCode: { _, context in - let element = try ContainerCodecJS.codecExpression(for: elementType, context: context) + let codec = try ContainerCodecJS.codecExpression(for: .array(elementType), context: context) let resultVar = context.scope.variable("arrayResult") - context.printer.write( - "const \(resultVar) = \(ContainerCodecJS.arrayCodec)(\(element)).lift();" - ) + context.printer.write("const \(resultVar) = \(codec).lift();") return [resultVar] } ) @@ -2072,11 +2166,9 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: [], printCode: { _, context in - let value = try ContainerCodecJS.codecExpression(for: valueType, context: context) + let codec = try ContainerCodecJS.codecExpression(for: .dictionary(valueType), context: context) let resultVar = context.scope.variable("dictResult") - context.printer.write( - "const \(resultVar) = \(ContainerCodecJS.dictCodec)(\(value)).lift();" - ) + context.printer.write("const \(resultVar) = \(codec).lift();") return [resultVar] } ) @@ -2339,9 +2431,11 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: [], printCode: { _, context in - let element = try ContainerCodecJS.codecExpression(for: wrappedType, context: context) + let codec = try ContainerCodecJS.codecExpression( + for: .nullable(wrappedType, kind), + context: context + ) let resultVar = context.scope.variable("optValue") - let codec = ContainerCodecJS.optionalCodecExpression(elementCodec: element, kind: kind) context.printer.write("const \(resultVar) = \(codec).lift();") return [resultVar] } @@ -2358,8 +2452,10 @@ struct IntrinsicJSFragment: Sendable { return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in - let element = try ContainerCodecJS.codecExpression(for: wrappedType, context: context) - let codec = ContainerCodecJS.optionalCodecExpression(elementCodec: element, kind: kind) + let codec = try ContainerCodecJS.codecExpression( + for: .nullable(wrappedType, kind), + context: context + ) context.printer.write("\(codec).lower(\(arguments[0]));") return [] } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSIntrinsicRegistry.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSIntrinsicRegistry.swift index e3654e89f..5c6596bcf 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSIntrinsicRegistry.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSIntrinsicRegistry.swift @@ -7,6 +7,20 @@ final class JSIntrinsicRegistry { private var entries: [String: [String]] = [:] var classNamespaces: [String: [String]] = [:] + /// Maps a type name as carried by `BridgeType` (struct ABI name, class name, + /// enum name, ...) to the module that declares it, so generated identifiers + /// derived from type names can be module-qualified. + /// + /// The whole link output shares one JS scope, so two modules declaring a + /// same-named `@JS` type would otherwise mint the same identifier. + var typeOwnerModules: [String: String] = [:] + + /// Module-scope `{ lower, lift }` codec helpers, one per type shape, in + /// dependency order: a composed codec is appended after the codecs it is + /// built from, so the emitted `const`s can be evaluated top to bottom. + private var codecNameOrder: [String] = [] + private var codecBodies: [String: [String]] = [:] + var isEmpty: Bool { entries.isEmpty } @@ -18,9 +32,34 @@ final class JSIntrinsicRegistry { entries[name] = printer.lines } + /// Registers a named codec helper once per name. + /// + /// `build` may itself register the codecs this one is composed from; those + /// are appended first, which is what keeps the emitted declarations in a + /// valid evaluation order. + func registerNamedCodec(name: String, build: (CodeFragmentPrinter) throws -> Void) rethrows { + guard codecBodies[name] == nil else { return } + let printer = CodeFragmentPrinter() + try build(printer) + guard codecBodies[name] == nil else { return } + codecBodies[name] = printer.lines + codecNameOrder.append(name) + } + + var hasNamedCodecs: Bool { + !codecNameOrder.isEmpty + } + + func emitNamedCodecLines() -> [String] { + codecNameOrder.flatMap { codecBodies[$0] ?? [] } + } + func reset() { entries.removeAll() classNamespaces.removeAll() + typeOwnerModules.removeAll() + codecNameOrder.removeAll() + codecBodies.removeAll() } func emitLines() -> [String] { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index 6cc9162ca..3fd696027 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -179,7 +179,14 @@ import Testing // struct through the container stack ABI. let nonGenericJS = try linkedJS(forFixture: "SwiftStructImports.swift") #expect(!nonGenericJS.contains("__bjs_codecByTypeId")) - #expect(nonGenericJS.contains("__bjs_optionalCodec(structHelpers.Point)")) + // The composed codec is hoisted to a module-scope const, so the call site + // only reads it. + #expect( + nonGenericJS.contains( + "const __bjs_codec_Optional_TestModule_Point = __bjs_optionalCodec(__bjs_codec_TestModule_Point);" + ) + ) + #expect(nonGenericJS.contains("__bjs_codec_Optional_TestModule_Point.lower(ret);")) #expect(nonGenericJS.contains("__bjs_primitiveCodecs")) #expect(nonGenericJS.contains("bjs[\"bjs_TestModule_register_type_handles\"] = function() {};")) #expect(!nonGenericJS.contains("instance.exports[\"bjs_TestModule_register_type_handles\"]();")) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift new file mode 100644 index 000000000..4e73e02d7 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift @@ -0,0 +1,105 @@ +import Testing + +@testable import BridgeJSLink +@testable import BridgeJSSkeleton + +/// Every type shape gets one module-scope `{ lower, lift }` helper, shared by the +/// container combinators' element positions and by the generic type-handle +/// registration table, and composed codecs are hoisted so that no call site +/// builds one. +@Suite struct NamedCodecHelperTests { + private func codecDeclarations(in js: String) -> [String] { + js.split(separator: "\n") + .map { $0.trimmingCharacters(in: .whitespaces) } + .filter { $0.hasPrefix("const \(ContainerCodecJS.namedCodecPrefix)") } + } + + @Test + func composedCodecsAreHoistedAndReusedByCallSites() throws { + let js = try linkSource( + """ + @JS func mirror(_ values: [String: Int?]) -> [String: Int?] { values } + @JS func mirrorAgain(_ values: [String: Int?]) -> [String: Int?] { values } + """ + ).js + + // Declared once, at module scope, out of the thunks. + #expect( + codecDeclarations(in: js) == [ + "const __bjs_codec_Optional_Int = __bjs_optionalCodec(__bjs_primitiveCodecs.Int);", + "const __bjs_codec_Dict_Optional_Int = __bjs_dictCodec(__bjs_codec_Optional_Int);", + ] + ) + // Call sites only read the helper; they never compose one. + #expect(js.contains("__bjs_codec_Dict_Optional_Int.lower(values);")) + #expect(js.contains("__bjs_codec_Dict_Optional_Int.lift();")) + let composedAtCallSite = js.contains("__bjs_dictCodec(__bjs_optionalCodec(") + #expect(!composedAtCallSite) + } + + @Test + func helperNamesAreQualifiedWithTheDeclaringModule() throws { + let js = try linkSource( + """ + @JS struct Point { + var x: Int + @JS init(x: Int) { self.x = x } + } + @JS func mirror(_ points: [Point]) -> [Point] { points } + """, + moduleName: "Core" + ).js + + #expect(js.contains("const __bjs_codec_Core_Point = {")) + #expect(js.contains("const __bjs_codec_Array_Core_Point = __bjs_arrayCodec(__bjs_codec_Core_Point);")) + } + + /// The type-table entry and the element position of a container must resolve + /// to the same helper, so a type's stack ABI is described exactly once. + @Test + func registrationTableReusesTheSameHelperAsElementPositions() throws { + let js = try linkSource( + """ + @JS struct Point { + var x: Int + @JS init(x: Int) { self.x = x } + } + @JS func mirror(_ points: [Point]) -> [Point] { points } + @JSClass struct Consumer { + @JSFunction func identity(_ value: T) throws(JSException) -> T + } + """, + moduleName: "Core" + ).js + + #expect(js.contains("const __bjs_codec_Core_Point = {")) + #expect(js.contains("const __bjs_codec_Array_Core_Point = __bjs_arrayCodec(__bjs_codec_Core_Point);")) + // One entry in the registration array, referencing the same helper. + let registrationArray = + js + .components(separatedBy: "bjs[\"bjs_Core_register_type_handles\"] = function(base, count) {") + .last + .map { $0.components(separatedBy: "];")[0] } + #expect(registrationArray?.contains("__bjs_codec_Core_Point,") == true) + // The struct's marshalling code is emitted once, in its helper factory. + #expect(js.components(separatedBy: "structHelpers.Point.lower(v);").count - 1 == 1) + } + + /// A string-backed raw value enum bridges exactly as `String`, so it shares + /// the string codec instead of minting a redundant helper. + @Test + func stringBackedRawValueEnumsShareTheStringCodec() throws { + let js = try linkSource( + """ + @JS enum Mode: String { + case light + case dark + } + @JS func mirror(_ modes: [Mode]) -> [Mode] { modes } + """ + ).js + + #expect(js.contains("const __bjs_codec_Array_String = __bjs_arrayCodec(__bjs_stringCodec);")) + #expect(!js.contains("__bjs_codec_TestModule_Mode")) + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js index c9c09bd97..fff8779ef 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js @@ -99,16 +99,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -347,6 +337,43 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_PolygonReference = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['PolygonReference'].__construct(ptr); + return obj; + }, + }; + const __bjs_codec_Array_TestModule_PolygonReference = __bjs_arrayCodec(__bjs_codec_TestModule_PolygonReference); + const __bjs_codec_TestModule_InnerTag = { + lower: (v) => { + const caseId = enumHelpers.InnerTag.lower(v); + i32Stack.push(caseId); + }, + lift: () => { + const enumValue = enumHelpers.InnerTag.lift(i32Stack.pop()); + return enumValue; + }, + }; + const __bjs_codec_Optional_TestModule_InnerTag = __bjs_optionalCodec(__bjs_codec_TestModule_InnerTag); + const __bjs_codec_Array_Optional_TestModule_InnerTag = __bjs_arrayCodec(__bjs_codec_Optional_TestModule_InnerTag); + const __bjs_codec_TestModule_Surface = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Optional_TestModule_Surface = __bjs_optionalCodec(__bjs_codec_TestModule_Surface); + const __bjs_createInnerTagValuesHelpers = () => ({ lower: (value) => { const enumTag = value.tag; @@ -596,19 +623,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_produceOptionalCanvas"] = function bjs_produceOptionalCanvas() { try { let ret = imports.produceOptionalCanvas(); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_optionalCodec(elemCodec).lower(ret); + __bjs_codec_Optional_TestModule_Surface.lower(ret); } catch (error) { setException(error); } @@ -759,29 +774,9 @@ export async function createInstantiator(options, swift) { return optResult; }, polygonArray: function bjs_polygonArray(polygons) { - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = PolygonReference.__construct(ptr); - return obj; - }, - }; - __bjs_arrayCodec(elemCodec).lower(polygons); + __bjs_codec_Array_TestModule_PolygonReference.lower(polygons); instance.exports.bjs_polygonArray(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = PolygonReference.__construct(ptr); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_TestModule_PolygonReference.lift(); return arrayResult; }, validatePolygon: function bjs_validatePolygon(polygon) { @@ -801,9 +796,9 @@ export async function createInstantiator(options, swift) { return TagReference.__construct(ret); }, roundtripTags: function bjs_roundtripTags(xs) { - __bjs_arrayCodec(__bjs_optionalCodec(__bjs_enumCodec(enumHelpers.InnerTag))).lower(xs); + __bjs_codec_Array_Optional_TestModule_InnerTag.lower(xs); instance.exports.bjs_roundtripTags(); - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_enumCodec(enumHelpers.InnerTag))).lift(); + const arrayResult = __bjs_codec_Array_Optional_TestModule_InnerTag.lift(); return arrayResult; }, describeUser: function bjs_describeUser(owner) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index 86a84490e..e038620c1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -106,16 +106,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -354,6 +344,114 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Array_String = __bjs_arrayCodec(__bjs_stringCodec); + const __bjs_codec_Array_Double = __bjs_arrayCodec(__bjs_primitiveCodecs.Double); + const __bjs_codec_Array_Bool = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool); + const __bjs_codec_TestModule_Point = { + lower: (v) => { + structHelpers.Point.lower(v); + }, + lift: () => { + const struct = structHelpers.Point.lift(); + return struct; + }, + }; + const __bjs_codec_Array_TestModule_Point = __bjs_arrayCodec(__bjs_codec_TestModule_Point); + const __bjs_codec_TestModule_Direction = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const __bjs_codec_Array_TestModule_Direction = __bjs_arrayCodec(__bjs_codec_TestModule_Direction); + const __bjs_codec_TestModule_Status = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const rawValue = i32Stack.pop(); + return rawValue; + }, + }; + const __bjs_codec_Array_TestModule_Status = __bjs_arrayCodec(__bjs_codec_TestModule_Status); + const __bjs_codec_Surp = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + const __bjs_codec_Array_Surp = __bjs_arrayCodec(__bjs_codec_Surp); + const __bjs_codec_Sumrp = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + const __bjs_codec_Array_Sumrp = __bjs_arrayCodec(__bjs_codec_Sumrp); + const __bjs_codec_Sop = { + lower: (v) => { + ptrStack.push((v | 0)); + }, + lift: () => { + const pointer = ptrStack.pop(); + return pointer; + }, + }; + const __bjs_codec_Array_Sop = __bjs_arrayCodec(__bjs_codec_Sop); + const __bjs_codec_Optional_Int = __bjs_optionalCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Array_Optional_Int = __bjs_arrayCodec(__bjs_codec_Optional_Int); + const __bjs_codec_Optional_String = __bjs_optionalCodec(__bjs_stringCodec); + const __bjs_codec_Array_Optional_String = __bjs_arrayCodec(__bjs_codec_Optional_String); + const __bjs_codec_Optional_Array_Int = __bjs_optionalCodec(__bjs_codec_Array_Int); + const __bjs_codec_Optional_TestModule_Point = __bjs_optionalCodec(__bjs_codec_TestModule_Point); + const __bjs_codec_Array_Optional_TestModule_Point = __bjs_arrayCodec(__bjs_codec_Optional_TestModule_Point); + const __bjs_codec_Optional_TestModule_Direction = __bjs_optionalCodec(__bjs_codec_TestModule_Direction); + const __bjs_codec_Array_Optional_TestModule_Direction = __bjs_arrayCodec(__bjs_codec_Optional_TestModule_Direction); + const __bjs_codec_Optional_TestModule_Status = __bjs_optionalCodec(__bjs_codec_TestModule_Status); + const __bjs_codec_Array_Optional_TestModule_Status = __bjs_arrayCodec(__bjs_codec_Optional_TestModule_Status); + const __bjs_codec_Array_Array_Int = __bjs_arrayCodec(__bjs_codec_Array_Int); + const __bjs_codec_Array_Array_String = __bjs_arrayCodec(__bjs_codec_Array_String); + const __bjs_codec_Array_Array_TestModule_Point = __bjs_arrayCodec(__bjs_codec_Array_TestModule_Point); + const __bjs_codec_TestModule_Item = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['Item'].__construct(ptr); + return obj; + }, + }; + const __bjs_codec_Array_TestModule_Item = __bjs_arrayCodec(__bjs_codec_TestModule_Item); + const __bjs_codec_Array_Array_TestModule_Item = __bjs_arrayCodec(__bjs_codec_Array_TestModule_Item); + const __bjs_codec_JSObject = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Array_JSObject = __bjs_arrayCodec(__bjs_codec_JSObject); + const __bjs_codec_Optional_JSObject = __bjs_optionalCodec(__bjs_codec_JSObject); + const __bjs_codec_Array_Optional_JSObject = __bjs_arrayCodec(__bjs_codec_Optional_JSObject); + const __bjs_codec_Array_Array_JSObject = __bjs_arrayCodec(__bjs_codec_Array_JSObject); + const __bjs_codec_Optional_Array_String = __bjs_optionalCodec(__bjs_codec_Array_String); + const __bjs_createPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -576,7 +674,7 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_importProcessNumbers"] = function bjs_importProcessNumbers() { try { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); + const arrayResult = __bjs_codec_Array_Double.lift(); imports.importProcessNumbers(arrayResult); } catch (error) { setException(error); @@ -585,34 +683,34 @@ export async function createInstantiator(options, swift) { TestModule["bjs_importGetNumbers"] = function bjs_importGetNumbers() { try { let ret = imports.importGetNumbers(); - __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(ret); + __bjs_codec_Array_Double.lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importTransformNumbers"] = function bjs_importTransformNumbers() { try { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); + const arrayResult = __bjs_codec_Array_Double.lift(); let ret = imports.importTransformNumbers(arrayResult); - __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(ret); + __bjs_codec_Array_Double.lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importProcessStrings"] = function bjs_importProcessStrings() { try { - const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); + const arrayResult = __bjs_codec_Array_String.lift(); let ret = imports.importProcessStrings(arrayResult); - __bjs_arrayCodec(__bjs_stringCodec).lower(ret); + __bjs_codec_Array_String.lower(ret); } catch (error) { setException(error); } } TestModule["bjs_importProcessBooleans"] = function bjs_importProcessBooleans() { try { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); + const arrayResult = __bjs_codec_Array_Bool.lift(); let ret = imports.importProcessBooleans(arrayResult); - __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(ret); + __bjs_codec_Array_Bool.lower(ret); } catch (error) { setException(error); } @@ -695,19 +793,19 @@ export async function createInstantiator(options, swift) { } constructor(nums, strs) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(nums); - __bjs_arrayCodec(__bjs_stringCodec).lower(strs); + __bjs_codec_Array_Int.lower(nums); + __bjs_codec_Array_String.lower(strs); const ret = instance.exports.bjs_MultiArrayContainer_init(); return MultiArrayContainer.__construct(ret); } get numbers() { instance.exports.bjs_MultiArrayContainer_numbers_get(this.pointer); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); return arrayResult; } get strings() { instance.exports.bjs_MultiArrayContainer_strings_get(this.pointer); - const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); + const arrayResult = __bjs_codec_Array_String.lift(); return arrayResult; } } @@ -716,90 +814,54 @@ export async function createInstantiator(options, swift) { const exports = { processIntArray: function bjs_processIntArray(values) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); + __bjs_codec_Array_Int.lower(values); instance.exports.bjs_processIntArray(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); return arrayResult; }, processStringArray: function bjs_processStringArray(values) { - __bjs_arrayCodec(__bjs_stringCodec).lower(values); + __bjs_codec_Array_String.lower(values); instance.exports.bjs_processStringArray(); - const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); + const arrayResult = __bjs_codec_Array_String.lift(); return arrayResult; }, processDoubleArray: function bjs_processDoubleArray(values) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(values); + __bjs_codec_Array_Double.lower(values); instance.exports.bjs_processDoubleArray(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); + const arrayResult = __bjs_codec_Array_Double.lift(); return arrayResult; }, processBoolArray: function bjs_processBoolArray(values) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(values); + __bjs_codec_Array_Bool.lower(values); instance.exports.bjs_processBoolArray(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); + const arrayResult = __bjs_codec_Array_Bool.lift(); return arrayResult; }, processPointArray: function bjs_processPointArray(points) { - __bjs_arrayCodec(structHelpers.Point).lower(points); + __bjs_codec_Array_TestModule_Point.lower(points); instance.exports.bjs_processPointArray(); - const arrayResult = __bjs_arrayCodec(structHelpers.Point).lift(); + const arrayResult = __bjs_codec_Array_TestModule_Point.lift(); return arrayResult; }, processDirectionArray: function bjs_processDirectionArray(directions) { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - __bjs_arrayCodec(elemCodec).lower(directions); + __bjs_codec_Array_TestModule_Direction.lower(directions); instance.exports.bjs_processDirectionArray(); - const elemCodec1 = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_TestModule_Direction.lift(); return arrayResult; }, processStatusArray: function bjs_processStatusArray(statuses) { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const rawValue = i32Stack.pop(); - return rawValue; - }, - }; - __bjs_arrayCodec(elemCodec).lower(statuses); + __bjs_codec_Array_TestModule_Status.lower(statuses); instance.exports.bjs_processStatusArray(); - const elemCodec1 = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const rawValue = i32Stack.pop(); - return rawValue; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_TestModule_Status.lift(); return arrayResult; }, sumIntArray: function bjs_sumIntArray(values) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); + __bjs_codec_Array_Int.lower(values); const ret = instance.exports.bjs_sumIntArray(); return ret; }, findFirstPoint: function bjs_findFirstPoint(points, matching) { - __bjs_arrayCodec(structHelpers.Point).lower(points); + __bjs_codec_Array_TestModule_Point.lower(points); const matchingBytes = textEncoder.encode(matching); const matchingId = swift.memory.retain(matchingBytes); instance.exports.bjs_findFirstPoint(matchingId, matchingBytes.length); @@ -807,318 +869,116 @@ export async function createInstantiator(options, swift) { return structValue; }, processUnsafeRawPointerArray: function bjs_processUnsafeRawPointerArray(values) { - const elemCodec = { - lower: (v) => { - ptrStack.push((v | 0)); - }, - lift: () => { - const pointer = ptrStack.pop(); - return pointer; - }, - }; - __bjs_arrayCodec(elemCodec).lower(values); + __bjs_codec_Array_Surp.lower(values); instance.exports.bjs_processUnsafeRawPointerArray(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push((v | 0)); - }, - lift: () => { - const pointer = ptrStack.pop(); - return pointer; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_Surp.lift(); return arrayResult; }, processUnsafeMutableRawPointerArray: function bjs_processUnsafeMutableRawPointerArray(values) { - const elemCodec = { - lower: (v) => { - ptrStack.push((v | 0)); - }, - lift: () => { - const pointer = ptrStack.pop(); - return pointer; - }, - }; - __bjs_arrayCodec(elemCodec).lower(values); + __bjs_codec_Array_Sumrp.lower(values); instance.exports.bjs_processUnsafeMutableRawPointerArray(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push((v | 0)); - }, - lift: () => { - const pointer = ptrStack.pop(); - return pointer; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_Sumrp.lift(); return arrayResult; }, processOpaquePointerArray: function bjs_processOpaquePointerArray(values) { - const elemCodec = { - lower: (v) => { - ptrStack.push((v | 0)); - }, - lift: () => { - const pointer = ptrStack.pop(); - return pointer; - }, - }; - __bjs_arrayCodec(elemCodec).lower(values); + __bjs_codec_Array_Sop.lower(values); instance.exports.bjs_processOpaquePointerArray(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push((v | 0)); - }, - lift: () => { - const pointer = ptrStack.pop(); - return pointer; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_Sop.lift(); return arrayResult; }, processOptionalIntArray: function bjs_processOptionalIntArray(values) { - __bjs_arrayCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lower(values); + __bjs_codec_Array_Optional_Int.lower(values); instance.exports.bjs_processOptionalIntArray(); - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lift(); + const arrayResult = __bjs_codec_Array_Optional_Int.lift(); return arrayResult; }, processOptionalStringArray: function bjs_processOptionalStringArray(values) { - __bjs_arrayCodec(__bjs_optionalCodec(__bjs_stringCodec)).lower(values); + __bjs_codec_Array_Optional_String.lower(values); instance.exports.bjs_processOptionalStringArray(); - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(__bjs_stringCodec)).lift(); + const arrayResult = __bjs_codec_Array_Optional_String.lift(); return arrayResult; }, processOptionalArray: function bjs_processOptionalArray(values) { - __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); + __bjs_codec_Optional_Array_Int.lower(values); instance.exports.bjs_processOptionalArray(); - const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); + const optValue = __bjs_codec_Optional_Array_Int.lift(); return optValue; }, processOptionalPointArray: function bjs_processOptionalPointArray(points) { - __bjs_arrayCodec(__bjs_optionalCodec(structHelpers.Point)).lower(points); + __bjs_codec_Array_Optional_TestModule_Point.lower(points); instance.exports.bjs_processOptionalPointArray(); - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(structHelpers.Point)).lift(); + const arrayResult = __bjs_codec_Array_Optional_TestModule_Point.lift(); return arrayResult; }, processOptionalDirectionArray: function bjs_processOptionalDirectionArray(directions) { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(directions); + __bjs_codec_Array_Optional_TestModule_Direction.lower(directions); instance.exports.bjs_processOptionalDirectionArray(); - const elemCodec1 = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); + const arrayResult = __bjs_codec_Array_Optional_TestModule_Direction.lift(); return arrayResult; }, processOptionalStatusArray: function bjs_processOptionalStatusArray(statuses) { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const rawValue = i32Stack.pop(); - return rawValue; - }, - }; - __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(statuses); + __bjs_codec_Array_Optional_TestModule_Status.lower(statuses); instance.exports.bjs_processOptionalStatusArray(); - const elemCodec1 = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const rawValue = i32Stack.pop(); - return rawValue; - }, - }; - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); + const arrayResult = __bjs_codec_Array_Optional_TestModule_Status.lift(); return arrayResult; }, processNestedIntArray: function bjs_processNestedIntArray(values) { - __bjs_arrayCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); + __bjs_codec_Array_Array_Int.lower(values); instance.exports.bjs_processNestedIntArray(); - const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); + const arrayResult = __bjs_codec_Array_Array_Int.lift(); return arrayResult; }, processNestedStringArray: function bjs_processNestedStringArray(values) { - __bjs_arrayCodec(__bjs_arrayCodec(__bjs_stringCodec)).lower(values); + __bjs_codec_Array_Array_String.lower(values); instance.exports.bjs_processNestedStringArray(); - const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(__bjs_stringCodec)).lift(); + const arrayResult = __bjs_codec_Array_Array_String.lift(); return arrayResult; }, processNestedPointArray: function bjs_processNestedPointArray(points) { - __bjs_arrayCodec(__bjs_arrayCodec(structHelpers.Point)).lower(points); + __bjs_codec_Array_Array_TestModule_Point.lower(points); instance.exports.bjs_processNestedPointArray(); - const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(structHelpers.Point)).lift(); + const arrayResult = __bjs_codec_Array_Array_TestModule_Point.lift(); return arrayResult; }, processItemArray: function bjs_processItemArray(items) { - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - return obj; - }, - }; - __bjs_arrayCodec(elemCodec).lower(items); + __bjs_codec_Array_TestModule_Item.lower(items); instance.exports.bjs_processItemArray(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_TestModule_Item.lift(); return arrayResult; }, processNestedItemArray: function bjs_processNestedItemArray(items) { - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - return obj; - }, - }; - __bjs_arrayCodec(__bjs_arrayCodec(elemCodec)).lower(items); + __bjs_codec_Array_Array_TestModule_Item.lower(items); instance.exports.bjs_processNestedItemArray(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(elemCodec1)).lift(); + const arrayResult = __bjs_codec_Array_Array_TestModule_Item.lift(); return arrayResult; }, processJSObjectArray: function bjs_processJSObjectArray(objects) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(elemCodec).lower(objects); + __bjs_codec_Array_JSObject.lower(objects); instance.exports.bjs_processJSObjectArray(); - const elemCodec1 = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_JSObject.lift(); return arrayResult; }, processOptionalJSObjectArray: function bjs_processOptionalJSObjectArray(objects) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(objects); + __bjs_codec_Array_Optional_JSObject.lower(objects); instance.exports.bjs_processOptionalJSObjectArray(); - const elemCodec1 = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); + const arrayResult = __bjs_codec_Array_Optional_JSObject.lift(); return arrayResult; }, processNestedJSObjectArray: function bjs_processNestedJSObjectArray(objects) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(__bjs_arrayCodec(elemCodec)).lower(objects); + __bjs_codec_Array_Array_JSObject.lower(objects); instance.exports.bjs_processNestedJSObjectArray(); - const elemCodec1 = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(__bjs_arrayCodec(elemCodec1)).lift(); + const arrayResult = __bjs_codec_Array_Array_JSObject.lift(); return arrayResult; }, multiArrayParams: function bjs_multiArrayParams(nums, strs) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(nums); - __bjs_arrayCodec(__bjs_stringCodec).lower(strs); + __bjs_codec_Array_Int.lower(nums); + __bjs_codec_Array_String.lower(strs); const ret = instance.exports.bjs_multiArrayParams(); return ret; }, multiOptionalArrayParams: function bjs_multiOptionalArrayParams(a, b) { - __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(a); - __bjs_optionalCodec(__bjs_arrayCodec(__bjs_stringCodec)).lower(b); + __bjs_codec_Optional_Array_Int.lower(a); + __bjs_codec_Optional_Array_String.lower(b); const ret = instance.exports.bjs_multiOptionalArrayParams(); return ret; }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 4b3e0c3ed..7bd19602d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -103,16 +103,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -351,6 +341,30 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_AsyncPoint = { + lower: (v) => { + structHelpers.AsyncPoint.lower(v); + }, + lift: () => { + const struct = structHelpers.AsyncPoint.lift(); + return struct; + }, + }; + const __bjs_codec_Optional_TestModule_AsyncPoint = __bjs_optionalCodec(__bjs_codec_TestModule_AsyncPoint); + const __bjs_codec_Array_TestModule_AsyncPoint = __bjs_arrayCodec(__bjs_codec_TestModule_AsyncPoint); + const __bjs_codec_TestModule_AsyncDirection = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const __bjs_codec_Array_TestModule_AsyncDirection = __bjs_arrayCodec(__bjs_codec_TestModule_AsyncDirection); + const __bjs_codec_Dict_TestModule_AsyncPoint = __bjs_dictCodec(__bjs_codec_TestModule_AsyncPoint); + const __bjs_codec_Dict_TestModule_AsyncDirection = __bjs_dictCodec(__bjs_codec_TestModule_AsyncDirection); + const __bjs_createAsyncPointHelpers = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); @@ -563,7 +577,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_Sa10AsyncPointV"] = function(promise) { try { - const arrayResult = __bjs_arrayCodec(structHelpers.AsyncPoint).lift(); + const arrayResult = __bjs_codec_Array_TestModule_AsyncPoint.lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); } catch (error) { setException(error); @@ -571,16 +585,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_Sa14AsyncDirectionO"] = function(promise) { try { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec).lift(); + const arrayResult = __bjs_codec_Array_TestModule_AsyncDirection.lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); } catch (error) { setException(error); @@ -588,7 +593,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_SD10AsyncPointV"] = function(promise) { try { - const dictResult = __bjs_dictCodec(structHelpers.AsyncPoint).lift(); + const dictResult = __bjs_codec_Dict_TestModule_AsyncPoint.lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); } catch (error) { setException(error); @@ -596,16 +601,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_SD14AsyncDirectionO"] = function(promise) { try { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - const dictResult = __bjs_dictCodec(elemCodec).lift(); + const dictResult = __bjs_codec_Dict_TestModule_AsyncDirection.lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); } catch (error) { setException(error); @@ -850,53 +846,35 @@ export async function createInstantiator(options, swift) { return ret1; }, asyncRoundTripOptionalStruct: function bjs_asyncRoundTripOptionalStruct(v) { - __bjs_optionalCodec(structHelpers.AsyncPoint).lower(v); + __bjs_codec_Optional_TestModule_AsyncPoint.lower(v); const ret = instance.exports.bjs_asyncRoundTripOptionalStruct(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripStructArray: function bjs_asyncRoundTripStructArray(v) { - __bjs_arrayCodec(structHelpers.AsyncPoint).lower(v); + __bjs_codec_Array_TestModule_AsyncPoint.lower(v); const ret = instance.exports.bjs_asyncRoundTripStructArray(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripEnumArray: function bjs_asyncRoundTripEnumArray(v) { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - __bjs_arrayCodec(elemCodec).lower(v); + __bjs_codec_Array_TestModule_AsyncDirection.lower(v); const ret = instance.exports.bjs_asyncRoundTripEnumArray(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripStructDictionary: function bjs_asyncRoundTripStructDictionary(v) { - __bjs_dictCodec(structHelpers.AsyncPoint).lower(v); + __bjs_codec_Dict_TestModule_AsyncPoint.lower(v); const ret = instance.exports.bjs_asyncRoundTripStructDictionary(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripEnumDictionary: function bjs_asyncRoundTripEnumDictionary(v) { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - __bjs_dictCodec(elemCodec).lower(v); + __bjs_codec_Dict_TestModule_AsyncDirection.lower(v); const ret = instance.exports.bjs_asyncRoundTripEnumDictionary(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index ac3a508da..ef00bad23 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -99,16 +99,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -347,6 +337,21 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_Config = { + lower: (v) => { + structHelpers.Config.lower(v); + }, + lift: () => { + const struct = structHelpers.Config.lift(); + return struct; + }, + }; + const __bjs_codec_Optional_TestModule_Config = __bjs_optionalCodec(__bjs_codec_TestModule_Config); + const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Array_String = __bjs_arrayCodec(__bjs_stringCodec); + const __bjs_codec_Array_Double = __bjs_arrayCodec(__bjs_primitiveCodecs.Double); + const __bjs_codec_Array_Bool = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool); + const __bjs_createConfigHelpers = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); @@ -847,51 +852,51 @@ export async function createInstantiator(options, swift) { return EmptyGreeter.__construct(ret); }, testOptionalStructDefault: function bjs_testOptionalStructDefault(point = null) { - __bjs_optionalCodec(structHelpers.Config).lower(point); + __bjs_codec_Optional_TestModule_Config.lower(point); instance.exports.bjs_testOptionalStructDefault(); - const optValue = __bjs_optionalCodec(structHelpers.Config).lift(); + const optValue = __bjs_codec_Optional_TestModule_Config.lift(); return optValue; }, testOptionalStructWithValueDefault: function bjs_testOptionalStructWithValueDefault(point = { name: "default", value: 42, enabled: true }) { - __bjs_optionalCodec(structHelpers.Config).lower(point); + __bjs_codec_Optional_TestModule_Config.lower(point); instance.exports.bjs_testOptionalStructWithValueDefault(); - const optValue = __bjs_optionalCodec(structHelpers.Config).lift(); + const optValue = __bjs_codec_Optional_TestModule_Config.lift(); return optValue; }, testIntArrayDefault: function bjs_testIntArrayDefault(values = [1, 2, 3]) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); + __bjs_codec_Array_Int.lower(values); instance.exports.bjs_testIntArrayDefault(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); return arrayResult; }, testStringArrayDefault: function bjs_testStringArrayDefault(names = ["a", "b", "c"]) { - __bjs_arrayCodec(__bjs_stringCodec).lower(names); + __bjs_codec_Array_String.lower(names); instance.exports.bjs_testStringArrayDefault(); - const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); + const arrayResult = __bjs_codec_Array_String.lift(); return arrayResult; }, testDoubleArrayDefault: function bjs_testDoubleArrayDefault(values = [1.5, 2.5, 3.5]) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lower(values); + __bjs_codec_Array_Double.lower(values); instance.exports.bjs_testDoubleArrayDefault(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Double).lift(); + const arrayResult = __bjs_codec_Array_Double.lift(); return arrayResult; }, testBoolArrayDefault: function bjs_testBoolArrayDefault(flags = [true, false, true]) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lower(flags); + __bjs_codec_Array_Bool.lower(flags); instance.exports.bjs_testBoolArrayDefault(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool).lift(); + const arrayResult = __bjs_codec_Array_Bool.lift(); return arrayResult; }, testEmptyArrayDefault: function bjs_testEmptyArrayDefault(items = []) { - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(items); + __bjs_codec_Array_Int.lower(items); instance.exports.bjs_testEmptyArrayDefault(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); return arrayResult; }, testMixedWithArrayDefault: function bjs_testMixedWithArrayDefault(name = "test", values = [10, 20, 30], enabled = true) { const nameBytes = textEncoder.encode(name); const nameId = swift.memory.retain(nameBytes); - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(values); + __bjs_codec_Array_Int.lower(values); instance.exports.bjs_testMixedWithArrayDefault(nameId, nameBytes.length, enabled); const ret = tmpRetString; tmpRetString = undefined; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 2ddf3e217..74d9e7e59 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,16 +331,38 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_Dict_Int = __bjs_dictCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Dict_String = __bjs_dictCodec(__bjs_stringCodec); + const __bjs_codec_Optional_Dict_String = __bjs_optionalCodec(__bjs_codec_Dict_String); + const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Dict_Array_Int = __bjs_dictCodec(__bjs_codec_Array_Int); + const __bjs_codec_TestModule_Box = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['Box'].__construct(ptr); + return obj; + }, + }; + const __bjs_codec_Dict_TestModule_Box = __bjs_dictCodec(__bjs_codec_TestModule_Box); + const __bjs_codec_Optional_TestModule_Box = __bjs_optionalCodec(__bjs_codec_TestModule_Box); + const __bjs_codec_Dict_Optional_TestModule_Box = __bjs_dictCodec(__bjs_codec_Optional_TestModule_Box); + const __bjs_codec_Dict_Double = __bjs_dictCodec(__bjs_primitiveCodecs.Double); + const __bjs_codec_Optional_Int = __bjs_optionalCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Dict_Optional_Int = __bjs_dictCodec(__bjs_codec_Optional_Int); + const __bjs_createCountersHelpers = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - __bjs_dictCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lower(value.counts); + __bjs_codec_Dict_Optional_Int.lower(value.counts); }, lift: () => { - const dictResult = __bjs_dictCodec(__bjs_optionalCodec(__bjs_primitiveCodecs.Int)).lift(); + const dictResult = __bjs_codec_Dict_Optional_Int.lift(); const string = strStack.pop(); return { name: string, counts: dictResult }; } @@ -548,9 +560,9 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_importMirrorDictionary"] = function bjs_importMirrorDictionary() { try { - const dictResult = __bjs_dictCodec(__bjs_primitiveCodecs.Double).lift(); + const dictResult = __bjs_codec_Dict_Double.lift(); let ret = imports.importMirrorDictionary(dictResult); - __bjs_dictCodec(__bjs_primitiveCodecs.Double).lower(ret); + __bjs_codec_Dict_Double.lower(ret); } catch (error) { setException(error); } @@ -632,73 +644,33 @@ export async function createInstantiator(options, swift) { const exports = { mirrorDictionary: function bjs_mirrorDictionary(values) { - __bjs_dictCodec(__bjs_primitiveCodecs.Int).lower(values); + __bjs_codec_Dict_Int.lower(values); instance.exports.bjs_mirrorDictionary(); - const dictResult = __bjs_dictCodec(__bjs_primitiveCodecs.Int).lift(); + const dictResult = __bjs_codec_Dict_Int.lift(); return dictResult; }, optionalDictionary: function bjs_optionalDictionary(values) { - __bjs_optionalCodec(__bjs_dictCodec(__bjs_stringCodec)).lower(values); + __bjs_codec_Optional_Dict_String.lower(values); instance.exports.bjs_optionalDictionary(); - const optValue = __bjs_optionalCodec(__bjs_dictCodec(__bjs_stringCodec)).lift(); + const optValue = __bjs_codec_Optional_Dict_String.lift(); return optValue; }, nestedDictionary: function bjs_nestedDictionary(values) { - __bjs_dictCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(values); + __bjs_codec_Dict_Array_Int.lower(values); instance.exports.bjs_nestedDictionary(); - const dictResult = __bjs_dictCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); + const dictResult = __bjs_codec_Dict_Array_Int.lift(); return dictResult; }, boxDictionary: function bjs_boxDictionary(boxes) { - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Box.__construct(ptr); - return obj; - }, - }; - __bjs_dictCodec(elemCodec).lower(boxes); + __bjs_codec_Dict_TestModule_Box.lower(boxes); instance.exports.bjs_boxDictionary(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Box.__construct(ptr); - return obj; - }, - }; - const dictResult = __bjs_dictCodec(elemCodec1).lift(); + const dictResult = __bjs_codec_Dict_TestModule_Box.lift(); return dictResult; }, optionalBoxDictionary: function bjs_optionalBoxDictionary(boxes) { - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Box.__construct(ptr); - return obj; - }, - }; - __bjs_dictCodec(__bjs_optionalCodec(elemCodec)).lower(boxes); + __bjs_codec_Dict_Optional_TestModule_Box.lower(boxes); instance.exports.bjs_optionalBoxDictionary(); - const elemCodec1 = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Box.__construct(ptr); - return obj; - }, - }; - const dictResult = __bjs_dictCodec(__bjs_optionalCodec(elemCodec1)).lift(); + const dictResult = __bjs_codec_Dict_Optional_TestModule_Box.lift(); return dictResult; }, roundtripCounters: function bjs_roundtripCounters(counters) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index b98b2af7e..eef5cdf30 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -174,16 +174,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -422,6 +412,77 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_Optional_String = __bjs_optionalCodec(__bjs_stringCodec); + const __bjs_codec_Optional_Bool = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool); + const __bjs_codec_Optional_Int = __bjs_optionalCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_TestModule_Precision = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + const __bjs_codec_Optional_TestModule_Precision = __bjs_optionalCodec(__bjs_codec_TestModule_Precision); + const __bjs_codec_TestModule_CardinalDirection = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const __bjs_codec_Optional_TestModule_CardinalDirection = __bjs_optionalCodec(__bjs_codec_TestModule_CardinalDirection); + const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_TestModule_Point = { + lower: (v) => { + structHelpers.Point.lower(v); + }, + lift: () => { + const struct = structHelpers.Point.lift(); + return struct; + }, + }; + const __bjs_codec_Optional_TestModule_Point = __bjs_optionalCodec(__bjs_codec_TestModule_Point); + const __bjs_codec_TestModule_User = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['User'].__construct(ptr); + return obj; + }, + }; + const __bjs_codec_Optional_TestModule_User = __bjs_optionalCodec(__bjs_codec_TestModule_User); + const __bjs_codec_JSObject = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Optional_JSObject = __bjs_optionalCodec(__bjs_codec_JSObject); + const __bjs_codec_TestModule_APIResult = { + lower: (v) => { + const caseId = enumHelpers.APIResult.lower(v); + i32Stack.push(caseId); + }, + lift: () => { + const enumValue = enumHelpers.APIResult.lift(i32Stack.pop()); + return enumValue; + }, + }; + const __bjs_codec_Optional_TestModule_APIResult = __bjs_optionalCodec(__bjs_codec_TestModule_APIResult); + const __bjs_codec_Optional_Array_Int = __bjs_optionalCodec(__bjs_codec_Array_Int); + const __bjs_createPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -692,18 +753,18 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIOptionalResultValues.Tag.Success: { - __bjs_optionalCodec(__bjs_stringCodec).lower(value.param0); + __bjs_codec_Optional_String.lower(value.param0); return APIOptionalResultValues.Tag.Success; } case APIOptionalResultValues.Tag.Failure: { - __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.param1); - __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.param0); + __bjs_codec_Optional_Bool.lower(value.param1); + __bjs_codec_Optional_Int.lower(value.param0); return APIOptionalResultValues.Tag.Failure; } case APIOptionalResultValues.Tag.Status: { - __bjs_optionalCodec(__bjs_stringCodec).lower(value.param2); - __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.param1); - __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.param0); + __bjs_codec_Optional_String.lower(value.param2); + __bjs_codec_Optional_Int.lower(value.param1); + __bjs_codec_Optional_Bool.lower(value.param0); return APIOptionalResultValues.Tag.Status; } default: throw new Error("Unknown APIOptionalResultValues tag: " + String(enumTag)); @@ -713,18 +774,18 @@ export async function createInstantiator(options, swift) { tag = tag | 0; switch (tag) { case APIOptionalResultValues.Tag.Success: { - const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); + const optValue = __bjs_codec_Optional_String.lift(); return { tag: APIOptionalResultValues.Tag.Success, param0: optValue }; } case APIOptionalResultValues.Tag.Failure: { - const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); - const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); + const optValue = __bjs_codec_Optional_Bool.lift(); + const optValue1 = __bjs_codec_Optional_Int.lift(); return { tag: APIOptionalResultValues.Tag.Failure, param0: optValue1, param1: optValue }; } case APIOptionalResultValues.Tag.Status: { - const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); - const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); - const optValue2 = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); + const optValue = __bjs_codec_Optional_String.lift(); + const optValue1 = __bjs_codec_Optional_Int.lift(); + const optValue2 = __bjs_codec_Optional_Bool.lift(); return { tag: APIOptionalResultValues.Tag.Status, param0: optValue2, param1: optValue1, param2: optValue }; } default: throw new Error("Unknown APIOptionalResultValues tag returned from Swift: " + String(tag)); @@ -744,29 +805,11 @@ export async function createInstantiator(options, swift) { return TypedPayloadResultValues.Tag.Direction; } case TypedPayloadResultValues.Tag.OptPrecision: { - const elemCodec = { - lower: (v) => { - f32Stack.push(Math.fround(v)); - }, - lift: () => { - const rawValue = f32Stack.pop(); - return rawValue; - }, - }; - __bjs_optionalCodec(elemCodec).lower(value.param0); + __bjs_codec_Optional_TestModule_Precision.lower(value.param0); return TypedPayloadResultValues.Tag.OptPrecision; } case TypedPayloadResultValues.Tag.OptDirection: { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - __bjs_optionalCodec(elemCodec).lower(value.param0); + __bjs_codec_Optional_TestModule_CardinalDirection.lower(value.param0); return TypedPayloadResultValues.Tag.OptDirection; } case TypedPayloadResultValues.Tag.Empty: { @@ -787,29 +830,11 @@ export async function createInstantiator(options, swift) { return { tag: TypedPayloadResultValues.Tag.Direction, param0: caseId }; } case TypedPayloadResultValues.Tag.OptPrecision: { - const elemCodec = { - lower: (v) => { - f32Stack.push(Math.fround(v)); - }, - lift: () => { - const rawValue = f32Stack.pop(); - return rawValue; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_Precision.lift(); return { tag: TypedPayloadResultValues.Tag.OptPrecision, param0: optValue }; } case TypedPayloadResultValues.Tag.OptDirection: { - const elemCodec = { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_CardinalDirection.lift(); return { tag: TypedPayloadResultValues.Tag.OptDirection, param0: optValue }; } case TypedPayloadResultValues.Tag.Empty: return { tag: TypedPayloadResultValues.Tag.Empty }; @@ -840,7 +865,7 @@ export async function createInstantiator(options, swift) { return AllTypesResultValues.Tag.NestedEnum; } case AllTypesResultValues.Tag.ArrayPayload: { - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(value.param0); + __bjs_codec_Array_Int.lower(value.param0); return AllTypesResultValues.Tag.ArrayPayload; } case AllTypesResultValues.Tag.Empty: { @@ -872,7 +897,7 @@ export async function createInstantiator(options, swift) { return { tag: AllTypesResultValues.Tag.NestedEnum, param0: enumValue }; } case AllTypesResultValues.Tag.ArrayPayload: { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); return { tag: AllTypesResultValues.Tag.ArrayPayload, param0: arrayResult }; } case AllTypesResultValues.Tag.Empty: return { tag: AllTypesResultValues.Tag.Empty }; @@ -885,45 +910,23 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case OptionalAllTypesResultValues.Tag.OptStruct: { - __bjs_optionalCodec(structHelpers.Point).lower(value.param0); + __bjs_codec_Optional_TestModule_Point.lower(value.param0); return OptionalAllTypesResultValues.Tag.OptStruct; } case OptionalAllTypesResultValues.Tag.OptClass: { - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = _exports['User'].__construct(ptr); - return obj; - }, - }; - __bjs_optionalCodec(elemCodec).lower(value.param0); + __bjs_codec_Optional_TestModule_User.lower(value.param0); return OptionalAllTypesResultValues.Tag.OptClass; } case OptionalAllTypesResultValues.Tag.OptJSObject: { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_optionalCodec(elemCodec).lower(value.param0); + __bjs_codec_Optional_JSObject.lower(value.param0); return OptionalAllTypesResultValues.Tag.OptJSObject; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - __bjs_optionalCodec(__bjs_enumCodec(enumHelpers.APIResult)).lower(value.param0); + __bjs_codec_Optional_TestModule_APIResult.lower(value.param0); return OptionalAllTypesResultValues.Tag.OptNestedEnum; } case OptionalAllTypesResultValues.Tag.OptArray: { - __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lower(value.param0); + __bjs_codec_Optional_Array_Int.lower(value.param0); return OptionalAllTypesResultValues.Tag.OptArray; } case OptionalAllTypesResultValues.Tag.Empty: { @@ -936,45 +939,23 @@ export async function createInstantiator(options, swift) { tag = tag | 0; switch (tag) { case OptionalAllTypesResultValues.Tag.OptStruct: { - const optValue = __bjs_optionalCodec(structHelpers.Point).lift(); + const optValue = __bjs_codec_Optional_TestModule_Point.lift(); return { tag: OptionalAllTypesResultValues.Tag.OptStruct, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptClass: { - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = _exports['User'].__construct(ptr); - return obj; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_User.lift(); return { tag: OptionalAllTypesResultValues.Tag.OptClass, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptJSObject: { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_JSObject.lift(); return { tag: OptionalAllTypesResultValues.Tag.OptJSObject, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptNestedEnum: { - const optValue = __bjs_optionalCodec(__bjs_enumCodec(enumHelpers.APIResult)).lift(); + const optValue = __bjs_codec_Optional_TestModule_APIResult.lift(); return { tag: OptionalAllTypesResultValues.Tag.OptNestedEnum, param0: optValue }; } case OptionalAllTypesResultValues.Tag.OptArray: { - const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.Int)).lift(); + const optValue = __bjs_codec_Optional_Array_Int.lift(); return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optValue }; } case OptionalAllTypesResultValues.Tag.Empty: return { tag: OptionalAllTypesResultValues.Tag.Empty }; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 92e1868c7..13e9e9015 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -168,16 +168,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -416,6 +406,27 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_FileSize = { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const rawValue = i64Stack.pop(); + return rawValue; + }, + }; + const __bjs_codec_Optional_TestModule_FileSize = __bjs_optionalCodec(__bjs_codec_TestModule_FileSize); + const __bjs_codec_TestModule_SessionId = { + lower: (v) => { + i64Stack.push(v); + }, + lift: () => { + const rawValue = i64Stack.pop(); + return rawValue; + }, + }; + const __bjs_codec_Optional_TestModule_SessionId = __bjs_optionalCodec(__bjs_codec_TestModule_SessionId); + return { /** @@ -760,16 +771,7 @@ export async function createInstantiator(options, swift) { roundTripOptionalFileSize: function bjs_roundTripOptionalFileSize(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalFileSize(+isSome, isSome ? input : 0n); - const elemCodec = { - lower: (v) => { - i64Stack.push(v); - }, - lift: () => { - const rawValue = i64Stack.pop(); - return rawValue; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_FileSize.lift(); return optValue; }, setUserId: function bjs_setUserId(id) { @@ -810,16 +812,7 @@ export async function createInstantiator(options, swift) { roundTripOptionalSessionId: function bjs_roundTripOptionalSessionId(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalSessionId(+isSome, isSome ? input : 0n); - const elemCodec = { - lower: (v) => { - i64Stack.push(v); - }, - lift: () => { - const rawValue = i64Stack.pop(); - return rawValue; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_SessionId.lift(); return optValue; }, setPrecision: function bjs_setPrecision(precision) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js index ec7fb161d..db2e0a95b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -127,16 +127,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -375,6 +365,46 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_TestModule_GenericPoint = { + lower: (v) => { + structHelpers.GenericPoint.lower(v); + }, + lift: () => { + const struct = structHelpers.GenericPoint.lift(); + return struct; + }, + }; + const __bjs_codec_TestModule_GenericImportBox = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports['GenericImportBox'].__construct(ptr); + return obj; + }, + }; + const __bjs_codec_TestModule_GenericColor = { + lower: (v) => { + i32Stack.push((v | 0)); + }, + lift: () => { + const caseId = i32Stack.pop(); + return caseId; + }, + }; + const __bjs_codec_TestModule_GenericTagged = { + lower: (v) => { + const caseId = enumHelpers.GenericTagged.lower(v); + i32Stack.push(caseId); + }, + lift: () => { + const enumValue = enumHelpers.GenericTagged.lift(i32Stack.pop()); + return enumValue; + }, + }; + const __bjs_createGenericPointHelpers = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); @@ -530,56 +560,11 @@ export async function createInstantiator(options, swift) { } bjs["bjs_TestModule_register_type_handles"] = function(base, count) { const codecs = [ - { - lower: (v) => { - structHelpers.GenericPoint.lower(v); - }, - lift: () => { - const struct = structHelpers.GenericPoint.lift(); - return struct; - }, - }, - { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = _exports['GenericImportBox'].__construct(ptr); - return obj; - }, - }, - { - lower: (v) => { - i32Stack.push((v | 0)); - }, - lift: () => { - const caseId = i32Stack.pop(); - return caseId; - }, - }, - { - lower: (v) => { - const bytes = textEncoder.encode(v); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); - i32Stack.push(id); - }, - lift: () => { - const rawValue = strStack.pop(); - return rawValue; - }, - }, - { - lower: (v) => { - const caseId = enumHelpers.GenericTagged.lower(v); - i32Stack.push(caseId); - }, - lift: () => { - const enumValue = enumHelpers.GenericTagged.lift(i32Stack.pop()); - return enumValue; - }, - }, + __bjs_codec_TestModule_GenericPoint, + __bjs_codec_TestModule_GenericImportBox, + __bjs_codec_TestModule_GenericColor, + __bjs_stringCodec, + __bjs_codec_TestModule_GenericTagged, ]; if (count !== codecs.length) { throw new Error("BridgeJS: type handle registration mismatch for module 'TestModule'"); @@ -774,7 +759,7 @@ export async function createInstantiator(options, swift) { const codecT = __bjs_codecForTypeId(tTypeId); let optResult; if (values) { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); optResult = arrayResult; } else { optResult = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 77cde8a89..535effde3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,6 +331,9 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Array_String = __bjs_arrayCodec(__bjs_stringCodec); + return { /** @@ -518,16 +511,16 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_roundtrip"] = function bjs_roundtrip() { try { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); let ret = imports.roundtrip(arrayResult); - __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lower(ret); + __bjs_codec_Array_Int.lower(ret); } catch (error) { setException(error); } } TestModule["bjs_logStrings"] = function bjs_logStrings() { try { - const arrayResult = __bjs_arrayCodec(__bjs_stringCodec).lift(); + const arrayResult = __bjs_codec_Array_String.lift(); imports.logStrings(arrayResult); } catch (error) { setException(error); @@ -537,12 +530,12 @@ export async function createInstantiator(options, swift) { try { let optResult; if (a) { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); optResult = arrayResult; } else { optResult = null; } - const arrayResult1 = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult1 = __bjs_codec_Array_Int.lift(); let ret = imports.optionalArrayThenArray(optResult, arrayResult1); return ret; } catch (error) { @@ -555,12 +548,12 @@ export async function createInstantiator(options, swift) { const string = decodeString(sBytes, sCount); let optResult; if (a) { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult = __bjs_codec_Array_Int.lift(); optResult = arrayResult; } else { optResult = null; } - const arrayResult1 = __bjs_arrayCodec(__bjs_primitiveCodecs.Int).lift(); + const arrayResult1 = __bjs_codec_Array_Int.lift(); let ret = imports.borrowedStringAroundStackParams(string, optResult, arrayResult1); return ret; } catch (error) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index e3fbdba8d..4a8cd2a4d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,6 +331,22 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_Foo = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Array_TestModule_Foo = __bjs_arrayCodec(__bjs_codec_TestModule_Foo); + const __bjs_codec_Optional_TestModule_Foo = __bjs_optionalCodec(__bjs_codec_TestModule_Foo); + const __bjs_codec_Array_Optional_TestModule_Foo = __bjs_arrayCodec(__bjs_codec_Optional_TestModule_Foo); + const __bjs_createFooContainerHelpers = () => ({ lower: (value) => { let id; @@ -350,34 +356,10 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_optionalCodec(elemCodec).lower(value.optionalFoo); + __bjs_codec_Optional_TestModule_Foo.lower(value.optionalFoo); }, lift: () => { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_Foo.lift(); const objectId = i32Stack.pop(); let value; if (objectId !== 0) { @@ -611,63 +593,15 @@ export async function createInstantiator(options, swift) { return ret1; }, processFooArray: function bjs_processFooArray(foos) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(elemCodec).lower(foos); + __bjs_codec_Array_TestModule_Foo.lower(foos); instance.exports.bjs_processFooArray(); - const elemCodec1 = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_TestModule_Foo.lift(); return arrayResult; }, processOptionalFooArray: function bjs_processOptionalFooArray(foos) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(__bjs_optionalCodec(elemCodec)).lower(foos); + __bjs_codec_Array_Optional_TestModule_Foo.lower(foos); instance.exports.bjs_processOptionalFooArray(); - const elemCodec1 = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(__bjs_optionalCodec(elemCodec1)).lift(); + const arrayResult = __bjs_codec_Array_Optional_TestModule_Foo.lift(); return arrayResult; }, roundtripFooContainer: function bjs_roundtripFooContainer(container) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 136167f2a..d46ffb1a8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,6 +331,9 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_Array_JSValue = __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue); + const __bjs_codec_Optional_Array_JSValue = __bjs_optionalCodec(__bjs_codec_Array_JSValue); + return { /** @@ -538,9 +531,9 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_jsEchoJSValueArray"] = function bjs_jsEchoJSValueArray() { try { - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lift(); + const arrayResult = __bjs_codec_Array_JSValue.lift(); let ret = imports.jsEchoJSValueArray(arrayResult); - __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lower(ret); + __bjs_codec_Array_JSValue.lower(ret); } catch (error) { setException(error); } @@ -766,15 +759,15 @@ export async function createInstantiator(options, swift) { return optResult; }, roundTripJSValueArray: function bjs_roundTripJSValueArray(values) { - __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lower(values); + __bjs_codec_Array_JSValue.lower(values); instance.exports.bjs_roundTripJSValueArray(); - const arrayResult = __bjs_arrayCodec(__bjs_primitiveCodecs.JSValue).lift(); + const arrayResult = __bjs_codec_Array_JSValue.lift(); return arrayResult; }, roundTripOptionalJSValueArray: function bjs_roundTripOptionalJSValueArray(values) { - __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.JSValue)).lower(values); + __bjs_codec_Optional_Array_JSValue.lower(values); instance.exports.bjs_roundTripOptionalJSValueArray(); - const optValue = __bjs_optionalCodec(__bjs_arrayCodec(__bjs_primitiveCodecs.JSValue)).lift(); + const optValue = __bjs_codec_Optional_Array_JSValue.lift(); return optValue; }, JSValueHolder, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index ef10ff9b9..40b5bd079 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,6 +331,18 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_Greeter = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports.__Swift.Foundation.Greeter.__construct(ptr); + return obj; + }, + }; + const __bjs_codec_Array_TestModule_Greeter = __bjs_arrayCodec(__bjs_codec_TestModule_Greeter); + return { /** @@ -667,17 +669,7 @@ export async function createInstantiator(options, swift) { } getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Greeter.__construct(ptr); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec).lift(); + const arrayResult = __bjs_codec_Array_TestModule_Greeter.lift(); return arrayResult; } addItem(item) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index bb4fce7a6..18f03f8d8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,6 +331,18 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_Greeter = { + lower: (v) => { + ptrStack.push(v.pointer); + }, + lift: () => { + const ptr = ptrStack.pop(); + const obj = _exports.__Swift.Foundation.Greeter.__construct(ptr); + return obj; + }, + }; + const __bjs_codec_Array_TestModule_Greeter = __bjs_arrayCodec(__bjs_codec_TestModule_Greeter); + return { /** @@ -667,17 +669,7 @@ export async function createInstantiator(options, swift) { } getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); - const elemCodec = { - lower: (v) => { - ptrStack.push(v.pointer); - }, - lift: () => { - const ptr = ptrStack.pop(); - const obj = Greeter.__construct(ptr); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec).lift(); + const arrayResult = __bjs_codec_Array_TestModule_Greeter.lift(); return arrayResult; } addItem(item) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 7d073e02a..2745d5a97 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,6 +331,33 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_JSObject = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Optional_JSObject = __bjs_optionalCodec(__bjs_codec_JSObject); + const __bjs_codec_TestModule_WithOptionalJSClass = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Optional_TestModule_WithOptionalJSClass = __bjs_optionalCodec(__bjs_codec_TestModule_WithOptionalJSClass); + return { /** @@ -625,19 +642,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WithOptionalJSClass_childOrNull_get"] = function bjs_WithOptionalJSClass_childOrNull_get(self) { try { let ret = swift.memory.getObject(self).childOrNull; - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_optionalCodec(elemCodec).lower(ret); + __bjs_codec_Optional_TestModule_WithOptionalJSClass.lower(ret); } catch (error) { setException(error); } @@ -808,19 +813,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WithOptionalJSClass_roundTripChildOrNull"] = function bjs_WithOptionalJSClass_roundTripChildOrNull(self, valueIsSome, valueObjectId) { try { let ret = swift.memory.getObject(self).roundTripChildOrNull(valueIsSome ? swift.memory.getObject(valueObjectId) : null); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_optionalCodec(elemCodec).lower(ret); + __bjs_codec_Optional_TestModule_WithOptionalJSClass.lower(ret); } catch (error) { setException(error); } @@ -1047,19 +1040,7 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.bjs_roundTripExportedOptionalJSObject(+isSome, result); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_JSObject.lift(); return optValue; }, roundTripExportedOptionalJSClass: function bjs_roundTripExportedOptionalJSClass(value) { @@ -1071,19 +1052,7 @@ export async function createInstantiator(options, swift) { result = 0; } instance.exports.bjs_roundTripExportedOptionalJSClass(+isSome, result); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_WithOptionalJSClass.lift(); return optValue; }, roundTripString: function bjs_roundTripString(name) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index c28ceeb31..65bf34266 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -117,16 +117,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -365,6 +355,21 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_MyViewControllerDelegate = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Array_TestModule_MyViewControllerDelegate = __bjs_arrayCodec(__bjs_codec_TestModule_MyViewControllerDelegate); + const __bjs_codec_Dict_TestModule_MyViewControllerDelegate = __bjs_dictCodec(__bjs_codec_TestModule_MyViewControllerDelegate); + const __bjs_createResultValuesHelpers = () => ({ lower: (value) => { const enumTag = value.tag; @@ -1036,19 +1041,7 @@ export async function createInstantiator(options, swift) { } constructor(delegates) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(elemCodec).lower(delegates); + __bjs_codec_Array_TestModule_MyViewControllerDelegate.lower(delegates); const ret = instance.exports.bjs_DelegateManager_init(); return DelegateManager.__construct(ret); } @@ -1057,68 +1050,20 @@ export async function createInstantiator(options, swift) { } get delegates() { instance.exports.bjs_DelegateManager_delegates_get(this.pointer); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec).lift(); + const arrayResult = __bjs_codec_Array_TestModule_MyViewControllerDelegate.lift(); return arrayResult; } set delegates(value) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(elemCodec).lower(value); + __bjs_codec_Array_TestModule_MyViewControllerDelegate.lower(value); instance.exports.bjs_DelegateManager_delegates_set(this.pointer); } get delegatesByName() { instance.exports.bjs_DelegateManager_delegatesByName_get(this.pointer); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const dictResult = __bjs_dictCodec(elemCodec).lift(); + const dictResult = __bjs_codec_Dict_TestModule_MyViewControllerDelegate.lift(); return dictResult; } set delegatesByName(value) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_dictCodec(elemCodec).lower(value); + __bjs_codec_Dict_TestModule_MyViewControllerDelegate.lower(value); instance.exports.bjs_DelegateManager_delegatesByName_set(this.pointer); } } @@ -1127,63 +1072,15 @@ export async function createInstantiator(options, swift) { const exports = { processDelegates: function bjs_processDelegates(delegates) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_arrayCodec(elemCodec).lower(delegates); + __bjs_codec_Array_TestModule_MyViewControllerDelegate.lower(delegates); instance.exports.bjs_processDelegates(); - const elemCodec1 = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const arrayResult = __bjs_arrayCodec(elemCodec1).lift(); + const arrayResult = __bjs_codec_Array_TestModule_MyViewControllerDelegate.lift(); return arrayResult; }, processDelegatesByName: function bjs_processDelegatesByName(delegates) { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_dictCodec(elemCodec).lower(delegates); + __bjs_codec_Dict_TestModule_MyViewControllerDelegate.lower(delegates); instance.exports.bjs_processDelegatesByName(); - const elemCodec1 = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const dictResult = __bjs_dictCodec(elemCodec1).lift(); + const dictResult = __bjs_codec_Dict_TestModule_MyViewControllerDelegate.lift(); return dictResult; }, Direction: DirectionValues, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index e208ff35c..cbf97bb5e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -123,16 +123,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -396,6 +386,17 @@ export async function createInstantiator(options, swift) { return swift.memory.retain(real); }; + const __bjs_codec_TestModule_Animal = { + lower: (v) => { + structHelpers.Animal.lower(v); + }, + lift: () => { + const struct = structHelpers.Animal.lift(); + return struct; + }, + }; + const __bjs_codec_Optional_TestModule_Animal = __bjs_optionalCodec(__bjs_codec_TestModule_Animal); + const __bjs_createAnimalHelpers = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.type); @@ -1086,16 +1087,16 @@ export async function createInstantiator(options, swift) { optResult = null; } let ret = callback(optResult); - __bjs_optionalCodec(structHelpers.Animal).lower(ret); + __bjs_codec_Optional_TestModule_Animal.lower(ret); } catch (error) { setException(error); } } bjs["make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV = function(param0) { - __bjs_optionalCodec(structHelpers.Animal).lower(param0); + __bjs_codec_Optional_TestModule_Animal.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(boxPtr); - const optValue = __bjs_optionalCodec(structHelpers.Animal).lift(); + const optValue = __bjs_codec_Optional_TestModule_Animal.lift(); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index ad8d4e29d..a5496d4ee 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -98,16 +98,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -346,6 +336,33 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_Optional_Int = __bjs_optionalCodec(__bjs_primitiveCodecs.Int); + const __bjs_codec_Optional_Bool = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool); + const __bjs_codec_Optional_String = __bjs_optionalCodec(__bjs_stringCodec); + const __bjs_codec_TestModule_Precision = { + lower: (v) => { + f32Stack.push(Math.fround(v)); + }, + lift: () => { + const rawValue = f32Stack.pop(); + return rawValue; + }, + }; + const __bjs_codec_Optional_TestModule_Precision = __bjs_optionalCodec(__bjs_codec_TestModule_Precision); + const __bjs_codec_JSObject = { + lower: (v) => { + const objId = swift.memory.retain(v); + i32Stack.push(objId); + }, + lift: () => { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + return obj; + }, + }; + const __bjs_codec_Optional_JSObject = __bjs_optionalCodec(__bjs_codec_JSObject); + const __bjs_createDataPointHelpers = () => ({ lower: (value) => { f64Stack.push(value.x); @@ -354,12 +371,12 @@ export async function createInstantiator(options, swift) { const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); - __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.optCount); - __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lower(value.optFlag); + __bjs_codec_Optional_Int.lower(value.optCount); + __bjs_codec_Optional_Bool.lower(value.optFlag); }, lift: () => { - const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Bool).lift(); - const optValue1 = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); + const optValue = __bjs_codec_Optional_Bool.lift(); + const optValue1 = __bjs_codec_Optional_Int.lift(); const string = strStack.pop(); const f64 = f64Stack.pop(); const f641 = f64Stack.pop(); @@ -376,10 +393,10 @@ export async function createInstantiator(options, swift) { const id1 = swift.memory.retain(bytes1); i32Stack.push(bytes1.length); i32Stack.push(id1); - __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lower(value.zipCode); + __bjs_codec_Optional_Int.lower(value.zipCode); }, lift: () => { - const optValue = __bjs_optionalCodec(__bjs_primitiveCodecs.Int).lift(); + const optValue = __bjs_codec_Optional_Int.lift(); const string = strStack.pop(); const string1 = strStack.pop(); return { street: string1, city: string, zipCode: optValue }; @@ -393,10 +410,10 @@ export async function createInstantiator(options, swift) { i32Stack.push(id); i32Stack.push((value.age | 0)); structHelpers.Address.lower(value.address); - __bjs_optionalCodec(__bjs_stringCodec).lower(value.email); + __bjs_codec_Optional_String.lower(value.email); }, lift: () => { - const optValue = __bjs_optionalCodec(__bjs_stringCodec).lift(); + const optValue = __bjs_codec_Optional_String.lift(); const struct = structHelpers.Address.lift(); const int = i32Stack.pop(); const string = strStack.pop(); @@ -419,28 +436,10 @@ export async function createInstantiator(options, swift) { lower: (value) => { f64Stack.push(value.value); f32Stack.push(Math.fround(value.precision)); - const elemCodec = { - lower: (v) => { - f32Stack.push(Math.fround(v)); - }, - lift: () => { - const rawValue = f32Stack.pop(); - return rawValue; - }, - }; - __bjs_optionalCodec(elemCodec).lower(value.optionalPrecision); + __bjs_codec_Optional_TestModule_Precision.lower(value.optionalPrecision); }, lift: () => { - const elemCodec = { - lower: (v) => { - f32Stack.push(Math.fround(v)); - }, - lift: () => { - const rawValue = f32Stack.pop(); - return rawValue; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_TestModule_Precision.lift(); const rawValue = f32Stack.pop(); const f64 = f64Stack.pop(); return { value: f64, precision: rawValue, optionalPrecision: optValue }; @@ -462,34 +461,10 @@ export async function createInstantiator(options, swift) { id = undefined; } i32Stack.push(id !== undefined ? id : 0); - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - __bjs_optionalCodec(elemCodec).lower(value.optionalObject); + __bjs_codec_Optional_JSObject.lower(value.optionalObject); }, lift: () => { - const elemCodec = { - lower: (v) => { - const objId = swift.memory.retain(v); - i32Stack.push(objId); - }, - lift: () => { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - return obj; - }, - }; - const optValue = __bjs_optionalCodec(elemCodec).lift(); + const optValue = __bjs_codec_Optional_JSObject.lift(); const objectId = i32Stack.pop(); let value; if (objectId !== 0) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index e9add7027..159d4b616 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -93,16 +93,6 @@ export async function createInstantiator(options, swift) { }, }; } - function __bjs_enumCodec(helper) { - return { - lower(value) { - i32Stack.push(helper.lower(value)); - }, - lift() { - return helper.lift(i32Stack.pop()); - }, - }; - } const __bjs_stringCodec = { lower: (v) => { @@ -341,6 +331,17 @@ export async function createInstantiator(options, swift) { return jsValue; } + const __bjs_codec_TestModule_Point = { + lower: (v) => { + structHelpers.Point.lower(v); + }, + lift: () => { + const struct = structHelpers.Point.lift(); + return struct; + }, + }; + const __bjs_codec_Optional_TestModule_Point = __bjs_optionalCodec(__bjs_codec_TestModule_Point); + const __bjs_createPointHelpers = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); @@ -554,7 +555,7 @@ export async function createInstantiator(options, swift) { optResult = null; } let ret = imports.roundTripOptional(optResult); - __bjs_optionalCodec(structHelpers.Point).lower(ret); + __bjs_codec_Optional_TestModule_Point.lower(ret); } catch (error) { setException(error); } From 71cc2f052f868d58c9434a6bbc42dda726da3a34 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 11 Aug 2026 14:51:48 +0200 Subject: [PATCH 5/6] BridgeJS: Memoize container codec combinators per element codec Statically known compositions are now hoisted into module-scope consts, so the combinators run once for them. A generic call site cannot be hoisted: it resolves its element codec from a runtime type ID, so `[T]`, `T?` and `[String: T]` parameters rebuilt a codec object on every call. Cache each combinator's result by element codec object. The element codecs are themselves module-scope singletons, so the cache is bounded by the number of distinct type shapes; a WeakMap keeps it from pinning codecs resolved for types that are never used again. The `JSUndefinedOr` flavour of the optional combinator differs in behaviour, not just in its element, so it gets its own cache. --- .../Sources/BridgeJSLink/JSGlueGen.swift | 37 +++++++++++++++++-- .../__Snapshots__/BridgeJSLinkTests/Alias.js | 29 +++++++++++++-- .../BridgeJSLinkTests/ArrayTypes.js | 29 +++++++++++++-- .../__Snapshots__/BridgeJSLinkTests/Async.js | 29 +++++++++++++-- .../BridgeJSLinkTests/DefaultParameters.js | 29 +++++++++++++-- .../BridgeJSLinkTests/DictionaryTypes.js | 29 +++++++++++++-- .../BridgeJSLinkTests/EnumAssociatedValue.js | 29 +++++++++++++-- .../BridgeJSLinkTests/EnumRawType.js | 29 +++++++++++++-- .../BridgeJSLinkTests/GenericImports.js | 29 +++++++++++++-- .../BridgeJSLinkTests/ImportArray.js | 29 +++++++++++++-- .../ImportedTypeInExportedInterface.js | 29 +++++++++++++-- .../BridgeJSLinkTests/JSValue.js | 29 +++++++++++++-- .../BridgeJSLinkTests/Namespaces.Global.js | 29 +++++++++++++-- .../BridgeJSLinkTests/Namespaces.js | 29 +++++++++++++-- .../BridgeJSLinkTests/Optionals.js | 29 +++++++++++++-- .../BridgeJSLinkTests/Protocol.js | 29 +++++++++++++-- .../BridgeJSLinkTests/SwiftClosure.js | 29 +++++++++++++-- .../BridgeJSLinkTests/SwiftStruct.js | 29 +++++++++++++-- .../BridgeJSLinkTests/SwiftStructImports.js | 29 +++++++++++++-- 19 files changed, 502 insertions(+), 57 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index f8b5d08a6..060f4f507 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -216,12 +216,23 @@ enum ContainerCodecJS { private static let primitiveCodecIntrinsicName = "containerPrimitiveCodecs" /// The single description of each container shape's stack ABI. + /// + /// The combinators memoize per element codec object. Statically known + /// compositions are hoisted into module-scope `const`s and so instantiate a + /// combinator only once, but a generic call site resolves its element codec + /// from a runtime type ID and cannot be hoisted; memoizing keeps those call + /// sites from allocating a fresh codec on every call. static func combinatorDeclarations() -> [String] { let i32 = JSGlueVariableScope.reservedI32Stack let stringCodec = JSGlueVariableScope.reservedStringCodec return [ + "const \(arrayCodec)Cache = new WeakMap();", "function \(arrayCodec)(elementCodec) {", - " return {", + " let codec = \(arrayCodec)Cache.get(elementCodec);", + " if (codec !== undefined) {", + " return codec;", + " }", + " codec = {", " lower(value) {", " for (let i = 0; i < value.length; i++) {", " elementCodec.lower(value[i]);", @@ -240,11 +251,22 @@ enum ContainerCodecJS { " return result;", " },", " };", + " \(arrayCodec)Cache.set(elementCodec, codec);", + " return codec;", "}", // `isUndefinedOr` selects the `JSUndefinedOr` flavor: `null` is then a // present value and absence surfaces as `undefined` instead of `null`. + // The two flavors are cached separately because they differ in + // behavior, not just in the element codec. + "const \(optionalCodec)Cache = new WeakMap();", + "const \(optionalCodec)UndefinedOrCache = new WeakMap();", "function \(optionalCodec)(elementCodec, isUndefinedOr = false) {", - " return {", + " const cache = isUndefinedOr ? \(optionalCodec)UndefinedOrCache : \(optionalCodec)Cache;", + " let codec = cache.get(elementCodec);", + " if (codec !== undefined) {", + " return codec;", + " }", + " codec = {", " lower(value) {", " const isSome = isUndefinedOr ? value !== undefined : value != null;", " if (isSome) {", @@ -261,9 +283,16 @@ enum ContainerCodecJS { " return elementCodec.lift();", " },", " };", + " cache.set(elementCodec, codec);", + " return codec;", "}", + "const \(dictCodec)Cache = new WeakMap();", "function \(dictCodec)(valueCodec) {", - " return {", + " let codec = \(dictCodec)Cache.get(valueCodec);", + " if (codec !== undefined) {", + " return codec;", + " }", + " codec = {", " lower(value) {", " const keys = Object.keys(value);", " for (let i = 0; i < keys.length; i++) {", @@ -283,6 +312,8 @@ enum ContainerCodecJS { " return result;", " },", " };", + " \(dictCodec)Cache.set(valueCodec, codec);", + " return codec;", "}", ] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js index fff8779ef..d70db0f42 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js @@ -37,8 +37,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -57,9 +62,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -76,9 +90,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -98,6 +119,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index e038620c1..aaa9460c8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -44,8 +44,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -64,9 +69,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -83,9 +97,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -105,6 +126,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 7bd19602d..2b667aefa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -41,8 +41,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -61,9 +66,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -80,9 +94,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -102,6 +123,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index ef00bad23..3dc39e445 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -37,8 +37,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -57,9 +62,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -76,9 +90,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -98,6 +119,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 74d9e7e59..6d8ea7392 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index eef5cdf30..2a8ed684c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -112,8 +112,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -132,9 +137,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -151,9 +165,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -173,6 +194,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 13e9e9015..082aa6c38 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -106,8 +106,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -126,9 +131,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -145,9 +159,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -167,6 +188,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js index db2e0a95b..6912648f7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -65,8 +65,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -85,9 +90,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -104,9 +118,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -126,6 +147,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 535effde3..42c02479f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 4a8cd2a4d..1a95bcb6e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index d46ffb1a8..9fe12ff47 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index 40b5bd079..024ef49c1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 18f03f8d8..7da962422 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 2745d5a97..f9761419b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 65bf34266..73c93c039 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -55,8 +55,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -75,9 +80,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -94,9 +108,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -116,6 +137,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index cbf97bb5e..24f037350 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -61,8 +61,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -81,9 +86,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -100,9 +114,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -122,6 +143,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index a5496d4ee..bb0de3d03 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -36,8 +36,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -56,9 +61,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -75,9 +89,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -97,6 +118,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index 159d4b616..f603bee2e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const __bjs_arrayCodecCache = new WeakMap(); function __bjs_arrayCodec(elementCodec) { - return { + let codec = __bjs_arrayCodecCache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { for (let i = 0; i < value.length; i++) { elementCodec.lower(value[i]); @@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_arrayCodecCache.set(elementCodec, codec); + return codec; } + const __bjs_optionalCodecCache = new WeakMap(); + const __bjs_optionalCodecUndefinedOrCache = new WeakMap(); function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) { - return { + const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache; + let codec = cache.get(elementCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const isSome = isUndefinedOr ? value !== undefined : value != null; if (isSome) { @@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) { return elementCodec.lift(); }, }; + cache.set(elementCodec, codec); + return codec; } + const __bjs_dictCodecCache = new WeakMap(); function __bjs_dictCodec(valueCodec) { - return { + let codec = __bjs_dictCodecCache.get(valueCodec); + if (codec !== undefined) { + return codec; + } + codec = { lower(value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { @@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) { return result; }, }; + __bjs_dictCodecCache.set(valueCodec, codec); + return codec; } const __bjs_stringCodec = { From 3eeee892ad4a546e1ccf11bd67a34d9d29553ece Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 11 Aug 2026 23:44:15 +0200 Subject: [PATCH 6/6] BridgeJS: Module-qualify JS helper identifiers minted from @JS type names The link step minted the struct/enum helper factories, the `const`s holding them, and the keys of the shared `structHelpers` / `enumHelpers` tables from the type name alone, so two modules declaring a same-named `@JS` type emitted duplicate top-level `const`s in one glue scope (a load-time SyntaxError). Qualify all of them with the declaring module, reusing the `__bjs_codec__` naming already used for the codec helpers: __bjs_createStructHelpers__ __bjs_createEnumHelpers__ __bjs_helpers__ structHelpers._ / enumHelpers._ Declaration sites take the module from the skeleton being emitted; reference sites, which only see a `BridgeType` (a bare type name), resolve it through the existing `typeOwnerModules` map. That map cannot disambiguate a name declared by two modules, and three things downstream stay minted from the bare name regardless: the top-level `const Values` object, the `class ` declaration, and the `bjs["swift_js_struct_*_"]` wasm import names, which the Swift side derives from the same name. Reject those inputs at link time with a message naming both modules and the type, instead of emitting glue that throws at load time or binds one module's values to the other module's helpers. --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 137 ++++++++++++--- .../Sources/BridgeJSLink/JSGlueGen.swift | 166 ++++++++++++++---- .../BridgeJSToolTests/BridgeJSLinkTests.swift | 112 ++++++++++-- .../NamedCodecHelperTests.swift | 2 +- .../__Snapshots__/BridgeJSLinkTests/Alias.js | 10 +- .../BridgeJSLinkTests/ArrayTypes.js | 16 +- .../__Snapshots__/BridgeJSLinkTests/Async.js | 26 +-- .../AsyncAssociatedValueEnum.js | 14 +- .../BridgeJSLinkTests/ClassWithNestedTypes.js | 14 +- .../BridgeJSLinkTests/DefaultParameters.js | 30 ++-- .../BridgeJSLinkTests/DictionaryTypes.js | 14 +- .../BridgeJSLinkTests/DocComments.js | 10 +- .../BridgeJSLinkTests/EnumAssociatedValue.js | 140 +++++++-------- .../EnumAssociatedValueImport.js | 18 +- .../BridgeJSLinkTests/GenericImports.js | 24 +-- .../ImportedTypeInExportedInterface.js | 14 +- .../BridgeJSLinkTests/JSNameOverride.js | 16 +- .../BridgeJSLinkTests/NestedType.js | 20 +-- .../BridgeJSLinkTests/Protocol.js | 18 +- .../StaticFunctions.Global.js | 10 +- .../BridgeJSLinkTests/StaticFunctions.js | 10 +- .../StructWithNestedTypes.js | 48 ++--- .../BridgeJSLinkTests/SwiftClosure.js | 60 +++---- .../BridgeJSLinkTests/SwiftStruct.js | 104 +++++------ .../BridgeJSLinkTests/SwiftStructImports.js | 20 +-- .../BridgeJSLinkTests/UnsafePointer.js | 16 +- 26 files changed, 667 insertions(+), 402 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 15d34eb2b..1a3c917e5 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -521,7 +521,9 @@ public struct BridgeJSLink { private func generateAddImports(needsImportsObject: Bool) throws -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() - let allStructs = skeletons.compactMap { $0.exported?.structs }.flatMap { $0 } + let allStructs = skeletons.flatMap { unified in + (unified.exported?.structs ?? []).map { (moduleName: unified.moduleName, structDef: $0) } + } printer.write("return {") try printer.indent { printer.write(lines: [ @@ -669,11 +671,16 @@ public struct BridgeJSLink { } printer.write("}") if !allStructs.isEmpty { - for structDef in allStructs { + for (moduleName, structDef) in allStructs { + // The `bjs` import names are part of the wasm ABI and are + // minted from the ABI name alone on both sides, so they + // cannot be module-qualified here. `validateNoCrossModuleTypeNameCollisions` + // rejects the inputs that would make them collide. + let key = HelperNaming.qualified(base: structDef.abiName, module: moduleName) printer.write("bjs[\"swift_js_struct_lower_\(structDef.abiName)\"] = function(objectId) {") printer.indent { printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));" + "\(JSGlueVariableScope.reservedStructHelpers).\(key).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));" ) } printer.write("}") @@ -681,7 +688,7 @@ public struct BridgeJSLink { printer.write("bjs[\"swift_js_struct_lift_\(structDef.abiName)\"] = function() {") printer.indent { printer.write( - "const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lift();" + "const value = \(JSGlueVariableScope.reservedStructHelpers).\(key).lift();" ) printer.write("return \(JSGlueVariableScope.reservedSwift).memory.retain(value);") } @@ -1255,12 +1262,18 @@ public struct BridgeJSLink { let bodyPrinter = CodeFragmentPrinter() let allStructs = exportedSkeletons.flatMap { $0.structs } - for structDef in allStructs { + for (moduleName, structDef) in skeletons.flatMap({ unified in + (unified.exported?.structs ?? []).map { (unified.moduleName, $0) } + }) { let structPrinter = CodeFragmentPrinter() let structScope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry) - let fragment = IntrinsicJSFragment.structHelper(structDefinition: structDef, allStructs: allStructs) + let fragment = IntrinsicJSFragment.structHelper( + structDefinition: structDef, + allStructs: allStructs, + moduleName: moduleName + ) _ = try fragment.printCode( - [structDef.abiName], + [], IntrinsicJSFragment.PrintCodeContext( scope: structScope, printer: structPrinter, @@ -1271,13 +1284,16 @@ public struct BridgeJSLink { bodyPrinter.write(lines: structPrinter.lines) } - let allAssocEnums = exportedSkeletons.flatMap { - $0.enums.filter { $0.enumType == .associatedValue } - } - for enumDef in allAssocEnums { + for (moduleName, enumDef) in skeletons.flatMap({ unified in + (unified.exported?.enums ?? []).filter { $0.enumType == .associatedValue } + .map { (unified.moduleName, $0) } + }) { let enumPrinter = CodeFragmentPrinter() let enumScope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry) - let fragment = IntrinsicJSFragment.associatedValueEnumHelperFactory(enumDefinition: enumDef) + let fragment = IntrinsicJSFragment.associatedValueEnumHelperFactory( + enumDefinition: enumDef, + moduleName: moduleName + ) _ = try fragment.printCode( [enumDef.valuesName], IntrinsicJSFragment.PrintCodeContext( @@ -1402,6 +1418,7 @@ public struct BridgeJSLink { } public func link() throws -> (outputJs: String, outputDts: String) { + try validateNoCrossModuleTypeNameCollisions() intrinsicRegistry.reset() importedModuleRegistry.configure(skeletons: skeletons) intrinsicRegistry.classNamespaces = skeletons.reduce(into: [:]) { result, unified in @@ -1419,6 +1436,74 @@ public struct BridgeJSLink { return (outputJs, outputDts) } + /// Rejects skeletons in which two modules declare an exported type under the + /// same name. + /// + /// Declaration-site identifiers are module-qualified, but three things + /// downstream of them are minted from the bare type name and cannot be: + /// + /// - `BridgeType` carries only a type name, so a reference to `Point` from + /// module *B* cannot tell which module's `structHelpers` entry it means. + /// - The top-level `const Values` object and the `class ` + /// declaration are part of the public JS surface, so both modules would + /// emit the same `const` / `class` in one glue module. + /// - `bjs["swift_js_struct_lower_"]` is a wasm import name minted + /// from the ABI name on the Swift side too, so both modules import the + /// same one. + /// + /// Emitting glue anyway would either throw at load time or silently bind one + /// module's values to the other module's helpers, so this fails the link. + func validateNoCrossModuleTypeNameCollisions() throws { + /// The identifier minted for a declaration, and where it comes from. + struct Declaration { + let moduleName: String + let kind: String + } + var declarations: [String: [Declaration]] = [:] + func record(_ mintedName: String, kind: String, module: String) { + // Two declarations from the *same* module colliding is a separate, + // pre-existing issue (`@JS` types of the same name in different + // namespaces); this check is only about cross-module collisions. + guard !(declarations[mintedName] ?? []).contains(where: { $0.moduleName == module }) else { return } + declarations[mintedName, default: []].append(Declaration(moduleName: module, kind: kind)) + } + + for unified in skeletons { + guard let skeleton = unified.exported else { continue } + let module = unified.moduleName + for structDef in skeleton.structs { + record(structDef.abiName, kind: "struct", module: module) + } + for klass in skeleton.classes { + record(klass.name, kind: "class", module: module) + } + // Namespace enums declare no runtime value of their own; they only + // contribute to the merged namespace objects, which already merge + // across modules. + for enumDef in skeleton.enums where enumDef.enumType != .namespace { + record(enumDef.name, kind: "enum", module: module) + } + } + + for (mintedName, declarations) in declarations.sorted(by: { $0.key < $1.key }) where declarations.count > 1 { + let modules = declarations.map(\.moduleName).sorted() + let kinds = Set(declarations.map(\.kind)).sorted().joined(separator: "/") + throw BridgeJSLinkError( + message: """ + Duplicate @JS \(kinds) '\(mintedName)' declared by modules \ + \(modules.map { "'\($0)'" }.joined(separator: " and ")). + + The generated JavaScript glue mints identifiers from the type name \ + (the helper tables, the top-level declarations, and the wasm import names \ + the Swift side derives from the same name), so the two declarations \ + would collide in a single glue module. + + Rename one of them so that each module declares a distinct name. + """ + ) + } + } + /// Maps every type name a `BridgeType` can carry to the module that declares /// it, so identifiers minted from type names can be module-qualified. /// @@ -1463,12 +1548,13 @@ public struct BridgeJSLink { private func enumHelperAssignments() -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() - for skeleton in skeletons.compactMap(\.exported) { + for unified in skeletons { + guard let skeleton = unified.exported else { continue } for enumDef in skeleton.enums where enumDef.enumType == .associatedValue { - printer.write( - "const \(enumDef.name)Helpers = __bjs_create\(enumDef.valuesName)Helpers();" - ) - printer.write("\(JSGlueVariableScope.reservedEnumHelpers).\(enumDef.name) = \(enumDef.name)Helpers;") + let key = HelperNaming.qualified(base: enumDef.name, module: unified.moduleName) + let local = HelperNaming.helperConstant(key) + printer.write("const \(local) = \(HelperNaming.enumHelperFactory(key))();") + printer.write("\(JSGlueVariableScope.reservedEnumHelpers).\(key) = \(local);") printer.nextLine() } } @@ -1479,14 +1565,13 @@ public struct BridgeJSLink { private func structHelperAssignments() -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() - for skeleton in skeletons.compactMap(\.exported) { + for unified in skeletons { + guard let skeleton = unified.exported else { continue } for structDef in skeleton.structs { - printer.write( - "const \(structDef.abiName)Helpers = __bjs_create\(structDef.abiName)Helpers();" - ) - printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName) = \(structDef.abiName)Helpers;" - ) + let key = HelperNaming.qualified(base: structDef.abiName, module: unified.moduleName) + let local = HelperNaming.helperConstant(key) + printer.write("const \(local) = \(HelperNaming.structHelperFactory(key))();") + printer.write("\(JSGlueVariableScope.reservedStructHelpers).\(key) = \(local);") printer.nextLine() } } @@ -4278,8 +4363,10 @@ private struct DocCComment { } } -struct BridgeJSLinkError: Error { +struct BridgeJSLinkError: Error, CustomStringConvertible { let message: String + + var description: String { message } } extension BridgeType { diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 060f4f507..eb7e9ad80 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -119,6 +119,79 @@ final class JSGlueVariableScope { } +extension JSGlueVariableScope { + // MARK: - Module-qualified names minted from `@JS` type names + + /// Qualifies `base` with the module declaring `typeName`, when the link step + /// resolves it. `base` is left alone when it doesn't, which happens for + /// types the skeletons don't declare (core JavaScriptKit handles, say). + func qualified(base: String, declaringType typeName: String) -> String { + let base = HelperNaming.sanitized(base) + guard let module = moduleName(declaringType: typeName) ?? moduleName(declaringType: base) else { + return base + } + return HelperNaming.qualified(base: base, module: module) + } + + /// The `structHelpers` key for the name carried by `BridgeType.swiftStruct`. + func structHelperKey(forTypeNamed fullName: String) -> String { + qualified(base: HelperNaming.structKeyBase(forTypeNamed: fullName), declaringType: fullName) + } + + /// The `enumHelpers` key for the name carried by `BridgeType.associatedValueEnum`. + func enumHelperKey(forTypeNamed fullName: String) -> String { + qualified(base: HelperNaming.enumKeyBase(forTypeNamed: fullName), declaringType: fullName) + } +} + +/// Naming of the JS identifiers the link step mints from `@JS` type names. +/// +/// Every such identifier — the module-scope helper factories, the `const`s +/// holding their result, and the keys of the shared `structHelpers` / +/// `enumHelpers` tables — is qualified with the declaring module, so two modules +/// declaring the same type name do not mint the same identifier. This mirrors +/// the `__bjs_codec__` naming of the codec helpers. +enum HelperNaming { + /// Replaces anything that can't appear in a JS identifier with `_`. + static func sanitized(_ name: String) -> String { + String(name.map { $0.isLetter || $0.isNumber || $0 == "_" ? $0 : "_" }) + } + + /// `_`. + static func qualified(base: String, module: String) -> String { + "\(sanitized(module))_\(sanitized(base))" + } + + /// The unqualified `structHelpers` key for a `BridgeType.swiftStruct` name. + /// + /// Matches `ExportedStruct.abiName`, which joins the namespace path with `_`. + static func structKeyBase(forTypeNamed fullName: String) -> String { + fullName.replacingOccurrences(of: ".", with: "_") + } + + /// The unqualified `enumHelpers` key for a `BridgeType.associatedValueEnum` + /// name. Matches `ExportedEnum.name`, which drops the namespace path. + static func enumKeyBase(forTypeNamed fullName: String) -> String { + fullName.components(separatedBy: ".").last ?? fullName + } + + /// The factory building the `{ lower, lift }` helpers for a `@JS` struct. + static func structHelperFactory(_ qualifiedKey: String) -> String { + "__bjs_createStructHelpers_\(qualifiedKey)" + } + + /// The factory building the `{ lower, lift }` helpers for a `@JS` + /// associated-value enum. + static func enumHelperFactory(_ qualifiedKey: String) -> String { + "__bjs_createEnumHelpers_\(qualifiedKey)" + } + + /// The `const` holding the result of one of the factories above. + static func helperConstant(_ qualifiedKey: String) -> String { + "__bjs_helpers_\(qualifiedKey)" + } +} + extension JSGlueVariableScope { // MARK: Parameter @@ -512,14 +585,10 @@ enum ContainerCodecJS { /// so two modules declaring the same type name do not mint the same helper. private static func leafToken(for type: BridgeType, scope: JSGlueVariableScope) -> String { func sanitized(_ name: String) -> String { - String(name.map { $0.isLetter || $0.isNumber || $0 == "_" ? $0 : "_" }) + HelperNaming.sanitized(name) } func qualified(_ name: String) -> String { - let base = sanitized(name) - guard let module = scope.moduleName(declaringType: name) ?? scope.moduleName(declaringType: base) else { - return base - } - return "\(sanitized(module))_\(base)" + scope.qualified(base: name, declaringType: name) } switch type { case .jsObject(nil): @@ -1017,12 +1086,13 @@ struct IntrinsicJSFragment: Sendable { // MARK: - Associated Enum Fragments - static func associatedEnumLowerParameter(enumBase: String) -> IntrinsicJSFragment { + static func associatedEnumLowerParameter(enumName: String) -> IntrinsicJSFragment { IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) let value = arguments[0] + let enumBase = scope.enumHelperKey(forTypeNamed: enumName) let caseIdName = scope.variable("\(value)CaseId") printer.write( "const \(caseIdName) = \(JSGlueVariableScope.reservedEnumHelpers).\(enumBase).lower(\(value));" @@ -1032,11 +1102,12 @@ struct IntrinsicJSFragment: Sendable { ) } - static func associatedEnumLiftReturn(enumBase: String) -> IntrinsicJSFragment { + static func associatedEnumLiftReturn(enumName: String) -> IntrinsicJSFragment { IntrinsicJSFragment( parameters: [], printCode: { _, context in let (scope, printer) = (context.scope, context.printer) + let enumBase = scope.enumHelperKey(forTypeNamed: enumName) let retName = scope.variable("ret") printer.write( "const \(retName) = \(JSGlueVariableScope.reservedEnumHelpers).\(enumBase).lift(\(scope.popI32()));" @@ -1298,12 +1369,12 @@ struct IntrinsicJSFragment: Sendable { fullName: String, kind: JSOptionalKind ) -> IntrinsicJSFragment { - let base = fullName.components(separatedBy: ".").last ?? fullName let absenceLiteral = kind.absenceLiteral return IntrinsicJSFragment( parameters: [], printCode: { _, context in let (scope, printer) = (context.scope, context.printer) + let base = scope.enumHelperKey(forTypeNamed: fullName) let resultVar = scope.variable("optResult") let tagVar = scope.variable("tag") printer.write("const \(tagVar) = \(scope.popI32());") @@ -1648,11 +1719,9 @@ struct IntrinsicJSFragment: Sendable { return try .optionalLowerParameter(wrappedType: wrappedType, kind: kind) case .rawValueEnum(_, .string): return .stringLowerParameter case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - return .associatedEnumLowerParameter(enumBase: base) + return .associatedEnumLowerParameter(enumName: fullName) case .swiftStruct(let fullName): - let base = fullName.replacingOccurrences(of: ".", with: "_") - return swiftStructLowerParameter(structBase: base) + return swiftStructLowerParameter(structName: fullName) case .closure: return IntrinsicJSFragment( parameters: ["closure"], @@ -1708,11 +1777,9 @@ struct IntrinsicJSFragment: Sendable { return try .optionalLiftReturn(wrappedType: wrappedType, kind: kind) case .rawValueEnum(_, .string): return .stringLiftReturn case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName - return .associatedEnumLiftReturn(enumBase: base) + return .associatedEnumLiftReturn(enumName: fullName) case .swiftStruct(let fullName): - let base = fullName.replacingOccurrences(of: ".", with: "_") - return swiftStructLiftReturn(structBase: base) + return swiftStructLiftReturn(structName: fullName) case .closure: return IntrinsicJSFragment( parameters: ["funcRef"], @@ -1771,11 +1838,11 @@ struct IntrinsicJSFragment: Sendable { return try .optionalLiftParameter(wrappedType: wrappedType, kind: kind, context: context) case .rawValueEnum(_, .string): return .stringLiftParameter case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( parameters: ["caseId"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let base = scope.enumHelperKey(forTypeNamed: fullName) let caseId = arguments[0] let resultVar = scope.variable("enumValue") printer.write( @@ -1785,11 +1852,11 @@ struct IntrinsicJSFragment: Sendable { } ) case .swiftStruct(let fullName): - let base = fullName.replacingOccurrences(of: ".", with: "_") return IntrinsicJSFragment( parameters: [], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let base = scope.structHelperKey(forTypeNamed: fullName) let resultVar = scope.variable("structValue") printer.write( "const \(resultVar) = \(JSGlueVariableScope.reservedStructHelpers).\(base).lift();" @@ -1871,11 +1938,11 @@ struct IntrinsicJSFragment: Sendable { // MARK: - Enums Payload Fragments static func associatedValueLowerReturn(fullName: String) -> IntrinsicJSFragment { - let base = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let base = scope.enumHelperKey(forTypeNamed: fullName) let value = arguments[0] let caseIdVar = scope.variable("caseId") printer.write( @@ -1917,14 +1984,24 @@ struct IntrinsicJSFragment: Sendable { /// Generates the enum helper factory function (lower/lift closures). /// This is placed inside `createInstantiator` alongside struct helpers, /// so it has access to `_exports` for class references. - static func associatedValueEnumHelperFactory(enumDefinition: ExportedEnum) -> IntrinsicJSFragment { + /// + /// - Parameter moduleName: The module declaring the enum. The factory + /// identifier is qualified with it so that two modules declaring an enum + /// of the same name don't mint the same `const`. + static func associatedValueEnumHelperFactory( + enumDefinition: ExportedEnum, + moduleName: String + ) -> IntrinsicJSFragment { + let factoryName = HelperNaming.enumHelperFactory( + HelperNaming.qualified(base: enumDefinition.name, module: moduleName) + ) return IntrinsicJSFragment( parameters: ["enumName"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) let enumName = arguments[0] - printer.write("const __bjs_create\(enumName)Helpers = () => ({") + printer.write("const \(factoryName) = () => ({") try printer.indent { printer.write("lower: (value) => {") try printer.indent { @@ -2117,11 +2194,12 @@ struct IntrinsicJSFragment: Sendable { } } - private static func swiftStructLower(structBase: String) -> IntrinsicJSFragment { + private static func swiftStructLower(structName: String) -> IntrinsicJSFragment { IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let printer = context.printer + let structBase = context.scope.structHelperKey(forTypeNamed: structName) let value = arguments[0] printer.write( "\(JSGlueVariableScope.reservedStructHelpers).\(structBase).lower(\(value));" @@ -2132,18 +2210,19 @@ struct IntrinsicJSFragment: Sendable { } static func swiftStructLowerReturn(fullName: String) -> IntrinsicJSFragment { - swiftStructLower(structBase: fullName.replacingOccurrences(of: ".", with: "_")) + swiftStructLower(structName: fullName) } - static func swiftStructLowerParameter(structBase: String) -> IntrinsicJSFragment { - swiftStructLower(structBase: structBase) + static func swiftStructLowerParameter(structName: String) -> IntrinsicJSFragment { + swiftStructLower(structName: structName) } - static func swiftStructLiftReturn(structBase: String) -> IntrinsicJSFragment { + static func swiftStructLiftReturn(structName: String) -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: [], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let structBase = scope.structHelperKey(forTypeNamed: structName) let resultVar = scope.variable("structValue") printer.write( "const \(resultVar) = \(JSGlueVariableScope.reservedStructHelpers).\(structBase).lift();" @@ -2270,11 +2349,11 @@ struct IntrinsicJSFragment: Sendable { } ) case .swiftStruct(let fullName): - let structBase = fullName.replacingOccurrences(of: ".", with: "_") return IntrinsicJSFragment( parameters: [], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let structBase = scope.structHelperKey(forTypeNamed: fullName) let resultVar = scope.variable("struct") printer.write( "const \(resultVar) = \(JSGlueVariableScope.reservedStructHelpers).\(structBase).lift();" @@ -2283,11 +2362,11 @@ struct IntrinsicJSFragment: Sendable { } ) case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( parameters: [], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let base = scope.enumHelperKey(forTypeNamed: fullName) let resultVar = scope.variable("enumValue") printer.write( "const \(resultVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(scope.popI32()));" @@ -2392,11 +2471,11 @@ struct IntrinsicJSFragment: Sendable { } ) case .swiftStruct(let fullName): - let structBase = fullName.replacingOccurrences(of: ".", with: "_") return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let printer = context.printer + let structBase = context.scope.structHelperKey(forTypeNamed: fullName) let value = arguments[0] printer.write( "\(JSGlueVariableScope.reservedStructHelpers).\(structBase).lower(\(value));" @@ -2406,11 +2485,11 @@ struct IntrinsicJSFragment: Sendable { ) case .associatedValueEnum(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let base = scope.enumHelperKey(forTypeNamed: fullName) let value = arguments[0] let caseIdVar = scope.variable("caseId") printer.write( @@ -2495,16 +2574,25 @@ struct IntrinsicJSFragment: Sendable { // MARK: - Struct Helpers - static func structHelper(structDefinition: ExportedStruct, allStructs: [ExportedStruct]) -> IntrinsicJSFragment { + /// - Parameter moduleName: The module declaring the struct. The factory + /// identifier is qualified with it so that two modules declaring a struct + /// of the same name don't mint the same `const`. + static func structHelper( + structDefinition: ExportedStruct, + allStructs: [ExportedStruct], + moduleName: String + ) -> IntrinsicJSFragment { + let factoryName = HelperNaming.structHelperFactory( + HelperNaming.qualified(base: structDefinition.abiName, module: moduleName) + ) return IntrinsicJSFragment( - parameters: ["structName"], + parameters: [], printCode: { arguments, context in let printer = context.printer - let structName = arguments[0] let capturedStructDef = structDefinition let capturedAllStructs = allStructs - printer.write("const __bjs_create\(structName)Helpers = () => ({") + printer.write("const \(factoryName) = () => ({") try printer.indent { printer.write("lower: (value) => {") try printer.indent { @@ -2603,7 +2691,7 @@ struct IntrinsicJSFragment: Sendable { ) try printer.indent { printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(this);" + "\(JSGlueVariableScope.reservedStructHelpers).\(context.scope.structHelperKey(forTypeNamed: structDef.abiName)).lower(this);" ) var paramForwardings: [String] = [] @@ -2674,9 +2762,10 @@ struct IntrinsicJSFragment: Sendable { parameters: ["value"], printCode: { arguments, context in let printer = context.printer + let nestedBase = context.scope.structHelperKey(forTypeNamed: nestedName) let value = arguments[0] printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lower(\(value));" + "\(JSGlueVariableScope.reservedStructHelpers).\(nestedBase).lower(\(value));" ) return [] } @@ -2713,9 +2802,10 @@ struct IntrinsicJSFragment: Sendable { parameters: [], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) + let nestedBase = scope.structHelperKey(forTypeNamed: nestedName) let structVar = scope.variable("struct") printer.write( - "const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lift();" + "const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedBase).lift();" ) return [structVar] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index 3fd696027..87e3f2b7e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -205,28 +205,116 @@ import Testing } @Test - func sameTypeNameAcrossModulesLinksWithHandleIdentity() throws { + func distinctTypeNamesAcrossModulesLinkWithHandleIdentity() throws { // Type identity is pointer-based (each type owns a BridgeJSTypeHandle), - // so two modules defining a same-named @JS type must link fine: each - // module registers its own handle IDs against its own codec array. - let structSource = """ + // so each module registers its own handle IDs against its own codec + // array, and every identifier minted from a type name is qualified with + // the declaring module. + let first = try makeSkeleton( + """ @JS public struct Point { public var x: Int @JS public init(x: Int) { self.x = x } } - """ - let first = try makeSkeleton( - structSource + """ - @JSFunction func identity(_ value: T) throws(JSException) -> T - """, + @JSFunction func identity(_ value: T) throws(JSException) -> T + """, moduleName: "FirstModule" ) - let second = try makeSkeleton(structSource, moduleName: "SecondModule") + let second = try makeSkeleton( + """ + @JS public struct Coordinate { + public var x: Int + @JS public init(x: Int) { self.x = x } + } + """, + moduleName: "SecondModule" + ) let bridgeJSLink = BridgeJSLink(skeletons: [first, second], sharedMemory: false) let js = try bridgeJSLink.link().outputJs #expect(js.contains("bjs[\"bjs_FirstModule_register_type_handles\"] = function(base, count) {")) #expect(js.contains("bjs[\"bjs_SecondModule_register_type_handles\"] = function(base, count) {")) + + // Each module's helper factory, the `const` holding it, and the + // `structHelpers` key are all module-qualified, so nothing collides. + #expect(js.contains("const __bjs_createStructHelpers_FirstModule_Point = () => ({")) + #expect(js.contains("const __bjs_createStructHelpers_SecondModule_Coordinate = () => ({")) + #expect( + js.contains( + "const __bjs_helpers_FirstModule_Point = __bjs_createStructHelpers_FirstModule_Point();" + ) + ) + #expect(js.contains("structHelpers.FirstModule_Point = __bjs_helpers_FirstModule_Point;")) + #expect(js.contains("structHelpers.SecondModule_Coordinate = __bjs_helpers_SecondModule_Coordinate;")) + // References resolve to the declaring module's entry, not to a bare name. + #expect(!js.contains("structHelpers.Point")) + #expect(!js.contains("structHelpers.Coordinate")) + } + + /// Two modules declaring a `@JS` type of the same name cannot be linked into + /// one glue module: `BridgeType` carries only the type name, the top-level + /// `const Values` / `class ` declarations are minted from it, and + /// so are the `bjs["swift_js_struct_*_"]` wasm import names. The + /// link step rejects them instead of emitting glue that throws at load time + /// or binds one module's values to the other module's helpers. + @Test(arguments: [ + ( + "struct", + """ + @JS public struct Point { + public var x: Int + @JS public init(x: Int) { self.x = x } + } + """, + "Duplicate @JS struct 'Point' declared by modules 'FirstModule' and 'SecondModule'." + ), + ( + "enum", + """ + @JS public enum Tagged { + case number(Int) + case text(String) + } + """, + "Duplicate @JS enum 'Tagged' declared by modules 'FirstModule' and 'SecondModule'." + ), + ( + "class", + """ + @JS public class Box { + @JS public init() {} + } + """, + "Duplicate @JS class 'Box' declared by modules 'FirstModule' and 'SecondModule'." + ), + ]) + func sameTypeNameAcrossModulesIsRejected(kind: String, source: String, expectedMessage: String) throws { + let first = try makeSkeleton(source, moduleName: "FirstModule") + let second = try makeSkeleton(source, moduleName: "SecondModule") + let bridgeJSLink = BridgeJSLink(skeletons: [first, second], sharedMemory: false) + #expect(throws: BridgeJSLinkError.self) { + _ = try bridgeJSLink.link() + } + do { + _ = try bridgeJSLink.link() + } catch let error as BridgeJSLinkError { + #expect(error.message.contains(expectedMessage)) + #expect(error.message.contains("Rename one of them")) + } + } + + /// A namespace enum declares no runtime value of its own, so two modules may + /// keep contributing to the same namespace. + @Test + func sameNamespaceEnumNameAcrossModulesIsAllowed() throws { + let source = """ + @JS public enum Shared { + @JS public static func ping() -> Int { 0 } + } + """ + let first = try makeSkeleton(source, moduleName: "FirstModule") + let second = try makeSkeleton(source, moduleName: "SecondModule") + _ = try BridgeJSLink(skeletons: [first, second], sharedMemory: false).link() } @Test @@ -267,8 +355,8 @@ import Testing #expect(js.contains("instance.exports[\"bjs_Core_register_type_handles\"]();")) #expect(!js.contains("bjs_App_register_type_handles")) // `lower(v)` is unique to a codec literal in a registration array; - // `structHelpers.Vector3D` on its own is emitted for every @JS struct. - #expect(js.contains("structHelpers.Vector3D.lower(v);")) + // `structHelpers.Core_Vector3D` on its own is emitted for every @JS struct. + #expect(js.contains("structHelpers.Core_Vector3D.lower(v);")) } @Test diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift index 4e73e02d7..c5464c78f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/NamedCodecHelperTests.swift @@ -82,7 +82,7 @@ import Testing .map { $0.components(separatedBy: "];")[0] } #expect(registrationArray?.contains("__bjs_codec_Core_Point,") == true) // The struct's marshalling code is emitted once, in its helper factory. - #expect(js.components(separatedBy: "structHelpers.Point.lower(v);").count - 1 == 1) + #expect(js.components(separatedBy: "structHelpers.Core_Point.lower(v);").count - 1 == 1) } /// A string-backed raw value enum bridges exactly as `String`, so it shares diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js index d70db0f42..53755e3a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js @@ -373,11 +373,11 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Array_TestModule_PolygonReference = __bjs_arrayCodec(__bjs_codec_TestModule_PolygonReference); const __bjs_codec_TestModule_InnerTag = { lower: (v) => { - const caseId = enumHelpers.InnerTag.lower(v); + const caseId = enumHelpers.TestModule_InnerTag.lower(v); i32Stack.push(caseId); }, lift: () => { - const enumValue = enumHelpers.InnerTag.lift(i32Stack.pop()); + const enumValue = enumHelpers.TestModule_InnerTag.lift(i32Stack.pop()); return enumValue; }, }; @@ -397,7 +397,7 @@ export async function createInstantiator(options, swift) { }; const __bjs_codec_Optional_TestModule_Surface = __bjs_optionalCodec(__bjs_codec_TestModule_Surface); - const __bjs_createInnerTagValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_InnerTag = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -774,8 +774,8 @@ export async function createInstantiator(options, swift) { return TagReference.__construct(ret); } } - const InnerTagHelpers = __bjs_createInnerTagValuesHelpers(); - enumHelpers.InnerTag = InnerTagHelpers; + const __bjs_helpers_TestModule_InnerTag = __bjs_createEnumHelpers_TestModule_InnerTag(); + enumHelpers.TestModule_InnerTag = __bjs_helpers_TestModule_InnerTag; const exports = { roundtripPolygon: function bjs_roundtripPolygon(polygon) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index aaa9460c8..e5b8438d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -373,10 +373,10 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Array_Bool = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool); const __bjs_codec_TestModule_Point = { lower: (v) => { - structHelpers.Point.lower(v); + structHelpers.TestModule_Point.lower(v); }, lift: () => { - const struct = structHelpers.Point.lift(); + const struct = structHelpers.TestModule_Point.lift(); return struct; }, }; @@ -475,7 +475,7 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Array_Array_JSObject = __bjs_arrayCodec(__bjs_codec_Array_JSObject); const __bjs_codec_Optional_Array_String = __bjs_optionalCodec(__bjs_codec_Array_String); - const __bjs_createPointHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Point = () => ({ lower: (value) => { f64Stack.push(value.x); f64Stack.push(value.y); @@ -563,10 +563,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Point"] = function(objectId) { - structHelpers.Point.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Point.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Point"] = function() { - const value = structHelpers.Point.lift(); + const value = structHelpers.TestModule_Point.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -832,8 +832,8 @@ export async function createInstantiator(options, swift) { return arrayResult; } } - const PointHelpers = __bjs_createPointHelpers(); - structHelpers.Point = PointHelpers; + const __bjs_helpers_TestModule_Point = __bjs_createStructHelpers_TestModule_Point(); + structHelpers.TestModule_Point = __bjs_helpers_TestModule_Point; const exports = { processIntArray: function bjs_processIntArray(values) { @@ -888,7 +888,7 @@ export async function createInstantiator(options, swift) { const matchingBytes = textEncoder.encode(matching); const matchingId = swift.memory.retain(matchingBytes); instance.exports.bjs_findFirstPoint(matchingId, matchingBytes.length); - const structValue = structHelpers.Point.lift(); + const structValue = structHelpers.TestModule_Point.lift(); return structValue; }, processUnsafeRawPointerArray: function bjs_processUnsafeRawPointerArray(values) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 2b667aefa..ea86e699e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -366,10 +366,10 @@ export async function createInstantiator(options, swift) { const __bjs_codec_TestModule_AsyncPoint = { lower: (v) => { - structHelpers.AsyncPoint.lower(v); + structHelpers.TestModule_AsyncPoint.lower(v); }, lift: () => { - const struct = structHelpers.AsyncPoint.lift(); + const struct = structHelpers.TestModule_AsyncPoint.lift(); return struct; }, }; @@ -388,7 +388,7 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Dict_TestModule_AsyncPoint = __bjs_dictCodec(__bjs_codec_TestModule_AsyncPoint); const __bjs_codec_Dict_TestModule_AsyncDirection = __bjs_dictCodec(__bjs_codec_TestModule_AsyncDirection); - const __bjs_createAsyncPointHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_AsyncPoint = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); i32Stack.push((value.y | 0)); @@ -475,10 +475,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_AsyncPoint"] = function(objectId) { - structHelpers.AsyncPoint.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_AsyncPoint.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_AsyncPoint"] = function() { - const value = structHelpers.AsyncPoint.lift(); + const value = structHelpers.TestModule_AsyncPoint.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -542,7 +542,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_10AsyncPointV"] = function(promise) { try { - const structValue = structHelpers.AsyncPoint.lift(); + const structValue = structHelpers.TestModule_AsyncPoint.lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(structValue); } catch (error) { setException(error); @@ -588,7 +588,7 @@ export async function createInstantiator(options, swift) { try { let optResult; if (value) { - const struct = structHelpers.AsyncPoint.lift(); + const struct = structHelpers.TestModule_AsyncPoint.lift(); optResult = struct; } else { optResult = null; @@ -742,8 +742,8 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const AsyncPointHelpers = __bjs_createAsyncPointHelpers(); - structHelpers.AsyncPoint = AsyncPointHelpers; + const __bjs_helpers_TestModule_AsyncPoint = __bjs_createStructHelpers_TestModule_AsyncPoint(); + structHelpers.TestModule_AsyncPoint = __bjs_helpers_TestModule_AsyncPoint; const exports = { asyncReturnVoid: function bjs_asyncReturnVoid() { @@ -791,14 +791,14 @@ export async function createInstantiator(options, swift) { return ret1; }, asyncRoundTripStruct: function bjs_asyncRoundTripStruct(v) { - structHelpers.AsyncPoint.lower(v); + structHelpers.TestModule_AsyncPoint.lower(v); const ret = instance.exports.bjs_asyncRoundTripStruct(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); return ret1; }, asyncRoundTripStructThrows: function bjs_asyncRoundTripStructThrows(v) { - structHelpers.AsyncPoint.lower(v); + structHelpers.TestModule_AsyncPoint.lower(v); const ret = instance.exports.bjs_asyncRoundTripStructThrows(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); @@ -823,8 +823,8 @@ export async function createInstantiator(options, swift) { return ret1; }, asyncCombineStructs: function bjs_asyncCombineStructs(a, b) { - structHelpers.AsyncPoint.lower(a); - structHelpers.AsyncPoint.lower(b); + structHelpers.TestModule_AsyncPoint.lower(a); + structHelpers.TestModule_AsyncPoint.lower(b); const ret = instance.exports.bjs_asyncCombineStructs(); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js index 5671e4898..04d9ca992 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js @@ -127,7 +127,7 @@ export async function createInstantiator(options, swift) { return jsValue; } - const __bjs_createAsyncPayloadResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_AsyncPayloadResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -250,7 +250,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_18AsyncPayloadResultO"] = function(promise, value) { try { - const enumValue = enumHelpers.AsyncPayloadResult.lift(value); + const enumValue = enumHelpers.TestModule_AsyncPayloadResult.lift(value); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(enumValue); } catch (error) { setException(error); @@ -260,7 +260,7 @@ export async function createInstantiator(options, swift) { try { let optResult; if (valueIsSome) { - const enumValue = enumHelpers.AsyncPayloadResult.lift(valueCaseId); + const enumValue = enumHelpers.TestModule_AsyncPayloadResult.lift(valueCaseId); optResult = enumValue; } else { optResult = null; @@ -382,12 +382,12 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const AsyncPayloadResultHelpers = __bjs_createAsyncPayloadResultValuesHelpers(); - enumHelpers.AsyncPayloadResult = AsyncPayloadResultHelpers; + const __bjs_helpers_TestModule_AsyncPayloadResult = __bjs_createEnumHelpers_TestModule_AsyncPayloadResult(); + enumHelpers.TestModule_AsyncPayloadResult = __bjs_helpers_TestModule_AsyncPayloadResult; const exports = { asyncRoundTripAssociatedValueEnum: function bjs_asyncRoundTripAssociatedValueEnum(value) { - const valueCaseId = enumHelpers.AsyncPayloadResult.lower(value); + const valueCaseId = enumHelpers.TestModule_AsyncPayloadResult.lower(value); const ret = instance.exports.bjs_asyncRoundTripAssociatedValueEnum(valueCaseId); const ret1 = swift.memory.getObject(ret); swift.memory.release(ret); @@ -397,7 +397,7 @@ export async function createInstantiator(options, swift) { const isSome = value != null; let result; if (isSome) { - const valueCaseId = enumHelpers.AsyncPayloadResult.lower(value); + const valueCaseId = enumHelpers.TestModule_AsyncPayloadResult.lower(value); result = valueCaseId; } else { result = 0; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js index 30d0522c0..fa74b5097 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ClassWithNestedTypes.js @@ -36,7 +36,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createAccount_CredentialsHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Account_Credentials = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.token); const id = swift.memory.retain(bytes); @@ -124,10 +124,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Account_Credentials"] = function(objectId) { - structHelpers.Account_Credentials.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Account_Credentials.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Account_Credentials"] = function() { - const value = structHelpers.Account_Credentials.lift(); + const value = structHelpers.TestModule_Account_Credentials.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -344,8 +344,8 @@ export async function createInstantiator(options, swift) { return ret; } } - const Account_CredentialsHelpers = __bjs_createAccount_CredentialsHelpers(); - structHelpers.Account_Credentials = Account_CredentialsHelpers; + const __bjs_helpers_TestModule_Account_Credentials = __bjs_createStructHelpers_TestModule_Account_Credentials(); + structHelpers.TestModule_Account_Credentials = __bjs_helpers_TestModule_Account_Credentials; const exports = { Account: Object.assign(Account, { @@ -355,7 +355,7 @@ export async function createInstantiator(options, swift) { const tokenBytes = textEncoder.encode(token); const tokenId = swift.memory.retain(tokenBytes); instance.exports.bjs_Account_Credentials_init(tokenId, tokenBytes.length); - const structValue = structHelpers.Account_Credentials.lift(); + const structValue = structHelpers.TestModule_Account_Credentials.lift(); return structValue; }, get maxLength() { @@ -364,7 +364,7 @@ export async function createInstantiator(options, swift) { }, empty: function() { instance.exports.bjs_Account_Credentials_static_empty(); - const structValue = structHelpers.Account_Credentials.lift(); + const structValue = structHelpers.TestModule_Account_Credentials.lift(); return structValue; }, }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index 3dc39e445..e41408943 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -362,10 +362,10 @@ export async function createInstantiator(options, swift) { const __bjs_codec_TestModule_Config = { lower: (v) => { - structHelpers.Config.lower(v); + structHelpers.TestModule_Config.lower(v); }, lift: () => { - const struct = structHelpers.Config.lift(); + const struct = structHelpers.TestModule_Config.lift(); return struct; }, }; @@ -375,7 +375,7 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Array_Double = __bjs_arrayCodec(__bjs_primitiveCodecs.Double); const __bjs_codec_Array_Bool = __bjs_arrayCodec(__bjs_primitiveCodecs.Bool); - const __bjs_createConfigHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Config = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); const id = swift.memory.retain(bytes); @@ -391,7 +391,7 @@ export async function createInstantiator(options, swift) { return { name: string, value: int, enabled: bool }; } }); - const __bjs_createMathOperationsHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_MathOperations = () => ({ lower: (value) => { f64Stack.push(value.baseValue); }, @@ -399,12 +399,12 @@ export async function createInstantiator(options, swift) { const f64 = f64Stack.pop(); const instance1 = { baseValue: f64 }; instance1.add = function(a, b = 10.0) { - structHelpers.MathOperations.lower(this); + structHelpers.TestModule_MathOperations.lower(this); const ret = instance.exports.bjs_MathOperations_add(a, b); return ret; }.bind(instance1); instance1.multiply = function(a, b) { - structHelpers.MathOperations.lower(this); + structHelpers.TestModule_MathOperations.lower(this); const ret1 = instance.exports.bjs_MathOperations_multiply(a, b); return ret1; }.bind(instance1); @@ -487,17 +487,17 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Config"] = function(objectId) { - structHelpers.Config.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Config.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Config"] = function() { - const value = structHelpers.Config.lift(); + const value = structHelpers.TestModule_Config.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_MathOperations"] = function(objectId) { - structHelpers.MathOperations.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_MathOperations.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_MathOperations"] = function() { - const value = structHelpers.MathOperations.lift(); + const value = structHelpers.TestModule_MathOperations.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -789,11 +789,11 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_ConstructorDefaults_tag_set(this.pointer, +isSome, result, result1); } } - const ConfigHelpers = __bjs_createConfigHelpers(); - structHelpers.Config = ConfigHelpers; + const __bjs_helpers_TestModule_Config = __bjs_createStructHelpers_TestModule_Config(); + structHelpers.TestModule_Config = __bjs_helpers_TestModule_Config; - const MathOperationsHelpers = __bjs_createMathOperationsHelpers(); - structHelpers.MathOperations = MathOperationsHelpers; + const __bjs_helpers_TestModule_MathOperations = __bjs_createStructHelpers_TestModule_MathOperations(); + structHelpers.TestModule_MathOperations = __bjs_helpers_TestModule_MathOperations; const exports = { testStringDefault: function bjs_testStringDefault(message = "Hello World") { @@ -932,7 +932,7 @@ export async function createInstantiator(options, swift) { MathOperations: { init: function(baseValue = 0.0) { instance.exports.bjs_MathOperations_init(baseValue); - const structValue = structHelpers.MathOperations.lift(); + const structValue = structHelpers.TestModule_MathOperations.lift(); return structValue; }, subtract: function(a, b = 5.0) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 6d8ea7392..0de3fde05 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -376,7 +376,7 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Optional_Int = __bjs_optionalCodec(__bjs_primitiveCodecs.Int); const __bjs_codec_Dict_Optional_Int = __bjs_dictCodec(__bjs_codec_Optional_Int); - const __bjs_createCountersHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Counters = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); const id = swift.memory.retain(bytes); @@ -467,10 +467,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Counters"] = function(objectId) { - structHelpers.Counters.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Counters.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Counters"] = function() { - const value = structHelpers.Counters.lift(); + const value = structHelpers.TestModule_Counters.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -662,8 +662,8 @@ export async function createInstantiator(options, swift) { } } - const CountersHelpers = __bjs_createCountersHelpers(); - structHelpers.Counters = CountersHelpers; + const __bjs_helpers_TestModule_Counters = __bjs_createStructHelpers_TestModule_Counters(); + structHelpers.TestModule_Counters = __bjs_helpers_TestModule_Counters; const exports = { mirrorDictionary: function bjs_mirrorDictionary(values) { @@ -697,9 +697,9 @@ export async function createInstantiator(options, swift) { return dictResult; }, roundtripCounters: function bjs_roundtripCounters(counters) { - structHelpers.Counters.lower(counters); + structHelpers.TestModule_Counters.lower(counters); instance.exports.bjs_roundtripCounters(); - const structValue = structHelpers.Counters.lift(); + const structValue = structHelpers.TestModule_Counters.lift(); return structValue; }, Box, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js index 65323aace..fffb28b1e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DocComments.js @@ -37,7 +37,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createPointHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Point = () => ({ lower: (value) => { f64Stack.push(value.x); f64Stack.push(value.y); @@ -124,10 +124,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Point"] = function(objectId) { - structHelpers.Point.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Point.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Point"] = function() { - const value = structHelpers.Point.lift(); + const value = structHelpers.TestModule_Point.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -349,8 +349,8 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } } - const PointHelpers = __bjs_createPointHelpers(); - structHelpers.Point = PointHelpers; + const __bjs_helpers_TestModule_Point = __bjs_createStructHelpers_TestModule_Point(); + structHelpers.TestModule_Point = __bjs_helpers_TestModule_Point; const exports = { greet: function bjs_greet(name, greeting = "Hello") { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 2a8ed684c..a22b38137 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -461,10 +461,10 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); const __bjs_codec_TestModule_Point = { lower: (v) => { - structHelpers.Point.lower(v); + structHelpers.TestModule_Point.lower(v); }, lift: () => { - const struct = structHelpers.Point.lift(); + const struct = structHelpers.TestModule_Point.lift(); return struct; }, }; @@ -495,18 +495,18 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Optional_JSObject = __bjs_optionalCodec(__bjs_codec_JSObject); const __bjs_codec_TestModule_APIResult = { lower: (v) => { - const caseId = enumHelpers.APIResult.lower(v); + const caseId = enumHelpers.TestModule_APIResult.lower(v); i32Stack.push(caseId); }, lift: () => { - const enumValue = enumHelpers.APIResult.lift(i32Stack.pop()); + const enumValue = enumHelpers.TestModule_APIResult.lift(i32Stack.pop()); return enumValue; }, }; const __bjs_codec_Optional_TestModule_APIResult = __bjs_optionalCodec(__bjs_codec_TestModule_APIResult); const __bjs_codec_Optional_Array_Int = __bjs_optionalCodec(__bjs_codec_Array_Int); - const __bjs_createPointHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Point = () => ({ lower: (value) => { f64Stack.push(value.x); f64Stack.push(value.y); @@ -517,7 +517,7 @@ export async function createInstantiator(options, swift) { return { x: f641, y: f64 }; } }); - const __bjs_createAPIResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_APIResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -578,7 +578,7 @@ export async function createInstantiator(options, swift) { } } }); - const __bjs_createComplexResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_ComplexResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -680,7 +680,7 @@ export async function createInstantiator(options, swift) { } } }); - const __bjs_createResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_Result = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -733,7 +733,7 @@ export async function createInstantiator(options, swift) { } } }); - const __bjs_createNetworkingResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_NetworkingResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -771,7 +771,7 @@ export async function createInstantiator(options, swift) { } } }); - const __bjs_createAPIOptionalResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_APIOptionalResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -815,7 +815,7 @@ export async function createInstantiator(options, swift) { } } }); - const __bjs_createTypedPayloadResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_TypedPayloadResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -865,12 +865,12 @@ export async function createInstantiator(options, swift) { } } }); - const __bjs_createAllTypesResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_AllTypesResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { case AllTypesResultValues.Tag.StructPayload: { - structHelpers.Point.lower(value.param0); + structHelpers.TestModule_Point.lower(value.param0); return AllTypesResultValues.Tag.StructPayload; } case AllTypesResultValues.Tag.ClassPayload: { @@ -883,7 +883,7 @@ export async function createInstantiator(options, swift) { return AllTypesResultValues.Tag.JsObjectPayload; } case AllTypesResultValues.Tag.NestedEnum: { - const caseId = enumHelpers.APIResult.lower(value.param0); + const caseId = enumHelpers.TestModule_APIResult.lower(value.param0); i32Stack.push(caseId); return AllTypesResultValues.Tag.NestedEnum; } @@ -901,7 +901,7 @@ export async function createInstantiator(options, swift) { tag = tag | 0; switch (tag) { case AllTypesResultValues.Tag.StructPayload: { - const struct = structHelpers.Point.lift(); + const struct = structHelpers.TestModule_Point.lift(); return { tag: AllTypesResultValues.Tag.StructPayload, param0: struct }; } case AllTypesResultValues.Tag.ClassPayload: { @@ -916,7 +916,7 @@ export async function createInstantiator(options, swift) { return { tag: AllTypesResultValues.Tag.JsObjectPayload, param0: obj }; } case AllTypesResultValues.Tag.NestedEnum: { - const enumValue = enumHelpers.APIResult.lift(i32Stack.pop()); + const enumValue = enumHelpers.TestModule_APIResult.lift(i32Stack.pop()); return { tag: AllTypesResultValues.Tag.NestedEnum, param0: enumValue }; } case AllTypesResultValues.Tag.ArrayPayload: { @@ -928,7 +928,7 @@ export async function createInstantiator(options, swift) { } } }); - const __bjs_createOptionalAllTypesResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_OptionalAllTypesResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -1062,10 +1062,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Point"] = function(objectId) { - structHelpers.Point.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Point.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Point"] = function() { - const value = structHelpers.Point.lift(); + const value = structHelpers.TestModule_Point.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -1247,139 +1247,139 @@ export async function createInstantiator(options, swift) { } } - const PointHelpers = __bjs_createPointHelpers(); - structHelpers.Point = PointHelpers; + const __bjs_helpers_TestModule_Point = __bjs_createStructHelpers_TestModule_Point(); + structHelpers.TestModule_Point = __bjs_helpers_TestModule_Point; - const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); - enumHelpers.APIResult = APIResultHelpers; + const __bjs_helpers_TestModule_APIResult = __bjs_createEnumHelpers_TestModule_APIResult(); + enumHelpers.TestModule_APIResult = __bjs_helpers_TestModule_APIResult; - const ComplexResultHelpers = __bjs_createComplexResultValuesHelpers(); - enumHelpers.ComplexResult = ComplexResultHelpers; + const __bjs_helpers_TestModule_ComplexResult = __bjs_createEnumHelpers_TestModule_ComplexResult(); + enumHelpers.TestModule_ComplexResult = __bjs_helpers_TestModule_ComplexResult; - const ResultHelpers = __bjs_createResultValuesHelpers(); - enumHelpers.Result = ResultHelpers; + const __bjs_helpers_TestModule_Result = __bjs_createEnumHelpers_TestModule_Result(); + enumHelpers.TestModule_Result = __bjs_helpers_TestModule_Result; - const NetworkingResultHelpers = __bjs_createNetworkingResultValuesHelpers(); - enumHelpers.NetworkingResult = NetworkingResultHelpers; + const __bjs_helpers_TestModule_NetworkingResult = __bjs_createEnumHelpers_TestModule_NetworkingResult(); + enumHelpers.TestModule_NetworkingResult = __bjs_helpers_TestModule_NetworkingResult; - const APIOptionalResultHelpers = __bjs_createAPIOptionalResultValuesHelpers(); - enumHelpers.APIOptionalResult = APIOptionalResultHelpers; + const __bjs_helpers_TestModule_APIOptionalResult = __bjs_createEnumHelpers_TestModule_APIOptionalResult(); + enumHelpers.TestModule_APIOptionalResult = __bjs_helpers_TestModule_APIOptionalResult; - const TypedPayloadResultHelpers = __bjs_createTypedPayloadResultValuesHelpers(); - enumHelpers.TypedPayloadResult = TypedPayloadResultHelpers; + const __bjs_helpers_TestModule_TypedPayloadResult = __bjs_createEnumHelpers_TestModule_TypedPayloadResult(); + enumHelpers.TestModule_TypedPayloadResult = __bjs_helpers_TestModule_TypedPayloadResult; - const AllTypesResultHelpers = __bjs_createAllTypesResultValuesHelpers(); - enumHelpers.AllTypesResult = AllTypesResultHelpers; + const __bjs_helpers_TestModule_AllTypesResult = __bjs_createEnumHelpers_TestModule_AllTypesResult(); + enumHelpers.TestModule_AllTypesResult = __bjs_helpers_TestModule_AllTypesResult; - const OptionalAllTypesResultHelpers = __bjs_createOptionalAllTypesResultValuesHelpers(); - enumHelpers.OptionalAllTypesResult = OptionalAllTypesResultHelpers; + const __bjs_helpers_TestModule_OptionalAllTypesResult = __bjs_createEnumHelpers_TestModule_OptionalAllTypesResult(); + enumHelpers.TestModule_OptionalAllTypesResult = __bjs_helpers_TestModule_OptionalAllTypesResult; const exports = { handle: function bjs_handle(result) { - const resultCaseId = enumHelpers.APIResult.lower(result); + const resultCaseId = enumHelpers.TestModule_APIResult.lower(result); instance.exports.bjs_handle(resultCaseId); }, getResult: function bjs_getResult() { instance.exports.bjs_getResult(); - const ret = enumHelpers.APIResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_APIResult.lift(i32Stack.pop()); return ret; }, roundtripAPIResult: function bjs_roundtripAPIResult(result) { - const resultCaseId = enumHelpers.APIResult.lower(result); + const resultCaseId = enumHelpers.TestModule_APIResult.lower(result); instance.exports.bjs_roundtripAPIResult(resultCaseId); - const ret = enumHelpers.APIResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_APIResult.lift(i32Stack.pop()); return ret; }, roundTripOptionalAPIResult: function bjs_roundTripOptionalAPIResult(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.APIResult.lower(result); + const resultCaseId = enumHelpers.TestModule_APIResult.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalAPIResult(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.APIResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_APIResult.lift(tag); return optResult; }, handleComplex: function bjs_handleComplex(result) { - const resultCaseId = enumHelpers.ComplexResult.lower(result); + const resultCaseId = enumHelpers.TestModule_ComplexResult.lower(result); instance.exports.bjs_handleComplex(resultCaseId); }, getComplexResult: function bjs_getComplexResult() { instance.exports.bjs_getComplexResult(); - const ret = enumHelpers.ComplexResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_ComplexResult.lift(i32Stack.pop()); return ret; }, roundtripComplexResult: function bjs_roundtripComplexResult(result) { - const resultCaseId = enumHelpers.ComplexResult.lower(result); + const resultCaseId = enumHelpers.TestModule_ComplexResult.lower(result); instance.exports.bjs_roundtripComplexResult(resultCaseId); - const ret = enumHelpers.ComplexResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_ComplexResult.lift(i32Stack.pop()); return ret; }, roundTripOptionalComplexResult: function bjs_roundTripOptionalComplexResult(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.ComplexResult.lower(result); + const resultCaseId = enumHelpers.TestModule_ComplexResult.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalComplexResult(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.ComplexResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_ComplexResult.lift(tag); return optResult; }, roundTripOptionalUtilitiesResult: function bjs_roundTripOptionalUtilitiesResult(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.Result.lower(result); + const resultCaseId = enumHelpers.TestModule_Result.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalUtilitiesResult(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.Result.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_Result.lift(tag); return optResult; }, roundTripOptionalNetworkingResult: function bjs_roundTripOptionalNetworkingResult(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.NetworkingResult.lower(result); + const resultCaseId = enumHelpers.TestModule_NetworkingResult.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalNetworkingResult(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.NetworkingResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_NetworkingResult.lift(tag); return optResult; }, roundTripOptionalAPIOptionalResult: function bjs_roundTripOptionalAPIOptionalResult(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.APIOptionalResult.lower(result); + const resultCaseId = enumHelpers.TestModule_APIOptionalResult.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalAPIOptionalResult(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.APIOptionalResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_APIOptionalResult.lift(tag); return optResult; }, compareAPIResults: function bjs_compareAPIResults(result1, result2) { const isSome = result1 != null; let result; if (isSome) { - const result1CaseId = enumHelpers.APIOptionalResult.lower(result1); + const result1CaseId = enumHelpers.TestModule_APIOptionalResult.lower(result1); result = result1CaseId; } else { result = 0; @@ -1387,74 +1387,74 @@ export async function createInstantiator(options, swift) { const isSome1 = result2 != null; let result3; if (isSome1) { - const result2CaseId = enumHelpers.APIOptionalResult.lower(result2); + const result2CaseId = enumHelpers.TestModule_APIOptionalResult.lower(result2); result3 = result2CaseId; } else { result3 = 0; } instance.exports.bjs_compareAPIResults(+isSome, result, +isSome1, result3); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.APIOptionalResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_APIOptionalResult.lift(tag); return optResult; }, roundTripTypedPayloadResult: function bjs_roundTripTypedPayloadResult(result) { - const resultCaseId = enumHelpers.TypedPayloadResult.lower(result); + const resultCaseId = enumHelpers.TestModule_TypedPayloadResult.lower(result); instance.exports.bjs_roundTripTypedPayloadResult(resultCaseId); - const ret = enumHelpers.TypedPayloadResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_TypedPayloadResult.lift(i32Stack.pop()); return ret; }, roundTripOptionalTypedPayloadResult: function bjs_roundTripOptionalTypedPayloadResult(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.TypedPayloadResult.lower(result); + const resultCaseId = enumHelpers.TestModule_TypedPayloadResult.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalTypedPayloadResult(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.TypedPayloadResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_TypedPayloadResult.lift(tag); return optResult; }, roundTripAllTypesResult: function bjs_roundTripAllTypesResult(result) { - const resultCaseId = enumHelpers.AllTypesResult.lower(result); + const resultCaseId = enumHelpers.TestModule_AllTypesResult.lower(result); instance.exports.bjs_roundTripAllTypesResult(resultCaseId); - const ret = enumHelpers.AllTypesResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_AllTypesResult.lift(i32Stack.pop()); return ret; }, roundTripOptionalAllTypesResult: function bjs_roundTripOptionalAllTypesResult(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.AllTypesResult.lower(result); + const resultCaseId = enumHelpers.TestModule_AllTypesResult.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalAllTypesResult(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.AllTypesResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_AllTypesResult.lift(tag); return optResult; }, roundTripOptionalPayloadResult: function bjs_roundTripOptionalPayloadResult(result) { - const resultCaseId = enumHelpers.OptionalAllTypesResult.lower(result); + const resultCaseId = enumHelpers.TestModule_OptionalAllTypesResult.lower(result); instance.exports.bjs_roundTripOptionalPayloadResult(resultCaseId); - const ret = enumHelpers.OptionalAllTypesResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_OptionalAllTypesResult.lift(i32Stack.pop()); return ret; }, roundTripOptionalPayloadResultOpt: function bjs_roundTripOptionalPayloadResultOpt(result) { const isSome = result != null; let result1; if (isSome) { - const resultCaseId = enumHelpers.OptionalAllTypesResult.lower(result); + const resultCaseId = enumHelpers.TestModule_OptionalAllTypesResult.lower(result); result1 = resultCaseId; } else { result1 = 0; } instance.exports.bjs_roundTripOptionalPayloadResultOpt(+isSome, result1); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.OptionalAllTypesResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_OptionalAllTypesResult.lift(tag); return optResult; }, APIResult: APIResultValues, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js index bc0df916b..046bd8bab 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js @@ -38,7 +38,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createPayloadSignalValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_PayloadSignal = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -252,9 +252,9 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_PayloadSignalControls_roundTrip_static"] = function bjs_PayloadSignalControls_roundTrip_static(signal) { try { - const enumValue = enumHelpers.PayloadSignal.lift(signal); + const enumValue = enumHelpers.TestModule_PayloadSignal.lift(signal); let ret = imports.PayloadSignalControls.roundTrip(enumValue); - const caseId = enumHelpers.PayloadSignal.lower(ret); + const caseId = enumHelpers.TestModule_PayloadSignal.lower(ret); return caseId; } catch (error) { setException(error); @@ -262,7 +262,7 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_PayloadSignalControls_send"] = function bjs_PayloadSignalControls_send(self, signal) { try { - const enumValue = enumHelpers.PayloadSignal.lift(signal); + const enumValue = enumHelpers.TestModule_PayloadSignal.lift(signal); swift.memory.getObject(self).send(enumValue); } catch (error) { setException(error); @@ -271,7 +271,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_PayloadSignalControls_current"] = function bjs_PayloadSignalControls_current(self) { try { let ret = swift.memory.getObject(self).current(); - const caseId = enumHelpers.PayloadSignal.lower(ret); + const caseId = enumHelpers.TestModule_PayloadSignal.lower(ret); return caseId; } catch (error) { setException(error); @@ -281,7 +281,7 @@ export async function createInstantiator(options, swift) { try { let optResult; if (signalIsSome) { - const enumValue = enumHelpers.PayloadSignal.lift(signalCaseId); + const enumValue = enumHelpers.TestModule_PayloadSignal.lift(signalCaseId); optResult = enumValue; } else { optResult = null; @@ -289,7 +289,7 @@ export async function createInstantiator(options, swift) { let ret = swift.memory.getObject(self).roundTripOptional(optResult); const isSome = ret != null; if (isSome) { - const caseId = enumHelpers.PayloadSignal.lower(ret); + const caseId = enumHelpers.TestModule_PayloadSignal.lower(ret); return caseId; } else { return -1; @@ -312,8 +312,8 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const PayloadSignalHelpers = __bjs_createPayloadSignalValuesHelpers(); - enumHelpers.PayloadSignal = PayloadSignalHelpers; + const __bjs_helpers_TestModule_PayloadSignal = __bjs_createEnumHelpers_TestModule_PayloadSignal(); + enumHelpers.TestModule_PayloadSignal = __bjs_helpers_TestModule_PayloadSignal; const exports = { PayloadSignal: PayloadSignalValues, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js index 6912648f7..ee65f59b7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GenericImports.js @@ -391,10 +391,10 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Array_Int = __bjs_arrayCodec(__bjs_primitiveCodecs.Int); const __bjs_codec_TestModule_GenericPoint = { lower: (v) => { - structHelpers.GenericPoint.lower(v); + structHelpers.TestModule_GenericPoint.lower(v); }, lift: () => { - const struct = structHelpers.GenericPoint.lift(); + const struct = structHelpers.TestModule_GenericPoint.lift(); return struct; }, }; @@ -419,16 +419,16 @@ export async function createInstantiator(options, swift) { }; const __bjs_codec_TestModule_GenericTagged = { lower: (v) => { - const caseId = enumHelpers.GenericTagged.lower(v); + const caseId = enumHelpers.TestModule_GenericTagged.lower(v); i32Stack.push(caseId); }, lift: () => { - const enumValue = enumHelpers.GenericTagged.lift(i32Stack.pop()); + const enumValue = enumHelpers.TestModule_GenericTagged.lift(i32Stack.pop()); return enumValue; }, }; - const __bjs_createGenericPointHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_GenericPoint = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); i32Stack.push((value.y | 0)); @@ -439,7 +439,7 @@ export async function createInstantiator(options, swift) { return { x: int1, y: int }; } }); - const __bjs_createGenericTaggedValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_GenericTagged = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -549,10 +549,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_GenericPoint"] = function(objectId) { - structHelpers.GenericPoint.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_GenericPoint.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_GenericPoint"] = function() { - const value = structHelpers.GenericPoint.lift(); + const value = structHelpers.TestModule_GenericPoint.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function(base, count) { @@ -936,11 +936,11 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_GenericImportBox_value_set(this.pointer, value); } } - const GenericPointHelpers = __bjs_createGenericPointHelpers(); - structHelpers.GenericPoint = GenericPointHelpers; + const __bjs_helpers_TestModule_GenericPoint = __bjs_createStructHelpers_TestModule_GenericPoint(); + structHelpers.TestModule_GenericPoint = __bjs_helpers_TestModule_GenericPoint; - const GenericTaggedHelpers = __bjs_createGenericTaggedValuesHelpers(); - enumHelpers.GenericTagged = GenericTaggedHelpers; + const __bjs_helpers_TestModule_GenericTagged = __bjs_createEnumHelpers_TestModule_GenericTagged(); + enumHelpers.TestModule_GenericTagged = __bjs_helpers_TestModule_GenericTagged; const exports = { GenericColor: GenericColorValues, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 1a95bcb6e..d532bbff6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -370,7 +370,7 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Optional_TestModule_Foo = __bjs_optionalCodec(__bjs_codec_TestModule_Foo); const __bjs_codec_Array_Optional_TestModule_Foo = __bjs_arrayCodec(__bjs_codec_Optional_TestModule_Foo); - const __bjs_createFooContainerHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_FooContainer = () => ({ lower: (value) => { let id; if (value.foo != null) { @@ -471,10 +471,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_FooContainer"] = function(objectId) { - structHelpers.FooContainer.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_FooContainer.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_FooContainer"] = function() { - const value = structHelpers.FooContainer.lift(); + const value = structHelpers.TestModule_FooContainer.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -599,8 +599,8 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const FooContainerHelpers = __bjs_createFooContainerHelpers(); - structHelpers.FooContainer = FooContainerHelpers; + const __bjs_helpers_TestModule_FooContainer = __bjs_createStructHelpers_TestModule_FooContainer(); + structHelpers.TestModule_FooContainer = __bjs_helpers_TestModule_FooContainer; const exports = { makeFoo: function bjs_makeFoo() { @@ -628,9 +628,9 @@ export async function createInstantiator(options, swift) { return arrayResult; }, roundtripFooContainer: function bjs_roundtripFooContainer(container) { - structHelpers.FooContainer.lower(container); + structHelpers.TestModule_FooContainer.lower(container); instance.exports.bjs_roundtripFooContainer(); - const structValue = structHelpers.FooContainer.lift(); + const structValue = structHelpers.TestModule_FooContainer.lift(); return structValue; }, }; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js index 7d11a24ff..2ec71c904 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js @@ -36,7 +36,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createRenamedVectorHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_RenamedVector = () => ({ lower: (value) => { f64Stack.push(value.dx); f64Stack.push(value.dy); @@ -46,7 +46,7 @@ export async function createInstantiator(options, swift) { const f641 = f64Stack.pop(); const instance1 = { dx: f641, dy: f64 }; instance1.magnitude = function() { - structHelpers.RenamedVector.lower(this); + structHelpers.TestModule_RenamedVector.lower(this); const ret = instance.exports.bjs_RenamedVector_magnitude(); return ret; }.bind(instance1); @@ -129,10 +129,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_RenamedVector"] = function(objectId) { - structHelpers.RenamedVector.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_RenamedVector.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_RenamedVector"] = function() { - const value = structHelpers.RenamedVector.lift(); + const value = structHelpers.TestModule_RenamedVector.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -356,8 +356,8 @@ export async function createInstantiator(options, swift) { return ret; } } - const RenamedVectorHelpers = __bjs_createRenamedVectorHelpers(); - structHelpers.RenamedVector = RenamedVectorHelpers; + const __bjs_helpers_TestModule_RenamedVector = __bjs_createStructHelpers_TestModule_RenamedVector(); + structHelpers.TestModule_RenamedVector = __bjs_helpers_TestModule_RenamedVector; const exports = { makeGreeting: function bjs_makeGreeting(name) { @@ -419,12 +419,12 @@ export async function createInstantiator(options, swift) { RenamedVector: { get originVector() { instance.exports.bjs_RenamedVector_static_origin_get(); - const structValue = structHelpers.RenamedVector.lift(); + const structValue = structHelpers.TestModule_RenamedVector.lift(); return structValue; }, fromPolar: function(radius, angle) { instance.exports.bjs_RenamedVector_static_fromPolar(radius, angle); - const structValue = structHelpers.RenamedVector.lift(); + const structValue = structHelpers.TestModule_RenamedVector.lift(); return structValue; }, }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index ad0c75942..a21711b2b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -31,7 +31,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createUser_StatsHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_User_Stats = () => ({ lower: (value) => { i32Stack.push((value.health | 0)); f64Stack.push(value.score); @@ -42,7 +42,7 @@ export async function createInstantiator(options, swift) { return { health: int, score: f64 }; } }); - const __bjs_createPlayer_StatsHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Player_Stats = () => ({ lower: (value) => { i32Stack.push((value.level | 0)); const bytes = textEncoder.encode(value.rating); @@ -132,17 +132,17 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_User_Stats"] = function(objectId) { - structHelpers.User_Stats.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_User_Stats.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_User_Stats"] = function() { - const value = structHelpers.User_Stats.lift(); + const value = structHelpers.TestModule_User_Stats.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Player_Stats"] = function(objectId) { - structHelpers.Player_Stats.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Player_Stats.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Player_Stats"] = function() { - const value = structHelpers.Player_Stats.lift(); + const value = structHelpers.TestModule_Player_Stats.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -346,11 +346,11 @@ export async function createInstantiator(options, swift) { return ret; } } - const User_StatsHelpers = __bjs_createUser_StatsHelpers(); - structHelpers.User_Stats = User_StatsHelpers; + const __bjs_helpers_TestModule_User_Stats = __bjs_createStructHelpers_TestModule_User_Stats(); + structHelpers.TestModule_User_Stats = __bjs_helpers_TestModule_User_Stats; - const Player_StatsHelpers = __bjs_createPlayer_StatsHelpers(); - structHelpers.Player_Stats = Player_StatsHelpers; + const __bjs_helpers_TestModule_Player_Stats = __bjs_createStructHelpers_TestModule_Player_Stats(); + structHelpers.TestModule_Player_Stats = __bjs_helpers_TestModule_Player_Stats; const exports = { Player, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 73c93c039..8c97e1cb7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -393,7 +393,7 @@ export async function createInstantiator(options, swift) { const __bjs_codec_Array_TestModule_MyViewControllerDelegate = __bjs_arrayCodec(__bjs_codec_TestModule_MyViewControllerDelegate); const __bjs_codec_Dict_TestModule_MyViewControllerDelegate = __bjs_dictCodec(__bjs_codec_TestModule_MyViewControllerDelegate); - const __bjs_createResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_Result = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -706,7 +706,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_MyViewControllerDelegate_result_get"] = function bjs_MyViewControllerDelegate_result_get(self) { try { let ret = swift.memory.getObject(self).result; - const caseId = enumHelpers.Result.lower(ret); + const caseId = enumHelpers.TestModule_Result.lower(ret); return caseId; } catch (error) { setException(error); @@ -714,7 +714,7 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_MyViewControllerDelegate_result_set"] = function bjs_MyViewControllerDelegate_result_set(self, value) { try { - const enumValue = enumHelpers.Result.lift(value); + const enumValue = enumHelpers.TestModule_Result.lift(value); swift.memory.getObject(self).result = enumValue; } catch (error) { setException(error); @@ -725,7 +725,7 @@ export async function createInstantiator(options, swift) { let ret = swift.memory.getObject(self).optionalResult; const isSome = ret != null; if (isSome) { - const caseId = enumHelpers.Result.lower(ret); + const caseId = enumHelpers.TestModule_Result.lower(ret); return caseId; } else { return -1; @@ -738,7 +738,7 @@ export async function createInstantiator(options, swift) { try { let optResult; if (valueIsSome) { - const enumValue = enumHelpers.Result.lift(valueCaseId); + const enumValue = enumHelpers.TestModule_Result.lift(valueCaseId); optResult = enumValue; } else { optResult = null; @@ -896,7 +896,7 @@ export async function createInstantiator(options, swift) { } TestModule["bjs_MyViewControllerDelegate_handleResult"] = function bjs_MyViewControllerDelegate_handleResult(self, result) { try { - const enumValue = enumHelpers.Result.lift(result); + const enumValue = enumHelpers.TestModule_Result.lift(result); swift.memory.getObject(self).handleResult(enumValue); } catch (error) { setException(error); @@ -905,7 +905,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_MyViewControllerDelegate_getResult"] = function bjs_MyViewControllerDelegate_getResult(self) { try { let ret = swift.memory.getObject(self).getResult(); - const caseId = enumHelpers.Result.lower(ret); + const caseId = enumHelpers.TestModule_Result.lower(ret); return caseId; } catch (error) { setException(error); @@ -1090,8 +1090,8 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_DelegateManager_delegatesByName_set(this.pointer); } } - const ResultHelpers = __bjs_createResultValuesHelpers(); - enumHelpers.Result = ResultHelpers; + const __bjs_helpers_TestModule_Result = __bjs_createEnumHelpers_TestModule_Result(); + enumHelpers.TestModule_Result = __bjs_helpers_TestModule_Result; const exports = { processDelegates: function bjs_processDelegates(delegates) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 88fb0c321..193d66703 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -42,7 +42,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createAPIResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_APIResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -353,8 +353,8 @@ export async function createInstantiator(options, swift) { return ret; } } - const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); - enumHelpers.APIResult = APIResultHelpers; + const __bjs_helpers_TestModule_APIResult = __bjs_createEnumHelpers_TestModule_APIResult(); + enumHelpers.TestModule_APIResult = __bjs_helpers_TestModule_APIResult; if (typeof globalThis.Utils === 'undefined') { globalThis.Utils = {}; @@ -383,9 +383,9 @@ export async function createInstantiator(options, swift) { APIResult: { ...APIResultValues, roundtrip: function(value) { - const valueCaseId = enumHelpers.APIResult.lower(value); + const valueCaseId = enumHelpers.TestModule_APIResult.lower(value); instance.exports.bjs_APIResult_static_roundtrip(valueCaseId); - const ret = enumHelpers.APIResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_APIResult.lift(i32Stack.pop()); return ret; } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 7c614f070..711d48d0a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -42,7 +42,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createAPIResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_APIResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -353,8 +353,8 @@ export async function createInstantiator(options, swift) { return ret; } } - const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); - enumHelpers.APIResult = APIResultHelpers; + const __bjs_helpers_TestModule_APIResult = __bjs_createEnumHelpers_TestModule_APIResult(); + enumHelpers.TestModule_APIResult = __bjs_helpers_TestModule_APIResult; const exports = { Calculator: { @@ -377,9 +377,9 @@ export async function createInstantiator(options, swift) { APIResult: { ...APIResultValues, roundtrip: function(value) { - const valueCaseId = enumHelpers.APIResult.lower(value); + const valueCaseId = enumHelpers.TestModule_APIResult.lower(value); instance.exports.bjs_APIResult_static_roundtrip(valueCaseId); - const ret = enumHelpers.APIResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_APIResult.lift(i32Stack.pop()); return ret; } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js index 06873bf26..b1be21624 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StructWithNestedTypes.js @@ -46,7 +46,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createShapeHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Shape = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.label); const id = swift.memory.retain(bytes); @@ -58,7 +58,7 @@ export async function createInstantiator(options, swift) { return { label: string }; } }); - const __bjs_createWidgetHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Widget = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); const id = swift.memory.retain(bytes); @@ -70,7 +70,7 @@ export async function createInstantiator(options, swift) { return { name: string }; } }); - const __bjs_createWidget_LayoutHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Widget_Layout = () => ({ lower: (value) => { i32Stack.push((value.padding | 0)); }, @@ -79,7 +79,7 @@ export async function createInstantiator(options, swift) { return { padding: int }; } }); - const __bjs_createWidget_BoundsHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Widget_Bounds = () => ({ lower: (value) => { i32Stack.push((value.width | 0)); i32Stack.push((value.height | 0)); @@ -166,31 +166,31 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Shape"] = function(objectId) { - structHelpers.Shape.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Shape.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Shape"] = function() { - const value = structHelpers.Shape.lift(); + const value = structHelpers.TestModule_Shape.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Widget"] = function(objectId) { - structHelpers.Widget.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Widget.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Widget"] = function() { - const value = structHelpers.Widget.lift(); + const value = structHelpers.TestModule_Widget.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Widget_Layout"] = function(objectId) { - structHelpers.Widget_Layout.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Widget_Layout.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Widget_Layout"] = function() { - const value = structHelpers.Widget_Layout.lift(); + const value = structHelpers.TestModule_Widget_Layout.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Widget_Bounds"] = function(objectId) { - structHelpers.Widget_Bounds.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Widget_Bounds.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Widget_Bounds"] = function() { - const value = structHelpers.Widget_Bounds.lift(); + const value = structHelpers.TestModule_Widget_Bounds.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -306,17 +306,17 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const ShapeHelpers = __bjs_createShapeHelpers(); - structHelpers.Shape = ShapeHelpers; + const __bjs_helpers_TestModule_Shape = __bjs_createStructHelpers_TestModule_Shape(); + structHelpers.TestModule_Shape = __bjs_helpers_TestModule_Shape; - const WidgetHelpers = __bjs_createWidgetHelpers(); - structHelpers.Widget = WidgetHelpers; + const __bjs_helpers_TestModule_Widget = __bjs_createStructHelpers_TestModule_Widget(); + structHelpers.TestModule_Widget = __bjs_helpers_TestModule_Widget; - const Widget_LayoutHelpers = __bjs_createWidget_LayoutHelpers(); - structHelpers.Widget_Layout = Widget_LayoutHelpers; + const __bjs_helpers_TestModule_Widget_Layout = __bjs_createStructHelpers_TestModule_Widget_Layout(); + structHelpers.TestModule_Widget_Layout = __bjs_helpers_TestModule_Widget_Layout; - const Widget_BoundsHelpers = __bjs_createWidget_BoundsHelpers(); - structHelpers.Widget_Bounds = Widget_BoundsHelpers; + const __bjs_helpers_TestModule_Widget_Bounds = __bjs_createStructHelpers_TestModule_Widget_Bounds(); + structHelpers.TestModule_Widget_Bounds = __bjs_helpers_TestModule_Widget_Bounds; const exports = { Shape: { @@ -324,7 +324,7 @@ export async function createInstantiator(options, swift) { const labelBytes = textEncoder.encode(label); const labelId = swift.memory.retain(labelBytes); instance.exports.bjs_Shape_init(labelId, labelBytes.length); - const structValue = structHelpers.Shape.lift(); + const structValue = structHelpers.TestModule_Shape.lift(); return structValue; }, Kind: KindValues, @@ -334,14 +334,14 @@ export async function createInstantiator(options, swift) { const nameBytes = textEncoder.encode(name); const nameId = swift.memory.retain(nameBytes); instance.exports.bjs_Widget_init(nameId, nameBytes.length); - const structValue = structHelpers.Widget.lift(); + const structValue = structHelpers.TestModule_Widget.lift(); return structValue; }, Variant: VariantValues, Bounds: { init: function(width, height) { instance.exports.bjs_Widget_Bounds_init(width, height); - const structValue = structHelpers.Widget_Bounds.lift(); + const structValue = structHelpers.TestModule_Widget_Bounds.lift(); return structValue; }, get dimensions() { @@ -350,7 +350,7 @@ export async function createInstantiator(options, swift) { }, zero: function() { instance.exports.bjs_Widget_Bounds_static_zero(); - const structValue = structHelpers.Widget_Bounds.lift(); + const structValue = structHelpers.TestModule_Widget_Bounds.lift(); return structValue; }, }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 24f037350..ded3f77e5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -411,16 +411,16 @@ export async function createInstantiator(options, swift) { const __bjs_codec_TestModule_Animal = { lower: (v) => { - structHelpers.Animal.lower(v); + structHelpers.TestModule_Animal.lower(v); }, lift: () => { - const struct = structHelpers.Animal.lift(); + const struct = structHelpers.TestModule_Animal.lift(); return struct; }, }; const __bjs_codec_Optional_TestModule_Animal = __bjs_optionalCodec(__bjs_codec_TestModule_Animal); - const __bjs_createAnimalHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Animal = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.type); const id = swift.memory.retain(bytes); @@ -432,7 +432,7 @@ export async function createInstantiator(options, swift) { return { type: string }; } }); - const __bjs_createAPIResultValuesHelpers = () => ({ + const __bjs_createEnumHelpers_TestModule_APIResult = () => ({ lower: (value) => { const enumTag = value.tag; switch (enumTag) { @@ -569,10 +569,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Animal"] = function(objectId) { - structHelpers.Animal.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Animal.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Animal"] = function() { - const value = structHelpers.Animal.lift(); + const value = structHelpers.TestModule_Animal.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -594,7 +594,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_6AnimalV"] = function(promise) { try { - const structValue = structHelpers.Animal.lift(); + const structValue = structHelpers.TestModule_Animal.lift(); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(structValue); } catch (error) { setException(error); @@ -602,7 +602,7 @@ export async function createInstantiator(options, swift) { } bjs["promise_resolve_TestModule_9APIResultO"] = function(promise, value) { try { - const enumValue = enumHelpers.APIResult.lift(value); + const enumValue = enumHelpers.TestModule_APIResult.lift(value); swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(enumValue); } catch (error) { setException(error); @@ -764,18 +764,18 @@ export async function createInstantiator(options, swift) { bjs["invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV"] = function(callbackId) { try { const callback = swift.memory.getObject(callbackId); - const structValue = structHelpers.Animal.lift(); + const structValue = structHelpers.TestModule_Animal.lift(); let ret = callback(structValue); - structHelpers.Animal.lower(ret); + structHelpers.TestModule_Animal.lower(ret); } catch (error) { setException(error); } } bjs["make_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModule6AnimalV_6AnimalV = function(param0) { - structHelpers.Animal.lower(param0); + structHelpers.TestModule_Animal.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV(boxPtr); - const structValue = structHelpers.Animal.lift(); + const structValue = structHelpers.TestModule_Animal.lift(); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); @@ -812,9 +812,9 @@ export async function createInstantiator(options, swift) { bjs["invoke_js_callback_TestModule_10TestModule9APIResultO_9APIResultO"] = function(callbackId, param0) { try { const callback = swift.memory.getObject(callbackId); - const enumValue = enumHelpers.APIResult.lift(param0); + const enumValue = enumHelpers.TestModule_APIResult.lift(param0); let ret = callback(enumValue); - const caseId = enumHelpers.APIResult.lower(ret); + const caseId = enumHelpers.TestModule_APIResult.lower(ret); return caseId; } catch (error) { setException(error); @@ -822,9 +822,9 @@ export async function createInstantiator(options, swift) { } bjs["make_swift_closure_TestModule_10TestModule9APIResultO_9APIResultO"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModule9APIResultO_9APIResultO = function(param0) { - const param0CaseId = enumHelpers.APIResult.lower(param0); + const param0CaseId = enumHelpers.TestModule_APIResult.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModule9APIResultO_9APIResultO(boxPtr, param0CaseId); - const ret = enumHelpers.APIResult.lift(i32Stack.pop()); + const ret = enumHelpers.TestModule_APIResult.lift(i32Stack.pop()); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); @@ -1104,7 +1104,7 @@ export async function createInstantiator(options, swift) { const callback = swift.memory.getObject(callbackId); let optResult; if (param0) { - const struct = structHelpers.Animal.lift(); + const struct = structHelpers.TestModule_Animal.lift(); optResult = struct; } else { optResult = null; @@ -1168,7 +1168,7 @@ export async function createInstantiator(options, swift) { const callback = swift.memory.getObject(callbackId); let optResult; if (param0IsSome) { - const enumValue = enumHelpers.APIResult.lift(param0CaseId); + const enumValue = enumHelpers.TestModule_APIResult.lift(param0CaseId); optResult = enumValue; } else { optResult = null; @@ -1176,7 +1176,7 @@ export async function createInstantiator(options, swift) { let ret = callback(optResult); const isSome = ret != null; if (isSome) { - const caseId = enumHelpers.APIResult.lower(ret); + const caseId = enumHelpers.TestModule_APIResult.lower(ret); return caseId; } else { return -1; @@ -1190,14 +1190,14 @@ export async function createInstantiator(options, swift) { const isSome = param0 != null; let result; if (isSome) { - const param0CaseId = enumHelpers.APIResult.lower(param0); + const param0CaseId = enumHelpers.TestModule_APIResult.lower(param0); result = param0CaseId; } else { result = 0; } instance.exports.invoke_swift_closure_TestModule_10TestModuleSq9APIResultO_Sq9APIResultO(boxPtr, +isSome, result); const tag = i32Stack.pop(); - const optResult = tag === -1 ? null : enumHelpers.APIResult.lift(tag); + const optResult = tag === -1 ? null : enumHelpers.TestModule_APIResult.lift(tag); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); @@ -1465,7 +1465,7 @@ export async function createInstantiator(options, swift) { bjs["invoke_js_callback_TestModule_10TestModules6AnimalV_y"] = function(callbackId) { try { const callback = swift.memory.getObject(callbackId); - const structValue = structHelpers.Animal.lift(); + const structValue = structHelpers.TestModule_Animal.lift(); callback(structValue); } catch (error) { setException(error); @@ -1473,7 +1473,7 @@ export async function createInstantiator(options, swift) { } bjs["make_swift_closure_TestModule_10TestModules6AnimalV_y"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModules6AnimalV_y = function(param0) { - structHelpers.Animal.lower(param0); + structHelpers.TestModule_Animal.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModules6AnimalV_y(boxPtr); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); @@ -1509,7 +1509,7 @@ export async function createInstantiator(options, swift) { bjs["invoke_js_callback_TestModule_10TestModules9APIResultO_y"] = function(callbackId, param0) { try { const callback = swift.memory.getObject(callbackId); - const enumValue = enumHelpers.APIResult.lift(param0); + const enumValue = enumHelpers.TestModule_APIResult.lift(param0); callback(enumValue); } catch (error) { setException(error); @@ -1517,7 +1517,7 @@ export async function createInstantiator(options, swift) { } bjs["make_swift_closure_TestModule_10TestModules9APIResultO_y"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModules9APIResultO_y = function(param0) { - const param0CaseId = enumHelpers.APIResult.lower(param0); + const param0CaseId = enumHelpers.TestModule_APIResult.lower(param0); instance.exports.invoke_swift_closure_TestModule_10TestModules9APIResultO_y(boxPtr, param0CaseId); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); @@ -1652,11 +1652,11 @@ export async function createInstantiator(options, swift) { return TestProcessor.__construct(ret); } } - const AnimalHelpers = __bjs_createAnimalHelpers(); - structHelpers.Animal = AnimalHelpers; + const __bjs_helpers_TestModule_Animal = __bjs_createStructHelpers_TestModule_Animal(); + structHelpers.TestModule_Animal = __bjs_helpers_TestModule_Animal; - const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); - enumHelpers.APIResult = APIResultHelpers; + const __bjs_helpers_TestModule_APIResult = __bjs_createEnumHelpers_TestModule_APIResult(); + enumHelpers.TestModule_APIResult = __bjs_helpers_TestModule_APIResult; const exports = { roundtripAnimal: function bjs_roundtripAnimal(animalClosure) { @@ -1807,7 +1807,7 @@ export async function createInstantiator(options, swift) { const typeBytes = textEncoder.encode(type); const typeId = swift.memory.retain(typeBytes); instance.exports.bjs_Animal_init(typeId, typeBytes.length); - const structValue = structHelpers.Animal.lift(); + const structValue = structHelpers.TestModule_Animal.lift(); return structValue; }, }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index bb0de3d03..db4fdbe93 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -386,7 +386,7 @@ export async function createInstantiator(options, swift) { }; const __bjs_codec_Optional_JSObject = __bjs_optionalCodec(__bjs_codec_JSObject); - const __bjs_createDataPointHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_DataPoint = () => ({ lower: (value) => { f64Stack.push(value.x); f64Stack.push(value.y); @@ -406,7 +406,7 @@ export async function createInstantiator(options, swift) { return { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; } }); - const __bjs_createAddressHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Address = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.street); const id = swift.memory.retain(bytes); @@ -425,25 +425,25 @@ export async function createInstantiator(options, swift) { return { street: string1, city: string, zipCode: optValue }; } }); - const __bjs_createPersonHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Person = () => ({ lower: (value) => { const bytes = textEncoder.encode(value.name); const id = swift.memory.retain(bytes); i32Stack.push(bytes.length); i32Stack.push(id); i32Stack.push((value.age | 0)); - structHelpers.Address.lower(value.address); + structHelpers.TestModule_Address.lower(value.address); __bjs_codec_Optional_String.lower(value.email); }, lift: () => { const optValue = __bjs_codec_Optional_String.lift(); - const struct = structHelpers.Address.lift(); + const struct = structHelpers.TestModule_Address.lift(); const int = i32Stack.pop(); const string = strStack.pop(); return { name: string, age: int, address: struct, email: optValue }; } }); - const __bjs_createSessionHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Session = () => ({ lower: (value) => { i32Stack.push((value.id | 0)); ptrStack.push(value.owner.pointer); @@ -455,7 +455,7 @@ export async function createInstantiator(options, swift) { return { id: int, owner: obj }; } }); - const __bjs_createMeasurementHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Measurement = () => ({ lower: (value) => { f64Stack.push(value.value); f32Stack.push(Math.fround(value.precision)); @@ -468,14 +468,14 @@ export async function createInstantiator(options, swift) { return { value: f64, precision: rawValue, optionalPrecision: optValue }; } }); - const __bjs_createConfigStructHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_ConfigStruct = () => ({ lower: (value) => { }, lift: () => { return { }; } }); - const __bjs_createContainerHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Container = () => ({ lower: (value) => { let id; if (value.object != null) { @@ -499,7 +499,7 @@ export async function createInstantiator(options, swift) { return { object: value, optionalObject: optValue }; } }); - const __bjs_createVector2DHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Vector2D = () => ({ lower: (value) => { f64Stack.push(value.dx); f64Stack.push(value.dy); @@ -509,18 +509,18 @@ export async function createInstantiator(options, swift) { const f641 = f64Stack.pop(); const instance1 = { dx: f641, dy: f64 }; instance1.magnitude = function() { - structHelpers.Vector2D.lower(this); + structHelpers.TestModule_Vector2D.lower(this); const ret = instance.exports.bjs_Vector2D_magnitude(); return ret; }.bind(instance1); instance1.scaled = function(factor) { - structHelpers.Vector2D.lower(this); + structHelpers.TestModule_Vector2D.lower(this); const ret1 = instance.exports.bjs_Vector2D_scaled(factor); - const structValue = structHelpers.Vector2D.lift(); + const structValue = structHelpers.TestModule_Vector2D.lift(); return structValue; }.bind(instance1); instance1.describe = function() { - structHelpers.Vector2D.lower(this); + structHelpers.TestModule_Vector2D.lower(this); const ret2 = instance.exports.bjs_Vector2D_describe(); const ret3 = tmpRetString; tmpRetString = undefined; @@ -605,59 +605,59 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_DataPoint"] = function(objectId) { - structHelpers.DataPoint.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_DataPoint.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_DataPoint"] = function() { - const value = structHelpers.DataPoint.lift(); + const value = structHelpers.TestModule_DataPoint.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Address"] = function(objectId) { - structHelpers.Address.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Address.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Address"] = function() { - const value = structHelpers.Address.lift(); + const value = structHelpers.TestModule_Address.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Person"] = function(objectId) { - structHelpers.Person.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Person.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Person"] = function() { - const value = structHelpers.Person.lift(); + const value = structHelpers.TestModule_Person.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Session"] = function(objectId) { - structHelpers.Session.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Session.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Session"] = function() { - const value = structHelpers.Session.lift(); + const value = structHelpers.TestModule_Session.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Measurement"] = function(objectId) { - structHelpers.Measurement.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Measurement.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Measurement"] = function() { - const value = structHelpers.Measurement.lift(); + const value = structHelpers.TestModule_Measurement.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_ConfigStruct"] = function(objectId) { - structHelpers.ConfigStruct.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_ConfigStruct.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_ConfigStruct"] = function() { - const value = structHelpers.ConfigStruct.lift(); + const value = structHelpers.TestModule_ConfigStruct.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Container"] = function(objectId) { - structHelpers.Container.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Container.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Container"] = function() { - const value = structHelpers.Container.lift(); + const value = structHelpers.TestModule_Container.lift(); return swift.memory.retain(value); } bjs["swift_js_struct_lower_Vector2D"] = function(objectId) { - structHelpers.Vector2D.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Vector2D.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Vector2D"] = function() { - const value = structHelpers.Vector2D.lift(); + const value = structHelpers.TestModule_Vector2D.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -862,41 +862,41 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } } - const DataPointHelpers = __bjs_createDataPointHelpers(); - structHelpers.DataPoint = DataPointHelpers; + const __bjs_helpers_TestModule_DataPoint = __bjs_createStructHelpers_TestModule_DataPoint(); + structHelpers.TestModule_DataPoint = __bjs_helpers_TestModule_DataPoint; - const AddressHelpers = __bjs_createAddressHelpers(); - structHelpers.Address = AddressHelpers; + const __bjs_helpers_TestModule_Address = __bjs_createStructHelpers_TestModule_Address(); + structHelpers.TestModule_Address = __bjs_helpers_TestModule_Address; - const PersonHelpers = __bjs_createPersonHelpers(); - structHelpers.Person = PersonHelpers; + const __bjs_helpers_TestModule_Person = __bjs_createStructHelpers_TestModule_Person(); + structHelpers.TestModule_Person = __bjs_helpers_TestModule_Person; - const SessionHelpers = __bjs_createSessionHelpers(); - structHelpers.Session = SessionHelpers; + const __bjs_helpers_TestModule_Session = __bjs_createStructHelpers_TestModule_Session(); + structHelpers.TestModule_Session = __bjs_helpers_TestModule_Session; - const MeasurementHelpers = __bjs_createMeasurementHelpers(); - structHelpers.Measurement = MeasurementHelpers; + const __bjs_helpers_TestModule_Measurement = __bjs_createStructHelpers_TestModule_Measurement(); + structHelpers.TestModule_Measurement = __bjs_helpers_TestModule_Measurement; - const ConfigStructHelpers = __bjs_createConfigStructHelpers(); - structHelpers.ConfigStruct = ConfigStructHelpers; + const __bjs_helpers_TestModule_ConfigStruct = __bjs_createStructHelpers_TestModule_ConfigStruct(); + structHelpers.TestModule_ConfigStruct = __bjs_helpers_TestModule_ConfigStruct; - const ContainerHelpers = __bjs_createContainerHelpers(); - structHelpers.Container = ContainerHelpers; + const __bjs_helpers_TestModule_Container = __bjs_createStructHelpers_TestModule_Container(); + structHelpers.TestModule_Container = __bjs_helpers_TestModule_Container; - const Vector2DHelpers = __bjs_createVector2DHelpers(); - structHelpers.Vector2D = Vector2DHelpers; + const __bjs_helpers_TestModule_Vector2D = __bjs_createStructHelpers_TestModule_Vector2D(); + structHelpers.TestModule_Vector2D = __bjs_helpers_TestModule_Vector2D; const exports = { roundtrip: function bjs_roundtrip(session) { - structHelpers.Person.lower(session); + structHelpers.TestModule_Person.lower(session); instance.exports.bjs_roundtrip(); - const structValue = structHelpers.Person.lift(); + const structValue = structHelpers.TestModule_Person.lift(); return structValue; }, roundtripContainer: function bjs_roundtripContainer(container) { - structHelpers.Container.lower(container); + structHelpers.TestModule_Container.lower(container); instance.exports.bjs_roundtripContainer(); - const structValue = structHelpers.Container.lift(); + const structValue = structHelpers.TestModule_Container.lift(); return structValue; }, Precision: PrecisionValues, @@ -941,7 +941,7 @@ export async function createInstantiator(options, swift) { const isSome = optCount != null; const isSome1 = optFlag != null; instance.exports.bjs_DataPoint_init(x, y, labelId, labelBytes.length, +isSome, isSome ? optCount : 0, +isSome1, isSome1 ? optFlag ? 1 : 0 : 0); - const structValue = structHelpers.DataPoint.lift(); + const structValue = structHelpers.TestModule_DataPoint.lift(); return structValue; }, get dimensions() { @@ -950,7 +950,7 @@ export async function createInstantiator(options, swift) { }, origin: function() { instance.exports.bjs_DataPoint_static_origin(); - const structValue = structHelpers.DataPoint.lift(); + const structValue = structHelpers.TestModule_DataPoint.lift(); return structValue; }, }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index f603bee2e..b3119f0d3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -356,16 +356,16 @@ export async function createInstantiator(options, swift) { const __bjs_codec_TestModule_Point = { lower: (v) => { - structHelpers.Point.lower(v); + structHelpers.TestModule_Point.lower(v); }, lift: () => { - const struct = structHelpers.Point.lift(); + const struct = structHelpers.TestModule_Point.lift(); return struct; }, }; const __bjs_codec_Optional_TestModule_Point = __bjs_optionalCodec(__bjs_codec_TestModule_Point); - const __bjs_createPointHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_Point = () => ({ lower: (value) => { i32Stack.push((value.x | 0)); i32Stack.push((value.y | 0)); @@ -453,10 +453,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_Point"] = function(objectId) { - structHelpers.Point.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_Point.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_Point"] = function() { - const value = structHelpers.Point.lift(); + const value = structHelpers.TestModule_Point.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -561,9 +561,9 @@ export async function createInstantiator(options, swift) { const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_translate"] = function bjs_translate(dx, dy) { try { - const structValue = structHelpers.Point.lift(); + const structValue = structHelpers.TestModule_Point.lift(); let ret = imports.translate(structValue, dx, dy); - structHelpers.Point.lower(ret); + structHelpers.TestModule_Point.lower(ret); } catch (error) { setException(error); } @@ -572,7 +572,7 @@ export async function createInstantiator(options, swift) { try { let optResult; if (point) { - const struct = structHelpers.Point.lift(); + const struct = structHelpers.TestModule_Point.lift(); optResult = struct; } else { optResult = null; @@ -597,8 +597,8 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const PointHelpers = __bjs_createPointHelpers(); - structHelpers.Point = PointHelpers; + const __bjs_helpers_TestModule_Point = __bjs_createStructHelpers_TestModule_Point(); + structHelpers.TestModule_Point = __bjs_helpers_TestModule_Point; const exports = { }; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index ecc14e5ae..b15310e76 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -31,7 +31,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createPointerFieldsHelpers = () => ({ + const __bjs_createStructHelpers_TestModule_PointerFields = () => ({ lower: (value) => { ptrStack.push((value.raw | 0)); ptrStack.push((value.mutRaw | 0)); @@ -124,10 +124,10 @@ export async function createInstantiator(options, swift) { taStack.push(Array.from(new Ctor(copy))); } bjs["swift_js_struct_lower_PointerFields"] = function(objectId) { - structHelpers.PointerFields.lower(swift.memory.getObject(objectId)); + structHelpers.TestModule_PointerFields.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_PointerFields"] = function() { - const value = structHelpers.PointerFields.lift(); + const value = structHelpers.TestModule_PointerFields.lift(); return swift.memory.retain(value); } bjs["bjs_core_register_type_handles"] = function() {}; @@ -243,8 +243,8 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - const PointerFieldsHelpers = __bjs_createPointerFieldsHelpers(); - structHelpers.PointerFields = PointerFieldsHelpers; + const __bjs_helpers_TestModule_PointerFields = __bjs_createStructHelpers_TestModule_PointerFields(); + structHelpers.TestModule_PointerFields = __bjs_helpers_TestModule_PointerFields; const exports = { takeUnsafeRawPointer: function bjs_takeUnsafeRawPointer(p) { @@ -283,15 +283,15 @@ export async function createInstantiator(options, swift) { return ret; }, roundTripPointerFields: function bjs_roundTripPointerFields(value) { - structHelpers.PointerFields.lower(value); + structHelpers.TestModule_PointerFields.lower(value); instance.exports.bjs_roundTripPointerFields(); - const structValue = structHelpers.PointerFields.lift(); + const structValue = structHelpers.TestModule_PointerFields.lift(); return structValue; }, PointerFields: { init: function(raw, mutRaw, opaque, ptr, mutPtr) { instance.exports.bjs_PointerFields_init(raw, mutRaw, opaque, ptr, mutPtr); - const structValue = structHelpers.PointerFields.lift(); + const structValue = structHelpers.TestModule_PointerFields.lift(); return structValue; }, },