From 5529520b25638aa86765ab33b175289f1ab263a3 Mon Sep 17 00:00:00 2001 From: Adin Date: Tue, 3 Mar 2026 15:37:28 +0700 Subject: [PATCH 01/68] Merge pull request #687 from gn-adin-b/adin/property-access-tracing Add property access tracing to JSTracing --- .../FundamentalObjects/JSObject.swift | 38 ++++++++++++ Sources/JavaScriptKit/JSTracing.swift | 2 + Tests/JavaScriptKitTests/JSTracingTests.swift | 60 ++++++++++++++++++- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift index caacd49f2..1b6facada 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift @@ -153,10 +153,18 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { public subscript(_ name: String) -> JSValue { get { assertOnOwnerThread(hint: "reading '\(name)' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall(.propertyGet(receiver: self, propertyName: name)) + defer { traceEnd?() } + #endif return getJSValue(this: self, name: JSString(name)) } set { assertOnOwnerThread(hint: "writing '\(name)' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall(.propertySet(receiver: self, propertyName: name, value: newValue)) + defer { traceEnd?() } + #endif setJSValue(this: self, name: JSString(name), value: newValue) } } @@ -167,10 +175,20 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { public subscript(_ name: JSString) -> JSValue { get { assertOnOwnerThread(hint: "reading '<>' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall(.propertyGet(receiver: self, propertyName: String(name))) + defer { traceEnd?() } + #endif return getJSValue(this: self, name: name) } set { assertOnOwnerThread(hint: "writing '<>' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall( + .propertySet(receiver: self, propertyName: String(name), value: newValue) + ) + defer { traceEnd?() } + #endif setJSValue(this: self, name: name, value: newValue) } } @@ -181,10 +199,20 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { public subscript(_ index: Int) -> JSValue { get { assertOnOwnerThread(hint: "reading '\(index)' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall(.propertyGet(receiver: self, propertyName: String(index))) + defer { traceEnd?() } + #endif return getJSValue(this: self, index: Int32(index)) } set { assertOnOwnerThread(hint: "writing '\(index)' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall( + .propertySet(receiver: self, propertyName: String(index), value: newValue) + ) + defer { traceEnd?() } + #endif setJSValue(this: self, index: Int32(index), value: newValue) } } @@ -195,10 +223,20 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { public subscript(_ name: JSSymbol) -> JSValue { get { assertOnOwnerThread(hint: "reading '<>' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall(.propertyGet(receiver: self, propertyName: "<>")) + defer { traceEnd?() } + #endif return getJSValue(this: self, symbol: name) } set { assertOnOwnerThread(hint: "writing '<>' property") + #if Tracing + let traceEnd = JSTracingHooks.beginJSCall( + .propertySet(receiver: self, propertyName: "<>", value: newValue) + ) + defer { traceEnd?() } + #endif setJSValue(this: self, symbol: name, value: newValue) } } diff --git a/Sources/JavaScriptKit/JSTracing.swift b/Sources/JavaScriptKit/JSTracing.swift index 8804e9afb..28e2a1bf8 100644 --- a/Sources/JavaScriptKit/JSTracing.swift +++ b/Sources/JavaScriptKit/JSTracing.swift @@ -7,6 +7,8 @@ public struct JSTracing: Sendable { public enum JSCallInfo { case function(function: JSObject, arguments: [JSValue]) case method(receiver: JSObject, methodName: String?, arguments: [JSValue]) + case propertyGet(receiver: JSObject, propertyName: String) + case propertySet(receiver: JSObject, propertyName: String, value: JSValue) } /// Register a hook for Swift to JavaScript calls. diff --git a/Tests/JavaScriptKitTests/JSTracingTests.swift b/Tests/JavaScriptKitTests/JSTracingTests.swift index 84fb9bfc6..755e89d49 100644 --- a/Tests/JavaScriptKitTests/JSTracingTests.swift +++ b/Tests/JavaScriptKitTests/JSTracingTests.swift @@ -16,15 +16,69 @@ final class JSTracingTests: XCTestCase { let prop5 = try XCTUnwrap(globalObject1.prop_5.object) _ = prop5.func6!(true, 1, 2) - XCTAssertEqual(startInfo.count, 1) - guard case let .method(receiver, methodName, arguments) = startInfo.first else { + let methodEvents = startInfo.filter { + if case .method = $0 { return true } + return false + } + XCTAssertEqual(methodEvents.count, 1) + guard case let .method(receiver, methodName, arguments) = methodEvents.first else { XCTFail("Expected method info") return } XCTAssertEqual(receiver.id, prop5.id) XCTAssertEqual(methodName, "func6") XCTAssertEqual(arguments, [.boolean(true), .number(1), .number(2)]) - XCTAssertEqual(ended, 1) + XCTAssertEqual(ended, startInfo.count) + } + + func testJSCallHookReportsPropertyAccess() throws { + var startInfo: [JSTracing.JSCallInfo] = [] + var ended = 0 + let remove = JSTracing.default.addJSCallHook { info in + startInfo.append(info) + return { ended += 1 } + } + defer { remove() } + + let obj = JSObject() + obj.foo = .number(42) + + // Reset after setup so we only capture the reads/writes below. + startInfo.removeAll() + ended = 0 + + // Read a property (triggers propertyGet) + let _: JSValue = obj.foo + + // Write a property (triggers propertySet) + obj.foo = .number(999) + + let propEvents = startInfo.filter { + switch $0 { + case .propertyGet(_, let name) where name == "foo": return true + case .propertySet(_, let name, _) where name == "foo": return true + default: return false + } + } + + XCTAssertEqual(propEvents.count, 2) + + guard case .propertyGet(let getReceiver, let getName) = propEvents[0] else { + XCTFail("Expected propertyGet info") + return + } + XCTAssertEqual(getReceiver.id, obj.id) + XCTAssertEqual(getName, "foo") + + guard case .propertySet(let setReceiver, let setName, let setValue) = propEvents[1] else { + XCTFail("Expected propertySet info") + return + } + XCTAssertEqual(setReceiver.id, obj.id) + XCTAssertEqual(setName, "foo") + XCTAssertEqual(setValue, .number(999)) + + XCTAssertEqual(ended, startInfo.count) } func testJSClosureCallHookReportsMetadata() throws { From 0c4c45a78184c96a685896270aec49e91fb7abfc Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Wed, 4 Mar 2026 13:34:30 +0100 Subject: [PATCH 02/68] fix use-after-free in BridgeJS (#690) fix use-after-free --- Sources/JavaScriptKit/BridgeJSIntrinsics.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 87f83d8a9..c0de9413e 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -420,7 +420,12 @@ extension JSObject: _BridgedSwiftStackType { } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Int32 { - return _swift_js_retain(Int32(bitPattern: self.id)) + // withExtendedLifetime is required here to prevent a use-after-free. + // In a `consuming func`, Swift ARC may release `self` (and thus release + // the underlying JS reference) as soon as it extracts `self.id`, which + // happens *before* `_swift_js_retain` is called. `withExtendedLifetime` forces + // `self` to stay alive until after `_swift_js_retain` returns. + return withExtendedLifetime(self) { _swift_js_retain(Int32(bitPattern: self.id)) } } @_spi(BridgeJS) public consuming func bridgeJSStackPush() { From bc05d2a82db665c2c4c1f0cafc8f07f04dcf0237 Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Wed, 4 Mar 2026 14:12:13 +0100 Subject: [PATCH 03/68] BridgeJS: fix codegen for async + throws exported methods (#691) --- .../BridgeJS/Sources/BridgeJSCore/ExportSwift.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 7311b24be..4c91ebd74 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -319,8 +319,19 @@ public class ExportSwift { func render(abiName: String) -> DeclSyntax { let body: CodeBlockItemListSyntax if effects.isAsync { + // Explicit closure type annotation needed when throws is present + // so Swift infers throws(JSException) instead of throws(any Error) + // See: https://github.com/swiftlang/swift/issues/76165 + let closureHead: String + if effects.isThrows { + let hasReturn = self.body.contains { $0.description.contains("return ") } + let ret = hasReturn ? " -> JSValue" : "" + closureHead = " () async throws(JSException)\(ret) in" + } else { + closureHead = "" + } body = """ - let ret = JSPromise.async { + let ret = JSPromise.async {\(raw: closureHead) \(CodeBlockItemListSyntax(self.body)) }.jsObject return ret.bridgeJSLowerReturn() From 3d25cd9faef03aa0e8c57d38cdab771d8d720a1c Mon Sep 17 00:00:00 2001 From: Simon Leeb <52261246+sliemeobn@users.noreply.github.com> Date: Thu, 5 Mar 2026 12:08:40 +0100 Subject: [PATCH 04/68] [BridgeJS] Pass String parameters unretained as (address, length) (#688) * pass unretained strings as tuple * Generalize lowering parameters with borrowing scope * factored out decodeString global * formatting * format (with Swift 6.2) --------- Co-authored-by: Yuta Saito --- Benchmarks/Sources/Generated/BridgeJS.swift | 15 +- .../PlayBridgeJS/Generated/BridgeJS.swift | 15 +- .../Sources/BridgeJSCore/ClosureCodegen.swift | 7 +- .../Sources/BridgeJSCore/ExportSwift.swift | 19 +- .../Sources/BridgeJSCore/ImportTS.swift | 162 +++++--- .../Sources/BridgeJSLink/BridgeJSLink.swift | 29 +- .../Sources/BridgeJSLink/JSGlueGen.swift | 15 +- .../BridgeJSCodegenTests/EnumRawType.swift | 13 +- .../BridgeJSCodegenTests/GlobalGetter.swift | 13 +- .../GlobalThisImports.swift | 43 ++- .../InvalidPropertyNames.swift | 65 ++-- .../BridgeJSCodegenTests/JSClass.swift | 41 +- .../BridgeJSCodegenTests/Optionals.swift | 71 ++-- .../BridgeJSCodegenTests/Protocol.swift | 68 ++-- .../StringParameter.swift | 28 +- .../BridgeJSCodegenTests/SwiftClosure.swift | 56 +-- .../BridgeJSLinkTests/ArrayTypes.js | 15 +- .../__Snapshots__/BridgeJSLinkTests/Async.js | 15 +- .../BridgeJSLinkTests/DefaultParameters.js | 15 +- .../BridgeJSLinkTests/DictionaryTypes.js | 15 +- .../BridgeJSLinkTests/EnumAssociatedValue.js | 15 +- .../BridgeJSLinkTests/EnumCase.js | 15 +- .../BridgeJSLinkTests/EnumNamespace.Global.js | 15 +- .../BridgeJSLinkTests/EnumNamespace.js | 15 +- .../BridgeJSLinkTests/EnumRawType.js | 22 +- .../BridgeJSLinkTests/GlobalGetter.js | 22 +- .../BridgeJSLinkTests/GlobalThisImports.js | 36 +- .../BridgeJSLinkTests/ImportArray.js | 15 +- .../ImportedTypeInExportedInterface.js | 15 +- .../BridgeJSLinkTests/InvalidPropertyNames.js | 50 ++- .../BridgeJSLinkTests/JSClass.js | 36 +- .../JSClassStaticFunctions.js | 15 +- .../BridgeJSLinkTests/JSValue.js | 15 +- .../BridgeJSLinkTests/MixedGlobal.js | 15 +- .../BridgeJSLinkTests/MixedModules.js | 15 +- .../BridgeJSLinkTests/MixedPrivate.js | 15 +- .../BridgeJSLinkTests/Namespaces.Global.js | 15 +- .../BridgeJSLinkTests/Namespaces.js | 15 +- .../BridgeJSLinkTests/Optionals.js | 55 ++- .../BridgeJSLinkTests/PrimitiveParameters.js | 15 +- .../BridgeJSLinkTests/PrimitiveReturn.js | 15 +- .../BridgeJSLinkTests/PropertyTypes.js | 15 +- .../BridgeJSLinkTests/Protocol.js | 53 ++- .../StaticFunctions.Global.js | 15 +- .../BridgeJSLinkTests/StaticFunctions.js | 15 +- .../StaticProperties.Global.js | 15 +- .../BridgeJSLinkTests/StaticProperties.js | 15 +- .../BridgeJSLinkTests/StringParameter.js | 29 +- .../BridgeJSLinkTests/StringReturn.js | 15 +- .../BridgeJSLinkTests/SwiftClass.js | 15 +- .../BridgeJSLinkTests/SwiftClosure.js | 43 +-- .../BridgeJSLinkTests/SwiftClosureImports.js | 15 +- .../BridgeJSLinkTests/SwiftStruct.js | 15 +- .../BridgeJSLinkTests/SwiftStructImports.js | 15 +- .../__Snapshots__/BridgeJSLinkTests/Throws.js | 15 +- .../BridgeJSLinkTests/UnsafePointer.js | 15 +- .../VoidParameterVoidReturn.js | 15 +- .../JavaScriptKit/BridgeJSIntrinsics.swift | 35 +- .../Generated/BridgeJS.swift | 359 ++++++++++-------- 59 files changed, 1000 insertions(+), 880 deletions(-) diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index bf033ae21..7b7c6e690 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -1750,20 +1750,21 @@ func _$benchmarkHelperNoopWithNumber(_ n: Double) throws(JSException) -> Void { #if arch(wasm32) @_extern(wasm, module: "Benchmarks", name: "bjs_benchmarkRunner") -fileprivate func bjs_benchmarkRunner_extern(_ name: Int32, _ body: Int32) -> Void +fileprivate func bjs_benchmarkRunner_extern(_ nameBytes: Int32, _ nameLength: Int32, _ body: Int32) -> Void #else -fileprivate func bjs_benchmarkRunner_extern(_ name: Int32, _ body: Int32) -> Void { +fileprivate func bjs_benchmarkRunner_extern(_ nameBytes: Int32, _ nameLength: Int32, _ body: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_benchmarkRunner(_ name: Int32, _ body: Int32) -> Void { - return bjs_benchmarkRunner_extern(name, body) +@inline(never) fileprivate func bjs_benchmarkRunner(_ nameBytes: Int32, _ nameLength: Int32, _ body: Int32) -> Void { + return bjs_benchmarkRunner_extern(nameBytes, nameLength, body) } func _$benchmarkRunner(_ name: String, _ body: JSObject) throws(JSException) -> Void { - let nameValue = name.bridgeJSLowerParameter() - let bodyValue = body.bridgeJSLowerParameter() - bjs_benchmarkRunner(nameValue, bodyValue) + name.bridgeJSWithLoweredParameter { (nameBytes, nameLength) in + let bodyValue = body.bridgeJSLowerParameter() + bjs_benchmarkRunner(nameBytes, nameLength, bodyValue) + } if let error = _swift_js_take_exception() { throw error } diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index 88cdf900e..f1baf3aa1 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift @@ -249,20 +249,23 @@ func _$createTS2Swift() throws(JSException) -> TS2Swift { #if arch(wasm32) @_extern(wasm, module: "PlayBridgeJS", name: "bjs_TS2Swift_convert") -fileprivate func bjs_TS2Swift_convert_extern(_ self: Int32, _ ts: Int32) -> Int32 +fileprivate func bjs_TS2Swift_convert_extern(_ self: Int32, _ tsBytes: Int32, _ tsLength: Int32) -> Int32 #else -fileprivate func bjs_TS2Swift_convert_extern(_ self: Int32, _ ts: Int32) -> Int32 { +fileprivate func bjs_TS2Swift_convert_extern(_ self: Int32, _ tsBytes: Int32, _ tsLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_TS2Swift_convert(_ self: Int32, _ ts: Int32) -> Int32 { - return bjs_TS2Swift_convert_extern(self, ts) +@inline(never) fileprivate func bjs_TS2Swift_convert(_ self: Int32, _ tsBytes: Int32, _ tsLength: Int32) -> Int32 { + return bjs_TS2Swift_convert_extern(self, tsBytes, tsLength) } func _$TS2Swift_convert(_ self: JSObject, _ ts: String) throws(JSException) -> String { let selfValue = self.bridgeJSLowerParameter() - let tsValue = ts.bridgeJSLowerParameter() - let ret = bjs_TS2Swift_convert(selfValue, tsValue) + let ret0 = ts.bridgeJSWithLoweredParameter { (tsBytes, tsLength) in + let ret = bjs_TS2Swift_convert(selfValue, tsBytes, tsLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index d974fc16d..e5648ccf7 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -26,9 +26,10 @@ public struct ClosureCodegen { let externName = "invoke_js_callback_\(signature.moduleName)_\(mangledName)" // Use CallJSEmission to generate the callback invocation - let builder = ImportTS.CallJSEmission( + let builder = try ImportTS.CallJSEmission( moduleName: "bjs", abiName: externName, + returnType: signature.returnType, context: .exportSwift ) @@ -41,8 +42,8 @@ public struct ClosureCodegen { } // Generate the call and return value lifting - try builder.call(returnType: signature.returnType) - try builder.liftReturnValue(returnType: signature.returnType) + try builder.call() + try builder.liftReturnValue() // Generate extern declaration using CallJSEmission let externDecl = builder.renderImportDecl() diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 4c91ebd74..dbe4a1312 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -1177,17 +1177,18 @@ struct ProtocolCodegen { var externDecls: [DeclSyntax] = [] for method in proto.methods { - let builder = ImportTS.CallJSEmission( + let builder = try ImportTS.CallJSEmission( moduleName: moduleName, abiName: "_extern_\(method.name)", + returnType: method.returnType, context: .exportSwift ) try builder.lowerParameter(param: Parameter(label: nil, name: "jsObject", type: .jsObject(nil))) for param in method.parameters { try builder.lowerParameter(param: param) } - try builder.call(returnType: method.returnType) - try builder.liftReturnValue(returnType: method.returnType) + try builder.call() + try builder.liftReturnValue() // Build function signature using SwiftSignatureBuilder let signature = SwiftSignatureBuilder.buildFunctionSignature( @@ -1275,14 +1276,15 @@ struct ProtocolCodegen { className: protocolName ) - let getterBuilder = ImportTS.CallJSEmission( + let getterBuilder = try ImportTS.CallJSEmission( moduleName: moduleName, abiName: getterAbiName, + returnType: property.type, context: .exportSwift ) try getterBuilder.lowerParameter(param: Parameter(label: nil, name: "jsObject", type: .jsObject(nil))) - try getterBuilder.call(returnType: property.type) - try getterBuilder.liftReturnValue(returnType: property.type) + try getterBuilder.call() + try getterBuilder.liftReturnValue() // Build getter extern declaration using helper function let getterExternDeclPrinter = CodeFragmentPrinter() @@ -1307,14 +1309,15 @@ struct ProtocolCodegen { if property.isReadonly { return } - let setterBuilder = ImportTS.CallJSEmission( + let setterBuilder = try ImportTS.CallJSEmission( moduleName: moduleName, abiName: setterAbiName, + returnType: .void, context: .exportSwift ) try setterBuilder.lowerParameter(param: Parameter(label: nil, name: "jsObject", type: .jsObject(nil))) try setterBuilder.lowerParameter(param: Parameter(label: nil, name: "newValue", type: property.type)) - try setterBuilder.call(returnType: .void) + try setterBuilder.call() // Build setter extern declaration using helper function let setterExternDeclPrinter = CodeFragmentPrinter() diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 8f5ac511a..1b7dce434 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -66,9 +66,13 @@ public struct ImportTS { _ getter: ImportedGetterSkeleton, topLevelDecls: inout [DeclSyntax] ) throws -> [DeclSyntax] { - let builder = CallJSEmission(moduleName: moduleName, abiName: getter.abiName(context: nil)) - try builder.call(returnType: getter.type) - try builder.liftReturnValue(returnType: getter.type) + let builder = try CallJSEmission( + moduleName: moduleName, + abiName: getter.abiName(context: nil), + returnType: getter.type + ) + try builder.call() + try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) return [ builder.renderThunkDecl( @@ -81,8 +85,16 @@ public struct ImportTS { } class CallJSEmission { + private struct BorrowedArgument { + /// The variable name of the `bridgeJSWithLoweredParameter` return value + let returnVariableName: String? + /// The closure to close the borrowing call + let closeBorrowedClosure: (CodeFragmentPrinter) -> Void + } + let abiName: String let moduleName: String + let returnType: BridgeType let context: BridgeContext var body = CodeFragmentPrinter() @@ -95,11 +107,19 @@ public struct ImportTS { var stackLoweringStmts: [String] = [] // Values to extend lifetime during call var valuesToExtendLifetimeDuringCall: [String] = [] + // Closures to close borrowed parameters + private var borrowedArguments: [BorrowedArgument] = [] + private let needsReturnVariable: Bool - init(moduleName: String, abiName: String, context: BridgeContext = .importTS) { + init(moduleName: String, abiName: String, returnType: BridgeType, context: BridgeContext = .importTS) throws { self.moduleName = moduleName self.abiName = abiName + self.returnType = returnType self.context = context + let liftingInfo = try returnType.liftingReturnInfo(context: context) + needsReturnVariable = + !(returnType == .void || returnType.usesSideChannelForOptionalReturn() + || liftingInfo.valueToLift == nil) } func lowerParameter(param: Parameter) throws { @@ -115,12 +135,6 @@ public struct ImportTS { default: break } - let initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()") - - if loweringInfo.loweredParameters.isEmpty { - stackLoweringStmts.insert("let _ = \(initializerExpr)", at: 0) - return - } // Generate destructured variable names for all lowered parameters let destructuredNames = loweringInfo.loweredParameters.map { @@ -135,7 +149,30 @@ public struct ImportTS { pattern = "(" + destructuredNames.joined(separator: ", ") + ")" } - body.write("let \(pattern) = \(initializerExpr)") + if loweringInfo.useBorrowing { + let returnVariableName = "ret\(borrowedArguments.count)" + let assign = needsReturnVariable ? "let \(returnVariableName) = " : "" + body.write("\(assign)\(param.name).bridgeJSWithLoweredParameter { \(pattern) in") + body.indent() + borrowedArguments.append( + BorrowedArgument( + returnVariableName: needsReturnVariable ? returnVariableName : nil, + closeBorrowedClosure: { printer in + printer.unindent() + printer.write("}") + } + ) + ) + } else { + let initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()") + + if loweringInfo.loweredParameters.isEmpty { + stackLoweringStmts.insert("let _ = \(initializerExpr)", at: 0) + return + } + + body.write("let \(pattern) = \(initializerExpr)") + } destructuredVarNames.append(contentsOf: destructuredNames) // Add to signatures and forwardings (unified for both single and multiple) @@ -155,27 +192,35 @@ public struct ImportTS { } } - func call(returnType: BridgeType) throws { - let liftingInfo: BridgeType.LiftingReturnInfo = try returnType.liftingReturnInfo(context: context) + func call() throws { for stmt in stackLoweringStmts { body.write(stmt.description) } - let assign = - (returnType == .void || returnType.usesSideChannelForOptionalReturn() || liftingInfo.valueToLift == nil) - ? "" : "let ret = " - let callExpr = "\(abiName)(\(abiParameterForwardings.joined(separator: ", ")))" + let assign = needsReturnVariable ? "let ret = " : "" + var callExpr = "\(abiName)(\(abiParameterForwardings.joined(separator: ", ")))" if !valuesToExtendLifetimeDuringCall.isEmpty { - body.write( - "\(assign)withExtendedLifetime((\(valuesToExtendLifetimeDuringCall.joined(separator: ", ")))) {" - ) - body.indent { - body.write(callExpr) + callExpr = + "withExtendedLifetime((\(valuesToExtendLifetimeDuringCall.joined(separator: ", ")))) { \(callExpr) }" + } + + body.write("\(assign)\(callExpr)") + + if let firstBorrowedArgument = borrowedArguments.first { + if needsReturnVariable { + body.write("return ret") + } + for borrowedArgument in borrowedArguments.dropFirst().reversed() { + borrowedArgument.closeBorrowedClosure(body) + if let returnVariableName = borrowedArgument.returnVariableName { + body.write("return \(returnVariableName)") + } + } + firstBorrowedArgument.closeBorrowedClosure(body) + if let returnVariableName = firstBorrowedArgument.returnVariableName { + body.write("let ret = \(returnVariableName)") } - body.write("}") - } else { - body.write("\(assign)\(callExpr)") } // Add exception check for ImportTS context @@ -184,7 +229,7 @@ public struct ImportTS { } } - func liftReturnValue(returnType: BridgeType) throws { + func liftReturnValue() throws { let liftingInfo = try returnType.liftingReturnInfo(context: context) if returnType == .void { @@ -294,12 +339,16 @@ public struct ImportTS { _ function: ImportedFunctionSkeleton, topLevelDecls: inout [DeclSyntax] ) throws -> [DeclSyntax] { - let builder = CallJSEmission(moduleName: moduleName, abiName: function.abiName(context: nil)) + let builder = try CallJSEmission( + moduleName: moduleName, + abiName: function.abiName(context: nil), + returnType: function.returnType + ) for param in function.parameters { try builder.lowerParameter(param: param) } - try builder.call(returnType: function.returnType) - try builder.liftReturnValue(returnType: function.returnType) + try builder.call() + try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) return [ builder.renderThunkDecl( @@ -316,13 +365,17 @@ public struct ImportTS { var decls: [DeclSyntax] = [] func renderMethod(method: ImportedFunctionSkeleton) throws -> [DeclSyntax] { - let builder = CallJSEmission(moduleName: moduleName, abiName: method.abiName(context: type)) + let builder = try CallJSEmission( + moduleName: moduleName, + abiName: method.abiName(context: type), + returnType: method.returnType + ) try builder.lowerParameter(param: selfParameter) for param in method.parameters { try builder.lowerParameter(param: param) } - try builder.call(returnType: method.returnType) - try builder.liftReturnValue(returnType: method.returnType) + try builder.call() + try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) return [ builder.renderThunkDecl( @@ -335,12 +388,12 @@ public struct ImportTS { func renderStaticMethod(method: ImportedFunctionSkeleton) throws -> [DeclSyntax] { let abiName = method.abiName(context: type, operation: "static") - let builder = CallJSEmission(moduleName: moduleName, abiName: abiName) + let builder = try CallJSEmission(moduleName: moduleName, abiName: abiName, returnType: method.returnType) for param in method.parameters { try builder.lowerParameter(param: param) } - try builder.call(returnType: method.returnType) - try builder.liftReturnValue(returnType: method.returnType) + try builder.call() + try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) return [ builder.renderThunkDecl( @@ -352,12 +405,16 @@ public struct ImportTS { } func renderConstructorDecl(constructor: ImportedConstructorSkeleton) throws -> [DeclSyntax] { - let builder = CallJSEmission(moduleName: moduleName, abiName: constructor.abiName(context: type)) + let builder = try CallJSEmission( + moduleName: moduleName, + abiName: constructor.abiName(context: type), + returnType: .jsObject(nil) + ) for param in constructor.parameters { try builder.lowerParameter(param: param) } - try builder.call(returnType: .jsObject(nil)) - try builder.liftReturnValue(returnType: .jsObject(nil)) + try builder.call() + try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) return [ builder.renderThunkDecl( @@ -369,13 +426,14 @@ public struct ImportTS { } func renderGetterDecl(getter: ImportedGetterSkeleton) throws -> DeclSyntax { - let builder = CallJSEmission( + let builder = try CallJSEmission( moduleName: moduleName, - abiName: getter.abiName(context: type) + abiName: getter.abiName(context: type), + returnType: getter.type ) try builder.lowerParameter(param: selfParameter) - try builder.call(returnType: getter.type) - try builder.liftReturnValue(returnType: getter.type) + try builder.call() + try builder.liftReturnValue() topLevelDecls.append(builder.renderImportDecl()) return DeclSyntax( builder.renderThunkDecl( @@ -387,14 +445,15 @@ public struct ImportTS { } func renderSetterDecl(setter: ImportedSetterSkeleton) throws -> DeclSyntax { - let builder = CallJSEmission( + let builder = try CallJSEmission( moduleName: moduleName, - abiName: setter.abiName(context: type) + abiName: setter.abiName(context: type), + returnType: .void ) let newValue = Parameter(label: nil, name: "newValue", type: setter.type) try builder.lowerParameter(param: selfParameter) try builder.lowerParameter(param: newValue) - try builder.call(returnType: .void) + try builder.call() topLevelDecls.append(builder.renderImportDecl()) // Use functionName if available (has lowercase first char), otherwise derive from name let propertyNameForThunk: String @@ -719,12 +778,18 @@ enum SwiftCodePattern { extension BridgeType { struct LoweringParameterInfo { let loweredParameters: [(name: String, type: WasmCoreType)] + /// If true, the parameter should be lowered by using `bridgeJSWithLoweredParameter` + /// that takes a closure to handle the borrowed parameter. + var useBorrowing: Bool = false static let bool = LoweringParameterInfo(loweredParameters: [("value", .i32)]) static let int = LoweringParameterInfo(loweredParameters: [("value", .i32)]) static let float = LoweringParameterInfo(loweredParameters: [("value", .f32)]) static let double = LoweringParameterInfo(loweredParameters: [("value", .f64)]) - static let string = LoweringParameterInfo(loweredParameters: [("value", .i32)]) + static let string = LoweringParameterInfo( + loweredParameters: [("bytes", .i32), ("length", .i32)], + useBorrowing: true + ) static let jsObject = LoweringParameterInfo(loweredParameters: [("value", .i32)]) static let jsValue = LoweringParameterInfo(loweredParameters: [ ("kind", .i32), @@ -761,6 +826,9 @@ extension BridgeType { return LoweringParameterInfo(loweredParameters: [("value", .i32)]) } case .rawValueEnum(_, let rawType): + if rawType == .string { + return .string + } let wasmType = rawType.wasmCoreType ?? .i32 return LoweringParameterInfo(loweredParameters: [("value", wasmType)]) case .associatedValueEnum: @@ -784,7 +852,7 @@ extension BridgeType { let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) var params = [("isSome", WasmCoreType.i32)] params.append(contentsOf: wrappedInfo.loweredParameters) - return LoweringParameterInfo(loweredParameters: params) + return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing) case .array, .dictionary: return LoweringParameterInfo(loweredParameters: []) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index af2456f81..68232b673 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -289,6 +289,7 @@ public struct BridgeJSLink { "let \(JSGlueVariableScope.reservedInstance);", "let \(JSGlueVariableScope.reservedMemory);", "let \(JSGlueVariableScope.reservedSetException);", + "let \(JSGlueVariableScope.reservedDecodeString);", "const \(JSGlueVariableScope.reservedTextDecoder) = new TextDecoder(\"utf-8\");", "const \(JSGlueVariableScope.reservedTextEncoder) = new TextEncoder(\"utf-8\");", "let \(JSGlueVariableScope.reservedStorageToReturnString);", @@ -337,10 +338,7 @@ public struct BridgeJSLink { printer.write("bjs[\"swift_js_return_string\"] = function(ptr, len) {") printer.indent { printer.write( - "const bytes = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, ptr, len)\(sharedMemory ? ".slice()" : "");" - ) - printer.write( - "\(JSGlueVariableScope.reservedStorageToReturnString) = \(JSGlueVariableScope.reservedTextDecoder).decode(bytes);" + "\(JSGlueVariableScope.reservedStorageToReturnString) = \(JSGlueVariableScope.reservedDecodeString)(ptr, len);" ) } printer.write("}") @@ -361,10 +359,7 @@ public struct BridgeJSLink { printer.write("bjs[\"swift_js_make_js_string\"] = function(ptr, len) {") printer.indent { printer.write( - "const bytes = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, ptr, len)\(sharedMemory ? ".slice()" : "");" - ) - printer.write( - "return \(JSGlueVariableScope.reservedSwift).\(JSGlueVariableScope.reservedMemory).retain(\(JSGlueVariableScope.reservedTextDecoder).decode(bytes));" + "return \(JSGlueVariableScope.reservedSwift).\(JSGlueVariableScope.reservedMemory).retain(\(JSGlueVariableScope.reservedDecodeString)(ptr, len));" ) } printer.write("}") @@ -413,10 +408,7 @@ public struct BridgeJSLink { printer.write("}") printer.write("bjs[\"swift_js_push_string\"] = function(ptr, len) {") printer.indent { - printer.write( - "const bytes = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, ptr, len)\(sharedMemory ? ".slice()" : "");" - ) - printer.write("const value = \(JSGlueVariableScope.reservedTextDecoder).decode(bytes);") + printer.write("const value = \(JSGlueVariableScope.reservedDecodeString)(ptr, len);") printer.write("\(JSGlueVariableScope.reservedStringStack).push(value);") } printer.write("}") @@ -529,8 +521,7 @@ public struct BridgeJSLink { printer.write("} else {") printer.indent { printer.write(lines: [ - "const bytes = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, ptr, len);", - "\(JSGlueVariableScope.reservedStorageToReturnString) = \(JSGlueVariableScope.reservedTextDecoder).decode(bytes);", + "\(JSGlueVariableScope.reservedStorageToReturnString) = \(JSGlueVariableScope.reservedDecodeString)(ptr, len);" ]) } printer.write("}") @@ -1039,6 +1030,16 @@ public struct BridgeJSLink { "\(JSGlueVariableScope.reservedMemory) = \(JSGlueVariableScope.reservedInstance).exports.memory;", ]) printer.nextLine() + if sharedMemory { + printer.write( + "\(JSGlueVariableScope.reservedDecodeString) = (ptr, len) => { const bytes = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, ptr >>> 0, len >>> 0).slice(); return \(JSGlueVariableScope.reservedTextDecoder).decode(bytes); }" + ) + } else { + printer.write( + "\(JSGlueVariableScope.reservedDecodeString) = (ptr, len) => { const bytes = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, ptr >>> 0, len >>> 0); return \(JSGlueVariableScope.reservedTextDecoder).decode(bytes); }" + ) + } + printer.nextLine() // Error handling printer.write("\(JSGlueVariableScope.reservedSetException) = (error) => {") printer.indent { diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index ba0d0d86c..bec5ce3e9 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -13,6 +13,7 @@ final class JSGlueVariableScope { static let reservedInstance = "instance" static let reservedMemory = "memory" static let reservedSetException = "setException" + static let reservedDecodeString = "decodeString" static let reservedStorageToReturnString = "tmpRetString" static let reservedStorageToReturnBytes = "tmpRetBytes" static let reservedStorageToReturnException = "tmpRetException" @@ -40,6 +41,7 @@ final class JSGlueVariableScope { reservedInstance, reservedMemory, reservedSetException, + reservedDecodeString, reservedStorageToReturnString, reservedStorageToReturnBytes, reservedStorageToReturnException, @@ -261,17 +263,16 @@ struct IntrinsicJSFragment: Sendable { } ) static let stringLiftParameter = IntrinsicJSFragment( - parameters: ["objectId"], + parameters: ["bytes", "count"], printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) - let objectId = arguments[0] - let objectLabel = scope.variable("\(objectId)Object") - // TODO: Implement "take" operation + let bytesExpr = arguments[0] + let countExpr = arguments[1] + let stringLabel = scope.variable("string") printer.write( - "const \(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(objectId));" + "const \(stringLabel) = \(JSGlueVariableScope.reservedDecodeString)(\(bytesExpr), \(countExpr));" ) - printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(objectId));") - return [objectLabel] + return [stringLabel] } ) static let stringLowerReturn = IntrinsicJSFragment( diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift index c3c3d5e7f..4511ed1df 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift @@ -453,19 +453,20 @@ public func _bjs_validateSession(_ session: Int32) -> Void { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_takesFeatureFlag") -fileprivate func bjs_takesFeatureFlag_extern(_ flag: Int32) -> Void +fileprivate func bjs_takesFeatureFlag_extern(_ flagBytes: Int32, _ flagLength: Int32) -> Void #else -fileprivate func bjs_takesFeatureFlag_extern(_ flag: Int32) -> Void { +fileprivate func bjs_takesFeatureFlag_extern(_ flagBytes: Int32, _ flagLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_takesFeatureFlag(_ flag: Int32) -> Void { - return bjs_takesFeatureFlag_extern(flag) +@inline(never) fileprivate func bjs_takesFeatureFlag(_ flagBytes: Int32, _ flagLength: Int32) -> Void { + return bjs_takesFeatureFlag_extern(flagBytes, flagLength) } func _$takesFeatureFlag(_ flag: FeatureFlag) throws(JSException) -> Void { - let flagValue = flag.bridgeJSLowerParameter() - bjs_takesFeatureFlag(flagValue) + flag.bridgeJSWithLoweredParameter { (flagBytes, flagLength) in + bjs_takesFeatureFlag(flagBytes, flagLength) + } if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.swift index b42f71563..5e7088db8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.swift @@ -20,20 +20,21 @@ func _$console_get() throws(JSException) -> JSConsole { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_JSConsole_log") -fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ message: Int32) -> Void +fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ messageBytes: Int32, _ messageLength: Int32) -> Void #else -fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ message: Int32) -> Void { +fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ messageBytes: Int32, _ messageLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_JSConsole_log(_ self: Int32, _ message: Int32) -> Void { - return bjs_JSConsole_log_extern(self, message) +@inline(never) fileprivate func bjs_JSConsole_log(_ self: Int32, _ messageBytes: Int32, _ messageLength: Int32) -> Void { + return bjs_JSConsole_log_extern(self, messageBytes, messageLength) } func _$JSConsole_log(_ self: JSObject, _ message: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let messageValue = message.bridgeJSLowerParameter() - bjs_JSConsole_log(selfValue, messageValue) + message.bridgeJSWithLoweredParameter { (messageBytes, messageLength) in + bjs_JSConsole_log(selfValue, messageBytes, messageLength) + } if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.swift index 58d69eed1..35b1c6281 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.swift @@ -20,19 +20,22 @@ func _$console_get() throws(JSException) -> JSConsole { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_parseInt") -fileprivate func bjs_parseInt_extern(_ string: Int32) -> Float64 +fileprivate func bjs_parseInt_extern(_ stringBytes: Int32, _ stringLength: Int32) -> Float64 #else -fileprivate func bjs_parseInt_extern(_ string: Int32) -> Float64 { +fileprivate func bjs_parseInt_extern(_ stringBytes: Int32, _ stringLength: Int32) -> Float64 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_parseInt(_ string: Int32) -> Float64 { - return bjs_parseInt_extern(string) +@inline(never) fileprivate func bjs_parseInt(_ stringBytes: Int32, _ stringLength: Int32) -> Float64 { + return bjs_parseInt_extern(stringBytes, stringLength) } func _$parseInt(_ string: String) throws(JSException) -> Double { - let stringValue = string.bridgeJSLowerParameter() - let ret = bjs_parseInt(stringValue) + let ret0 = string.bridgeJSWithLoweredParameter { (stringBytes, stringLength) in + let ret = bjs_parseInt(stringBytes, stringLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -41,20 +44,21 @@ func _$parseInt(_ string: String) throws(JSException) -> Double { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_JSConsole_log") -fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ message: Int32) -> Void +fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ messageBytes: Int32, _ messageLength: Int32) -> Void #else -fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ message: Int32) -> Void { +fileprivate func bjs_JSConsole_log_extern(_ self: Int32, _ messageBytes: Int32, _ messageLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_JSConsole_log(_ self: Int32, _ message: Int32) -> Void { - return bjs_JSConsole_log_extern(self, message) +@inline(never) fileprivate func bjs_JSConsole_log(_ self: Int32, _ messageBytes: Int32, _ messageLength: Int32) -> Void { + return bjs_JSConsole_log_extern(self, messageBytes, messageLength) } func _$JSConsole_log(_ self: JSObject, _ message: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let messageValue = message.bridgeJSLowerParameter() - bjs_JSConsole_log(selfValue, messageValue) + message.bridgeJSWithLoweredParameter { (messageBytes, messageLength) in + bjs_JSConsole_log(selfValue, messageBytes, messageLength) + } if let error = _swift_js_take_exception() { throw error } @@ -62,14 +66,14 @@ func _$JSConsole_log(_ self: JSObject, _ message: String) throws(JSException) -> #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WebSocket_init") -fileprivate func bjs_WebSocket_init_extern(_ url: Int32) -> Int32 +fileprivate func bjs_WebSocket_init_extern(_ urlBytes: Int32, _ urlLength: Int32) -> Int32 #else -fileprivate func bjs_WebSocket_init_extern(_ url: Int32) -> Int32 { +fileprivate func bjs_WebSocket_init_extern(_ urlBytes: Int32, _ urlLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WebSocket_init(_ url: Int32) -> Int32 { - return bjs_WebSocket_init_extern(url) +@inline(never) fileprivate func bjs_WebSocket_init(_ urlBytes: Int32, _ urlLength: Int32) -> Int32 { + return bjs_WebSocket_init_extern(urlBytes, urlLength) } #if arch(wasm32) @@ -85,8 +89,11 @@ fileprivate func bjs_WebSocket_close_extern(_ self: Int32) -> Void { } func _$WebSocket_init(_ url: String) throws(JSException) -> JSObject { - let urlValue = url.bridgeJSLowerParameter() - let ret = bjs_WebSocket_init(urlValue) + let ret0 = url.bridgeJSWithLoweredParameter { (urlBytes, urlLength) in + let ret = bjs_WebSocket_init(urlBytes, urlLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.swift index 2ff17ea24..7f7fa8685 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.swift @@ -136,14 +136,14 @@ fileprivate func bjs_WeirdNaming_Any_get_extern(_ self: Int32) -> Int32 { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WeirdNaming_normalProperty_set") -fileprivate func bjs_WeirdNaming_normalProperty_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_WeirdNaming_normalProperty_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_WeirdNaming_normalProperty_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_WeirdNaming_normalProperty_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WeirdNaming_normalProperty_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_WeirdNaming_normalProperty_set_extern(self, newValue) +@inline(never) fileprivate func bjs_WeirdNaming_normalProperty_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WeirdNaming_normalProperty_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @@ -172,14 +172,14 @@ fileprivate func bjs_WeirdNaming__123invalidStart_set_extern(_ self: Int32, _ ne #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WeirdNaming_property_with_spaces_set") -fileprivate func bjs_WeirdNaming_property_with_spaces_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_WeirdNaming_property_with_spaces_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_WeirdNaming_property_with_spaces_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_WeirdNaming_property_with_spaces_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WeirdNaming_property_with_spaces_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_WeirdNaming_property_with_spaces_set_extern(self, newValue) +@inline(never) fileprivate func bjs_WeirdNaming_property_with_spaces_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WeirdNaming_property_with_spaces_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @@ -196,38 +196,38 @@ fileprivate func bjs_WeirdNaming__specialChar_set_extern(_ self: Int32, _ newVal #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WeirdNaming_constructor_set") -fileprivate func bjs_WeirdNaming_constructor_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_WeirdNaming_constructor_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_WeirdNaming_constructor_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_WeirdNaming_constructor_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WeirdNaming_constructor_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_WeirdNaming_constructor_set_extern(self, newValue) +@inline(never) fileprivate func bjs_WeirdNaming_constructor_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WeirdNaming_constructor_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WeirdNaming_for_set") -fileprivate func bjs_WeirdNaming_for_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_WeirdNaming_for_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_WeirdNaming_for_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_WeirdNaming_for_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WeirdNaming_for_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_WeirdNaming_for_set_extern(self, newValue) +@inline(never) fileprivate func bjs_WeirdNaming_for_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WeirdNaming_for_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WeirdNaming_any_set") -fileprivate func bjs_WeirdNaming_any_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_WeirdNaming_any_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_WeirdNaming_any_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_WeirdNaming_any_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WeirdNaming_any_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_WeirdNaming_any_set_extern(self, newValue) +@inline(never) fileprivate func bjs_WeirdNaming_any_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WeirdNaming_any_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @@ -328,8 +328,9 @@ func _$WeirdNaming_Any_get(_ self: JSObject) throws(JSException) -> String { func _$WeirdNaming_normalProperty_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_WeirdNaming_normalProperty_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_WeirdNaming_normalProperty_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -355,8 +356,9 @@ func _$WeirdNaming__123invalidStart_set(_ self: JSObject, _ newValue: Bool) thro func _$WeirdNaming_property_with_spaces_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_WeirdNaming_property_with_spaces_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_WeirdNaming_property_with_spaces_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -373,8 +375,9 @@ func _$WeirdNaming__specialChar_set(_ self: JSObject, _ newValue: Double) throws func _$WeirdNaming_constructor_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_WeirdNaming_constructor_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_WeirdNaming_constructor_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -382,8 +385,9 @@ func _$WeirdNaming_constructor_set(_ self: JSObject, _ newValue: String) throws( func _$WeirdNaming_for_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_WeirdNaming_for_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_WeirdNaming_for_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -391,8 +395,9 @@ func _$WeirdNaming_for_set(_ self: JSObject, _ newValue: String) throws(JSExcept func _$WeirdNaming_any_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_WeirdNaming_any_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_WeirdNaming_any_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.swift index 11a644759..3e1de0030 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.swift @@ -20,14 +20,14 @@ func _$returnAnimatable() throws(JSException) -> Animatable { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_Greeter_init") -fileprivate func bjs_Greeter_init_extern(_ name: Int32) -> Int32 +fileprivate func bjs_Greeter_init_extern(_ nameBytes: Int32, _ nameLength: Int32) -> Int32 #else -fileprivate func bjs_Greeter_init_extern(_ name: Int32) -> Int32 { +fileprivate func bjs_Greeter_init_extern(_ nameBytes: Int32, _ nameLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_Greeter_init(_ name: Int32) -> Int32 { - return bjs_Greeter_init_extern(name) +@inline(never) fileprivate func bjs_Greeter_init(_ nameBytes: Int32, _ nameLength: Int32) -> Int32 { + return bjs_Greeter_init_extern(nameBytes, nameLength) } #if arch(wasm32) @@ -56,14 +56,14 @@ fileprivate func bjs_Greeter_age_get_extern(_ self: Int32) -> Float64 { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_Greeter_name_set") -fileprivate func bjs_Greeter_name_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_Greeter_name_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_Greeter_name_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_Greeter_name_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_Greeter_name_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_Greeter_name_set_extern(self, newValue) +@inline(never) fileprivate func bjs_Greeter_name_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_Greeter_name_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @@ -80,19 +80,22 @@ fileprivate func bjs_Greeter_greet_extern(_ self: Int32) -> Int32 { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_Greeter_changeName") -fileprivate func bjs_Greeter_changeName_extern(_ self: Int32, _ name: Int32) -> Void +fileprivate func bjs_Greeter_changeName_extern(_ self: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void #else -fileprivate func bjs_Greeter_changeName_extern(_ self: Int32, _ name: Int32) -> Void { +fileprivate func bjs_Greeter_changeName_extern(_ self: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_Greeter_changeName(_ self: Int32, _ name: Int32) -> Void { - return bjs_Greeter_changeName_extern(self, name) +@inline(never) fileprivate func bjs_Greeter_changeName(_ self: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { + return bjs_Greeter_changeName_extern(self, nameBytes, nameLength) } func _$Greeter_init(_ name: String) throws(JSException) -> JSObject { - let nameValue = name.bridgeJSLowerParameter() - let ret = bjs_Greeter_init(nameValue) + let ret0 = name.bridgeJSWithLoweredParameter { (nameBytes, nameLength) in + let ret = bjs_Greeter_init(nameBytes, nameLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -119,8 +122,9 @@ func _$Greeter_age_get(_ self: JSObject) throws(JSException) -> Double { func _$Greeter_name_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_Greeter_name_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_Greeter_name_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -137,8 +141,9 @@ func _$Greeter_greet(_ self: JSObject) throws(JSException) -> String { func _$Greeter_changeName(_ self: JSObject, _ name: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let nameValue = name.bridgeJSLowerParameter() - bjs_Greeter_changeName(selfValue, nameValue) + name.bridgeJSWithLoweredParameter { (nameBytes, nameLength) in + bjs_Greeter_changeName(selfValue, nameBytes, nameLength) + } if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift index eafbd3253..ca1078836 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift @@ -348,14 +348,14 @@ fileprivate func _bjs_OptionalPropertyHolder_wrap_extern(_ pointer: UnsafeMutabl #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_init") -fileprivate func bjs_WithOptionalJSClass_init_extern(_ valueOrNullIsSome: Int32, _ valueOrNullValue: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedValue: Int32) -> Int32 +fileprivate func bjs_WithOptionalJSClass_init_extern(_ valueOrNullIsSome: Int32, _ valueOrNullBytes: Int32, _ valueOrNullLength: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedBytes: Int32, _ valueOrUndefinedLength: Int32) -> Int32 #else -fileprivate func bjs_WithOptionalJSClass_init_extern(_ valueOrNullIsSome: Int32, _ valueOrNullValue: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedValue: Int32) -> Int32 { +fileprivate func bjs_WithOptionalJSClass_init_extern(_ valueOrNullIsSome: Int32, _ valueOrNullBytes: Int32, _ valueOrNullLength: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedBytes: Int32, _ valueOrUndefinedLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WithOptionalJSClass_init(_ valueOrNullIsSome: Int32, _ valueOrNullValue: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedValue: Int32) -> Int32 { - return bjs_WithOptionalJSClass_init_extern(valueOrNullIsSome, valueOrNullValue, valueOrUndefinedIsSome, valueOrUndefinedValue) +@inline(never) fileprivate func bjs_WithOptionalJSClass_init(_ valueOrNullIsSome: Int32, _ valueOrNullBytes: Int32, _ valueOrNullLength: Int32, _ valueOrUndefinedIsSome: Int32, _ valueOrUndefinedBytes: Int32, _ valueOrUndefinedLength: Int32) -> Int32 { + return bjs_WithOptionalJSClass_init_extern(valueOrNullIsSome, valueOrNullBytes, valueOrNullLength, valueOrUndefinedIsSome, valueOrUndefinedBytes, valueOrUndefinedLength) } #if arch(wasm32) @@ -456,26 +456,26 @@ fileprivate func bjs_WithOptionalJSClass_intOrUndefined_get_extern(_ self: Int32 #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_stringOrNull_set") -fileprivate func bjs_WithOptionalJSClass_stringOrNull_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +fileprivate func bjs_WithOptionalJSClass_stringOrNull_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_WithOptionalJSClass_stringOrNull_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { +fileprivate func bjs_WithOptionalJSClass_stringOrNull_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WithOptionalJSClass_stringOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { - return bjs_WithOptionalJSClass_stringOrNull_set_extern(self, newValueIsSome, newValueValue) +@inline(never) fileprivate func bjs_WithOptionalJSClass_stringOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WithOptionalJSClass_stringOrNull_set_extern(self, newValueIsSome, newValueBytes, newValueLength) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_stringOrUndefined_set") -fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { +fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { - return bjs_WithOptionalJSClass_stringOrUndefined_set_extern(self, newValueIsSome, newValueValue) +@inline(never) fileprivate func bjs_WithOptionalJSClass_stringOrUndefined_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WithOptionalJSClass_stringOrUndefined_set_extern(self, newValueIsSome, newValueBytes, newValueLength) } #if arch(wasm32) @@ -552,26 +552,26 @@ fileprivate func bjs_WithOptionalJSClass_intOrUndefined_set_extern(_ self: Int32 #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripStringOrNull") -fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull_extern(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull_extern(_ self: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void #else -fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull_extern(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull_extern(_ self: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { - return bjs_WithOptionalJSClass_roundTripStringOrNull_extern(self, valueIsSome, valueValue) +@inline(never) fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return bjs_WithOptionalJSClass_roundTripStringOrNull_extern(self, valueIsSome, valueBytes, valueLength) } #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripStringOrUndefined") -fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined_extern(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined_extern(_ self: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void #else -fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined_extern(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { +fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined_extern(_ self: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { - return bjs_WithOptionalJSClass_roundTripStringOrUndefined_extern(self, valueIsSome, valueValue) +@inline(never) fileprivate func bjs_WithOptionalJSClass_roundTripStringOrUndefined(_ self: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return bjs_WithOptionalJSClass_roundTripStringOrUndefined_extern(self, valueIsSome, valueBytes, valueLength) } #if arch(wasm32) @@ -647,9 +647,14 @@ fileprivate func bjs_WithOptionalJSClass_roundTripIntOrUndefined_extern(_ self: } func _$WithOptionalJSClass_init(_ valueOrNull: Optional, _ valueOrUndefined: JSUndefinedOr) throws(JSException) -> JSObject { - let (valueOrNullIsSome, valueOrNullValue) = valueOrNull.bridgeJSLowerParameter() - let (valueOrUndefinedIsSome, valueOrUndefinedValue) = valueOrUndefined.bridgeJSLowerParameter() - let ret = bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullValue, valueOrUndefinedIsSome, valueOrUndefinedValue) + let ret0 = valueOrNull.bridgeJSWithLoweredParameter { (valueOrNullIsSome, valueOrNullBytes, valueOrNullLength) in + let ret1 = valueOrUndefined.bridgeJSWithLoweredParameter { (valueOrUndefinedIsSome, valueOrUndefinedBytes, valueOrUndefinedLength) in + let ret = bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullBytes, valueOrNullLength, valueOrUndefinedIsSome, valueOrUndefinedBytes, valueOrUndefinedLength) + return ret + } + return ret1 + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -730,8 +735,9 @@ func _$WithOptionalJSClass_intOrUndefined_get(_ self: JSObject) throws(JSExcepti func _$WithOptionalJSClass_stringOrNull_set(_ self: JSObject, _ newValue: Optional) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() - bjs_WithOptionalJSClass_stringOrNull_set(selfValue, newValueIsSome, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueIsSome, newValueBytes, newValueLength) in + bjs_WithOptionalJSClass_stringOrNull_set(selfValue, newValueIsSome, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -739,8 +745,9 @@ func _$WithOptionalJSClass_stringOrNull_set(_ self: JSObject, _ newValue: Option func _$WithOptionalJSClass_stringOrUndefined_set(_ self: JSObject, _ newValue: JSUndefinedOr) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() - bjs_WithOptionalJSClass_stringOrUndefined_set(selfValue, newValueIsSome, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueIsSome, newValueBytes, newValueLength) in + bjs_WithOptionalJSClass_stringOrUndefined_set(selfValue, newValueIsSome, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -802,8 +809,9 @@ func _$WithOptionalJSClass_intOrUndefined_set(_ self: JSObject, _ newValue: JSUn func _$WithOptionalJSClass_roundTripStringOrNull(_ self: JSObject, _ value: Optional) throws(JSException) -> Optional { let selfValue = self.bridgeJSLowerParameter() - let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() - bjs_WithOptionalJSClass_roundTripStringOrNull(selfValue, valueIsSome, valueValue) + value.bridgeJSWithLoweredParameter { (valueIsSome, valueBytes, valueLength) in + bjs_WithOptionalJSClass_roundTripStringOrNull(selfValue, valueIsSome, valueBytes, valueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -812,8 +820,9 @@ func _$WithOptionalJSClass_roundTripStringOrNull(_ self: JSObject, _ value: Opti func _$WithOptionalJSClass_roundTripStringOrUndefined(_ self: JSObject, _ value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr { let selfValue = self.bridgeJSLowerParameter() - let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() - bjs_WithOptionalJSClass_roundTripStringOrUndefined(selfValue, valueIsSome, valueValue) + value.bridgeJSWithLoweredParameter { (valueIsSome, valueBytes, valueLength) in + bjs_WithOptionalJSClass_roundTripStringOrUndefined(selfValue, valueIsSome, valueBytes, valueLength) + } if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index 785cb997a..d9cd22836 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -8,8 +8,9 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto func onValueChanged(_ value: String) -> Void { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let valueValue = value.bridgeJSLowerParameter() - _extern_onValueChanged(jsObjectValue, valueValue) + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + _extern_onValueChanged(jsObjectValue, valueBytes, valueLength) + } } func onCountUpdated(count: Int) -> Bool { @@ -21,9 +22,11 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto func onLabelUpdated(_ prefix: String, _ suffix: String) -> Void { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let prefixValue = prefix.bridgeJSLowerParameter() - let suffixValue = suffix.bridgeJSLowerParameter() - _extern_onLabelUpdated(jsObjectValue, prefixValue, suffixValue) + prefix.bridgeJSWithLoweredParameter { (prefixBytes, prefixLength) in + suffix.bridgeJSWithLoweredParameter { (suffixBytes, suffixLength) in + _extern_onLabelUpdated(jsObjectValue, prefixBytes, prefixLength, suffixBytes, suffixLength) + } + } } func isCountEven() -> Bool { @@ -103,8 +106,9 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto } set { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() - bjs_MyViewControllerDelegate_optionalName_set(jsObjectValue, newValueIsSome, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueIsSome, newValueBytes, newValueLength) in + bjs_MyViewControllerDelegate_optionalName_set(jsObjectValue, newValueIsSome, newValueBytes, newValueLength) + } } } @@ -116,8 +120,9 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto } set { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() - bjs_MyViewControllerDelegate_optionalRawEnum_set(jsObjectValue, newValueIsSome, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueIsSome, newValueBytes, newValueLength) in + bjs_MyViewControllerDelegate_optionalRawEnum_set(jsObjectValue, newValueIsSome, newValueBytes, newValueLength) + } } } @@ -129,8 +134,9 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto } set { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_MyViewControllerDelegate_rawStringEnum_set(jsObjectValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_MyViewControllerDelegate_rawStringEnum_set(jsObjectValue, newValueBytes, newValueLength) + } } } @@ -231,14 +237,14 @@ fileprivate func _extern_onSomethingHappened_extern(_ jsObject: Int32) -> Void { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onValueChanged") -fileprivate func _extern_onValueChanged_extern(_ jsObject: Int32, _ value: Int32) -> Void +fileprivate func _extern_onValueChanged_extern(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void #else -fileprivate func _extern_onValueChanged_extern(_ jsObject: Int32, _ value: Int32) -> Void { +fileprivate func _extern_onValueChanged_extern(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onValueChanged(_ jsObject: Int32, _ value: Int32) -> Void { - return _extern_onValueChanged_extern(jsObject, value) +@inline(never) fileprivate func _extern_onValueChanged(_ jsObject: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return _extern_onValueChanged_extern(jsObject, valueBytes, valueLength) } #if arch(wasm32) @@ -255,14 +261,14 @@ fileprivate func _extern_onCountUpdated_extern(_ jsObject: Int32, _ count: Int32 #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onLabelUpdated") -fileprivate func _extern_onLabelUpdated_extern(_ jsObject: Int32, _ prefix: Int32, _ suffix: Int32) -> Void +fileprivate func _extern_onLabelUpdated_extern(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void #else -fileprivate func _extern_onLabelUpdated_extern(_ jsObject: Int32, _ prefix: Int32, _ suffix: Int32) -> Void { +fileprivate func _extern_onLabelUpdated_extern(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_onLabelUpdated(_ jsObject: Int32, _ prefix: Int32, _ suffix: Int32) -> Void { - return _extern_onLabelUpdated_extern(jsObject, prefix, suffix) +@inline(never) fileprivate func _extern_onLabelUpdated(_ jsObject: Int32, _ prefixBytes: Int32, _ prefixLength: Int32, _ suffixBytes: Int32, _ suffixLength: Int32) -> Void { + return _extern_onLabelUpdated_extern(jsObject, prefixBytes, prefixLength, suffixBytes, suffixLength) } #if arch(wasm32) @@ -411,14 +417,14 @@ fileprivate func bjs_MyViewControllerDelegate_optionalName_get_extern(_ jsObject #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalName_set") -fileprivate func bjs_MyViewControllerDelegate_optionalName_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +fileprivate func bjs_MyViewControllerDelegate_optionalName_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_MyViewControllerDelegate_optionalName_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { +fileprivate func bjs_MyViewControllerDelegate_optionalName_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_MyViewControllerDelegate_optionalName_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { - return bjs_MyViewControllerDelegate_optionalName_set_extern(jsObject, newValueIsSome, newValueValue) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_optionalName_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_MyViewControllerDelegate_optionalName_set_extern(jsObject, newValueIsSome, newValueBytes, newValueLength) } #if arch(wasm32) @@ -435,14 +441,14 @@ fileprivate func bjs_MyViewControllerDelegate_optionalRawEnum_get_extern(_ jsObj #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalRawEnum_set") -fileprivate func bjs_MyViewControllerDelegate_optionalRawEnum_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +fileprivate func bjs_MyViewControllerDelegate_optionalRawEnum_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_MyViewControllerDelegate_optionalRawEnum_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { +fileprivate func bjs_MyViewControllerDelegate_optionalRawEnum_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_MyViewControllerDelegate_optionalRawEnum_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { - return bjs_MyViewControllerDelegate_optionalRawEnum_set_extern(jsObject, newValueIsSome, newValueValue) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_optionalRawEnum_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_MyViewControllerDelegate_optionalRawEnum_set_extern(jsObject, newValueIsSome, newValueBytes, newValueLength) } #if arch(wasm32) @@ -459,14 +465,14 @@ fileprivate func bjs_MyViewControllerDelegate_rawStringEnum_get_extern(_ jsObjec #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_rawStringEnum_set") -fileprivate func bjs_MyViewControllerDelegate_rawStringEnum_set_extern(_ jsObject: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_MyViewControllerDelegate_rawStringEnum_set_extern(_ jsObject: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_MyViewControllerDelegate_rawStringEnum_set_extern(_ jsObject: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_MyViewControllerDelegate_rawStringEnum_set_extern(_ jsObject: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_MyViewControllerDelegate_rawStringEnum_set(_ jsObject: Int32, _ newValue: Int32) -> Void { - return bjs_MyViewControllerDelegate_rawStringEnum_set_extern(jsObject, newValue) +@inline(never) fileprivate func bjs_MyViewControllerDelegate_rawStringEnum_set(_ jsObject: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_MyViewControllerDelegate_rawStringEnum_set_extern(jsObject, newValueBytes, newValueLength) } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.swift index 427c2b576..0760df764 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.swift @@ -21,19 +21,20 @@ public func _bjs_roundtripString(_ aBytes: Int32, _ aLength: Int32) -> Void { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_checkString") -fileprivate func bjs_checkString_extern(_ a: Int32) -> Void +fileprivate func bjs_checkString_extern(_ aBytes: Int32, _ aLength: Int32) -> Void #else -fileprivate func bjs_checkString_extern(_ a: Int32) -> Void { +fileprivate func bjs_checkString_extern(_ aBytes: Int32, _ aLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_checkString(_ a: Int32) -> Void { - return bjs_checkString_extern(a) +@inline(never) fileprivate func bjs_checkString(_ aBytes: Int32, _ aLength: Int32) -> Void { + return bjs_checkString_extern(aBytes, aLength) } func _$checkString(_ a: String) throws(JSException) -> Void { - let aValue = a.bridgeJSLowerParameter() - bjs_checkString(aValue) + a.bridgeJSWithLoweredParameter { (aBytes, aLength) in + bjs_checkString(aBytes, aLength) + } if let error = _swift_js_take_exception() { throw error } @@ -41,20 +42,21 @@ func _$checkString(_ a: String) throws(JSException) -> Void { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_checkStringWithLength") -fileprivate func bjs_checkStringWithLength_extern(_ a: Int32, _ b: Float64) -> Void +fileprivate func bjs_checkStringWithLength_extern(_ aBytes: Int32, _ aLength: Int32, _ b: Float64) -> Void #else -fileprivate func bjs_checkStringWithLength_extern(_ a: Int32, _ b: Float64) -> Void { +fileprivate func bjs_checkStringWithLength_extern(_ aBytes: Int32, _ aLength: Int32, _ b: Float64) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_checkStringWithLength(_ a: Int32, _ b: Float64) -> Void { - return bjs_checkStringWithLength_extern(a, b) +@inline(never) fileprivate func bjs_checkStringWithLength(_ aBytes: Int32, _ aLength: Int32, _ b: Float64) -> Void { + return bjs_checkStringWithLength_extern(aBytes, aLength, b) } func _$checkStringWithLength(_ a: String, _ b: Double) throws(JSException) -> Void { - let aValue = a.bridgeJSLowerParameter() - let bValue = b.bridgeJSLowerParameter() - bjs_checkStringWithLength(aValue, bValue) + a.bridgeJSWithLoweredParameter { (aBytes, aLength) in + let bValue = b.bridgeJSLowerParameter() + bjs_checkStringWithLength(aBytes, aLength, bValue) + } if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index d4bdc4a58..e2cf9e09b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -63,14 +63,14 @@ public func _invoke_swift_closure_TestModule_10TestModule10HttpStatusO_10HttpSta #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO") -fileprivate func invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO_extern(_ callback: Int32, _ param0: Int32) -> Int32 +fileprivate func invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 #else -fileprivate func invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO_extern(_ callback: Int32, _ param0: Int32) -> Int32 { +fileprivate func invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO(_ callback: Int32, _ param0: Int32) -> Int32 { - return invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO_extern(callback, param0Bytes, param0Length) } #if arch(wasm32) @@ -91,8 +91,11 @@ private enum _BJS_Closure_10TestModule5ThemeO_5ThemeO { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let param0Value = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO(callbackValue, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 return Theme.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -315,14 +318,14 @@ public func _invoke_swift_closure_TestModule_10TestModule9DirectionO_9DirectionO #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSS_SS") -fileprivate func invoke_js_callback_TestModule_10TestModuleSS_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 +fileprivate func invoke_js_callback_TestModule_10TestModuleSS_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 #else -fileprivate func invoke_js_callback_TestModule_10TestModuleSS_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 { +fileprivate func invoke_js_callback_TestModule_10TestModuleSS_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSS_SS(_ callback: Int32, _ param0: Int32) -> Int32 { - return invoke_js_callback_TestModule_10TestModuleSS_SS_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSS_SS(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuleSS_SS_extern(callback, param0Bytes, param0Length) } #if arch(wasm32) @@ -343,8 +346,11 @@ private enum _BJS_Closure_10TestModuleSS_SS { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let param0Value = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_TestModule_10TestModuleSS_SS(callbackValue, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_TestModule_10TestModuleSS_SS(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 return String.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -693,14 +699,14 @@ public func _invoke_swift_closure_TestModule_10TestModuleSq10HttpStatusO_Sq10Htt #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO") -fileprivate func invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Void +fileprivate func invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void #else -fileprivate func invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { +fileprivate func invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { - return invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO_extern(callback, param0IsSome, param0Value) +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO_extern(callback, param0IsSome, param0Bytes, param0Length) } #if arch(wasm32) @@ -721,8 +727,9 @@ private enum _BJS_Closure_10TestModuleSq5ThemeO_Sq5ThemeO { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let (param0IsSome, param0Value) = param0.bridgeJSLowerParameter() - invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(callbackValue, param0IsSome, param0Value) + param0.bridgeJSWithLoweredParameter { (param0IsSome, param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(callbackValue, param0IsSome, param0Bytes, param0Length) + } return Optional.bridgeJSLiftReturnFromSideChannel() #else fatalError("Only available on WebAssembly") @@ -945,14 +952,14 @@ public func _invoke_swift_closure_TestModule_10TestModuleSq9DirectionO_Sq9Direct #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSqSS_SqSS") -fileprivate func invoke_js_callback_TestModule_10TestModuleSqSS_SqSS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Void +fileprivate func invoke_js_callback_TestModule_10TestModuleSqSS_SqSS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void #else -fileprivate func invoke_js_callback_TestModule_10TestModuleSqSS_SqSS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { +fileprivate func invoke_js_callback_TestModule_10TestModuleSqSS_SqSS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSqSS_SqSS(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { - return invoke_js_callback_TestModule_10TestModuleSqSS_SqSS_extern(callback, param0IsSome, param0Value) +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSqSS_SqSS(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleSqSS_SqSS_extern(callback, param0IsSome, param0Bytes, param0Length) } #if arch(wasm32) @@ -973,8 +980,9 @@ private enum _BJS_Closure_10TestModuleSqSS_SqSS { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let (param0IsSome, param0Value) = param0.bridgeJSLowerParameter() - invoke_js_callback_TestModule_10TestModuleSqSS_SqSS(callbackValue, param0IsSome, param0Value) + param0.bridgeJSWithLoweredParameter { (param0IsSome, param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModuleSqSS_SqSS(callbackValue, param0IsSome, param0Bytes, param0Length) + } return Optional.bridgeJSLiftReturnFromSideChannel() #else fatalError("Only available on WebAssembly") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index 81b432012..fcd29e31a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -21,6 +21,7 @@ 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; @@ -62,8 +63,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -72,8 +72,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -99,8 +98,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -157,8 +155,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -330,6 +327,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 6e7e810ca..d274e5606 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -189,6 +186,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index b514a50f8..67e73fb33 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -14,6 +14,7 @@ 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; @@ -79,8 +80,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -89,8 +89,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -116,8 +115,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -181,8 +179,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -261,6 +258,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 8627b2c80..7c31ce220 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -223,6 +220,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 8e9dfa65f..18cc2c945 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -89,6 +89,7 @@ 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; @@ -770,8 +771,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -780,8 +780,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -807,8 +806,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -865,8 +863,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -937,6 +934,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index 0ea2b0a53..a79d508a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -32,6 +32,7 @@ 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; @@ -61,8 +62,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -71,8 +71,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -98,8 +97,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -149,8 +147,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -213,6 +210,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index 7c3166d36..e52cf02d5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -52,6 +52,7 @@ 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; @@ -81,8 +82,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -91,8 +91,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -118,8 +117,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -169,8 +167,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -253,6 +250,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index 6eea84ffa..2d05a7a2d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -33,6 +33,7 @@ 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; @@ -62,8 +63,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -72,8 +72,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -99,8 +98,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -150,8 +148,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -234,6 +231,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index efd75f1fa..5d28ce60b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -83,6 +83,7 @@ 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; @@ -113,8 +114,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -123,8 +123,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -150,8 +149,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -201,8 +199,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -261,11 +258,10 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_closure_unregister"] = function(funcRef) {} const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; - TestModule["bjs_takesFeatureFlag"] = function bjs_takesFeatureFlag(flag) { + TestModule["bjs_takesFeatureFlag"] = function bjs_takesFeatureFlag(flagBytes, flagCount) { try { - const flagObject = swift.memory.getObject(flag); - swift.memory.release(flag); - imports.takesFeatureFlag(flagObject); + const string = decodeString(flagBytes, flagCount); + imports.takesFeatureFlag(string); } catch (error) { setException(error); } @@ -284,6 +280,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js index 21613733e..4d1e7abdf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -195,11 +192,10 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_JSConsole_log"] = function bjs_JSConsole_log(self, message) { + TestModule["bjs_JSConsole_log"] = function bjs_JSConsole_log(self, messageBytes, messageCount) { try { - const messageObject = swift.memory.getObject(message); - swift.memory.release(message); - swift.memory.getObject(self).log(messageObject); + const string = decodeString(messageBytes, messageCount); + swift.memory.getObject(self).log(string); } catch (error) { setException(error); } @@ -209,6 +205,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js index 21296b88a..e4a17ebd0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -194,31 +191,28 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_parseInt"] = function bjs_parseInt(string) { + TestModule["bjs_parseInt"] = function bjs_parseInt(stringBytes, stringCount) { try { - const stringObject = swift.memory.getObject(string); - swift.memory.release(string); - let ret = globalThis.parseInt(stringObject); + const string = decodeString(stringBytes, stringCount); + let ret = globalThis.parseInt(string); return ret; } catch (error) { setException(error); return 0 } } - TestModule["bjs_JSConsole_log"] = function bjs_JSConsole_log(self, message) { + TestModule["bjs_JSConsole_log"] = function bjs_JSConsole_log(self, messageBytes, messageCount) { try { - const messageObject = swift.memory.getObject(message); - swift.memory.release(message); - swift.memory.getObject(self).log(messageObject); + const string = decodeString(messageBytes, messageCount); + swift.memory.getObject(self).log(string); } catch (error) { setException(error); } } - TestModule["bjs_WebSocket_init"] = function bjs_WebSocket_init(url) { + TestModule["bjs_WebSocket_init"] = function bjs_WebSocket_init(urlBytes, urlCount) { try { - const urlObject = swift.memory.getObject(url); - swift.memory.release(url); - return swift.memory.retain(new globalThis.WebSocket(urlObject)); + const string = decodeString(urlBytes, urlCount); + return swift.memory.retain(new globalThis.WebSocket(string)); } catch (error) { setException(error); return 0 @@ -236,6 +230,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 2a2fd3d50..7a97a47ff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -223,6 +220,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index 8b938f75a..cfb0f75e7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -8,6 +8,7 @@ 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; @@ -76,8 +77,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -86,8 +86,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -113,8 +112,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -171,8 +169,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -244,6 +241,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js index eabfe8c13..ca54d8f16 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -276,11 +273,10 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WeirdNaming_normalProperty_set"] = function bjs_WeirdNaming_normalProperty_set(self, newValue) { + TestModule["bjs_WeirdNaming_normalProperty_set"] = function bjs_WeirdNaming_normalProperty_set(self, newValueBytes, newValueCount) { try { - const newValueObject = swift.memory.getObject(newValue); - swift.memory.release(newValue); - swift.memory.getObject(self).normalProperty = newValueObject; + const string = decodeString(newValueBytes, newValueCount); + swift.memory.getObject(self).normalProperty = string; } catch (error) { setException(error); } @@ -299,11 +295,10 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WeirdNaming_property_with_spaces_set"] = function bjs_WeirdNaming_property_with_spaces_set(self, newValue) { + TestModule["bjs_WeirdNaming_property_with_spaces_set"] = function bjs_WeirdNaming_property_with_spaces_set(self, newValueBytes, newValueCount) { try { - const newValueObject = swift.memory.getObject(newValue); - swift.memory.release(newValue); - swift.memory.getObject(self)["property with spaces"] = newValueObject; + const string = decodeString(newValueBytes, newValueCount); + swift.memory.getObject(self)["property with spaces"] = string; } catch (error) { setException(error); } @@ -315,29 +310,26 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WeirdNaming_constructor_set"] = function bjs_WeirdNaming_constructor_set(self, newValue) { + TestModule["bjs_WeirdNaming_constructor_set"] = function bjs_WeirdNaming_constructor_set(self, newValueBytes, newValueCount) { try { - const newValueObject = swift.memory.getObject(newValue); - swift.memory.release(newValue); - swift.memory.getObject(self).constructor = newValueObject; + const string = decodeString(newValueBytes, newValueCount); + swift.memory.getObject(self).constructor = string; } catch (error) { setException(error); } } - TestModule["bjs_WeirdNaming_for_set"] = function bjs_WeirdNaming_for_set(self, newValue) { + TestModule["bjs_WeirdNaming_for_set"] = function bjs_WeirdNaming_for_set(self, newValueBytes, newValueCount) { try { - const newValueObject = swift.memory.getObject(newValue); - swift.memory.release(newValue); - swift.memory.getObject(self).for = newValueObject; + const string = decodeString(newValueBytes, newValueCount); + swift.memory.getObject(self).for = string; } catch (error) { setException(error); } } - TestModule["bjs_WeirdNaming_any_set"] = function bjs_WeirdNaming_any_set(self, newValue) { + TestModule["bjs_WeirdNaming_any_set"] = function bjs_WeirdNaming_any_set(self, newValueBytes, newValueCount) { try { - const newValueObject = swift.memory.getObject(newValue); - swift.memory.release(newValue); - swift.memory.getObject(self).Any = newValueObject; + const string = decodeString(newValueBytes, newValueCount); + swift.memory.getObject(self).Any = string; } catch (error) { setException(error); } @@ -376,6 +368,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js index d84c77d45..7e97170e9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -195,11 +192,10 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_Greeter_init"] = function bjs_Greeter_init(name) { + TestModule["bjs_Greeter_init"] = function bjs_Greeter_init(nameBytes, nameCount) { try { - const nameObject = swift.memory.getObject(name); - swift.memory.release(name); - return swift.memory.retain(new imports.Greeter(nameObject)); + const string = decodeString(nameBytes, nameCount); + return swift.memory.retain(new imports.Greeter(string)); } catch (error) { setException(error); return 0 @@ -223,11 +219,10 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_Greeter_name_set"] = function bjs_Greeter_name_set(self, newValue) { + TestModule["bjs_Greeter_name_set"] = function bjs_Greeter_name_set(self, newValueBytes, newValueCount) { try { - const newValueObject = swift.memory.getObject(newValue); - swift.memory.release(newValue); - swift.memory.getObject(self).name = newValueObject; + const string = decodeString(newValueBytes, newValueCount); + swift.memory.getObject(self).name = string; } catch (error) { setException(error); } @@ -241,11 +236,10 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_Greeter_changeName"] = function bjs_Greeter_changeName(self, name) { + TestModule["bjs_Greeter_changeName"] = function bjs_Greeter_changeName(self, nameBytes, nameCount) { try { - const nameObject = swift.memory.getObject(name); - swift.memory.release(name); - swift.memory.getObject(self).changeName(nameObject); + const string = decodeString(nameBytes, nameCount); + swift.memory.getObject(self).changeName(string); } catch (error) { setException(error); } @@ -273,6 +267,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js index 6912af0f3..39a859e4a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -253,6 +250,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 8571bbd6c..9ed0b93f2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -8,6 +8,7 @@ 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; @@ -127,8 +128,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -137,8 +137,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -164,8 +163,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -215,8 +213,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -324,6 +321,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index dd0e0c55e..1b5651765 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -197,6 +194,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index 523df73cd..840a7a107 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -205,6 +202,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index 4d08957d0..672d5ef7b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -197,6 +194,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index ac55ae750..8401e96b4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -209,6 +206,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 1fb247cbe..9efb38ffa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -209,6 +206,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 941d66ea9..f247c8efc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -198,21 +195,19 @@ export async function createInstantiator(options, swift) { return swift.memory.retain(obj); }; const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; - TestModule["bjs_WithOptionalJSClass_init"] = function bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullObjectId, valueOrUndefinedIsSome, valueOrUndefinedObjectId) { + TestModule["bjs_WithOptionalJSClass_init"] = function bjs_WithOptionalJSClass_init(valueOrNullIsSome, valueOrNullBytes, valueOrNullCount, valueOrUndefinedIsSome, valueOrUndefinedBytes, valueOrUndefinedCount) { try { let optResult; if (valueOrNullIsSome) { - const valueOrNullObjectIdObject = swift.memory.getObject(valueOrNullObjectId); - swift.memory.release(valueOrNullObjectId); - optResult = valueOrNullObjectIdObject; + const string = decodeString(valueOrNullBytes, valueOrNullCount); + optResult = string; } else { optResult = null; } let optResult1; if (valueOrUndefinedIsSome) { - const valueOrUndefinedObjectIdObject = swift.memory.getObject(valueOrUndefinedObjectId); - swift.memory.release(valueOrUndefinedObjectId); - optResult1 = valueOrUndefinedObjectIdObject; + const string1 = decodeString(valueOrUndefinedBytes, valueOrUndefinedCount); + optResult1 = string1; } else { optResult1 = undefined; } @@ -294,13 +289,12 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_stringOrNull_set"] = function bjs_WithOptionalJSClass_stringOrNull_set(self, newValueIsSome, newValueObjectId) { + TestModule["bjs_WithOptionalJSClass_stringOrNull_set"] = function bjs_WithOptionalJSClass_stringOrNull_set(self, newValueIsSome, newValueBytes, newValueCount) { try { let optResult; if (newValueIsSome) { - const newValueObjectIdObject = swift.memory.getObject(newValueObjectId); - swift.memory.release(newValueObjectId); - optResult = newValueObjectIdObject; + const string = decodeString(newValueBytes, newValueCount); + optResult = string; } else { optResult = null; } @@ -309,13 +303,12 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_stringOrUndefined_set"] = function bjs_WithOptionalJSClass_stringOrUndefined_set(self, newValueIsSome, newValueObjectId) { + TestModule["bjs_WithOptionalJSClass_stringOrUndefined_set"] = function bjs_WithOptionalJSClass_stringOrUndefined_set(self, newValueIsSome, newValueBytes, newValueCount) { try { let optResult; if (newValueIsSome) { - const newValueObjectIdObject = swift.memory.getObject(newValueObjectId); - swift.memory.release(newValueObjectId); - optResult = newValueObjectIdObject; + const string = decodeString(newValueBytes, newValueCount); + optResult = string; } else { optResult = undefined; } @@ -366,13 +359,12 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_roundTripStringOrNull"] = function bjs_WithOptionalJSClass_roundTripStringOrNull(self, valueIsSome, valueObjectId) { + TestModule["bjs_WithOptionalJSClass_roundTripStringOrNull"] = function bjs_WithOptionalJSClass_roundTripStringOrNull(self, valueIsSome, valueBytes, valueCount) { try { let optResult; if (valueIsSome) { - const valueObjectIdObject = swift.memory.getObject(valueObjectId); - swift.memory.release(valueObjectId); - optResult = valueObjectIdObject; + const string = decodeString(valueBytes, valueCount); + optResult = string; } else { optResult = null; } @@ -383,13 +375,12 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_roundTripStringOrUndefined"] = function bjs_WithOptionalJSClass_roundTripStringOrUndefined(self, valueIsSome, valueObjectId) { + TestModule["bjs_WithOptionalJSClass_roundTripStringOrUndefined"] = function bjs_WithOptionalJSClass_roundTripStringOrUndefined(self, valueIsSome, valueBytes, valueCount) { try { let optResult; if (valueIsSome) { - const valueObjectIdObject = swift.memory.getObject(valueObjectId); - swift.memory.release(valueObjectId); - optResult = valueObjectIdObject; + const string = decodeString(valueBytes, valueCount); + optResult = string; } else { optResult = undefined; } @@ -459,6 +450,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js index 8999ae8b6..770212417 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -198,6 +195,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js index c8372362d..0efb2d2b5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -209,6 +206,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index dbdd030b6..338e87f9a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -197,6 +194,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 6e95d2ddf..79711d878 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -32,6 +32,7 @@ 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; @@ -94,8 +95,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -104,8 +104,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -131,8 +130,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -182,8 +180,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -291,13 +288,12 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_optionalName_set"] = function bjs_MyViewControllerDelegate_optionalName_set(self, valueIsSome, valueObjectId) { + TestModule["bjs_MyViewControllerDelegate_optionalName_set"] = function bjs_MyViewControllerDelegate_optionalName_set(self, valueIsSome, valueBytes, valueCount) { try { let optResult; if (valueIsSome) { - const valueObjectIdObject = swift.memory.getObject(valueObjectId); - swift.memory.release(valueObjectId); - optResult = valueObjectIdObject; + const string = decodeString(valueBytes, valueCount); + optResult = string; } else { optResult = null; } @@ -314,13 +310,12 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_optionalRawEnum_set"] = function bjs_MyViewControllerDelegate_optionalRawEnum_set(self, valueIsSome, valueObjectId) { + TestModule["bjs_MyViewControllerDelegate_optionalRawEnum_set"] = function bjs_MyViewControllerDelegate_optionalRawEnum_set(self, valueIsSome, valueBytes, valueCount) { try { let optResult; if (valueIsSome) { - const valueObjectIdObject = swift.memory.getObject(valueObjectId); - swift.memory.release(valueObjectId); - optResult = valueObjectIdObject; + const string = decodeString(valueBytes, valueCount); + optResult = string; } else { optResult = null; } @@ -338,11 +333,10 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_rawStringEnum_set"] = function bjs_MyViewControllerDelegate_rawStringEnum_set(self, value) { + TestModule["bjs_MyViewControllerDelegate_rawStringEnum_set"] = function bjs_MyViewControllerDelegate_rawStringEnum_set(self, valueBytes, valueCount) { try { - const valueObject = swift.memory.getObject(value); - swift.memory.release(value); - swift.memory.getObject(self).rawStringEnum = valueObject; + const string = decodeString(valueBytes, valueCount); + swift.memory.getObject(self).rawStringEnum = string; } catch (error) { setException(error); } @@ -462,11 +456,10 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_onValueChanged"] = function bjs_MyViewControllerDelegate_onValueChanged(self, value) { + TestModule["bjs_MyViewControllerDelegate_onValueChanged"] = function bjs_MyViewControllerDelegate_onValueChanged(self, valueBytes, valueCount) { try { - const valueObject = swift.memory.getObject(value); - swift.memory.release(value); - swift.memory.getObject(self).onValueChanged(valueObject); + const string = decodeString(valueBytes, valueCount); + swift.memory.getObject(self).onValueChanged(string); } catch (error) { setException(error); } @@ -480,13 +473,11 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_MyViewControllerDelegate_onLabelUpdated"] = function bjs_MyViewControllerDelegate_onLabelUpdated(self, prefix, suffix) { + TestModule["bjs_MyViewControllerDelegate_onLabelUpdated"] = function bjs_MyViewControllerDelegate_onLabelUpdated(self, prefixBytes, prefixCount, suffixBytes, suffixCount) { try { - const prefixObject = swift.memory.getObject(prefix); - swift.memory.release(prefix); - const suffixObject = swift.memory.getObject(suffix); - swift.memory.release(suffix); - swift.memory.getObject(self).onLabelUpdated(prefixObject, suffixObject); + const string = decodeString(prefixBytes, prefixCount); + const string1 = decodeString(suffixBytes, suffixCount); + swift.memory.getObject(self).onLabelUpdated(string, string1); } catch (error) { setException(error); } @@ -563,6 +554,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 0e8a5a7bb..800b07107 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -19,6 +19,7 @@ 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; @@ -81,8 +82,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -91,8 +91,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -118,8 +117,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -169,8 +167,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -241,6 +238,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 2eea1f12f..a4290f828 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -19,6 +19,7 @@ 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; @@ -81,8 +82,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -91,8 +91,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -118,8 +117,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -169,8 +167,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -241,6 +238,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 16bf8ba0c..056293ff7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -13,6 +13,7 @@ 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; @@ -42,8 +43,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -52,8 +52,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -79,8 +78,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -130,8 +128,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -202,6 +199,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index ea6c448ed..06f032555 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -13,6 +13,7 @@ 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; @@ -42,8 +43,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -52,8 +52,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -79,8 +78,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -130,8 +128,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -202,6 +199,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js index 480f40f92..d602d4e5a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -186,20 +183,18 @@ export async function createInstantiator(options, swift) { } bjs["swift_js_closure_unregister"] = function(funcRef) {} const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; - TestModule["bjs_checkString"] = function bjs_checkString(a) { + TestModule["bjs_checkString"] = function bjs_checkString(aBytes, aCount) { try { - const aObject = swift.memory.getObject(a); - swift.memory.release(a); - imports.checkString(aObject); + const string = decodeString(aBytes, aCount); + imports.checkString(string); } catch (error) { setException(error); } } - TestModule["bjs_checkStringWithLength"] = function bjs_checkStringWithLength(a, b) { + TestModule["bjs_checkStringWithLength"] = function bjs_checkStringWithLength(aBytes, aCount, b) { try { - const aObject = swift.memory.getObject(a); - swift.memory.release(a); - imports.checkStringWithLength(aObject, b); + const string = decodeString(aBytes, aCount); + imports.checkStringWithLength(string, b); } catch (error) { setException(error); } @@ -209,6 +204,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js index 49f07b5ef..b2241d6ca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -200,6 +197,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index a74d49327..9acf70de2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -225,6 +222,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 023a2fab0..09eb39050 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -38,6 +38,7 @@ 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; @@ -153,8 +154,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -163,8 +163,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -190,8 +189,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -241,8 +239,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -327,12 +324,11 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule10HttpStatusO_10HttpStatusO); } - bjs["invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO"] = function(callbackId, param0) { + bjs["invoke_js_callback_TestModule_10TestModule5ThemeO_5ThemeO"] = function(callbackId, param0Bytes, param0Count) { try { const callback = swift.memory.getObject(callbackId); - const param0Object = swift.memory.getObject(param0); - swift.memory.release(param0); - let ret = callback(param0Object); + const string = decodeString(param0Bytes, param0Count); + let ret = callback(string); tmpRetBytes = textEncoder.encode(ret); return tmpRetBytes.length; } catch (error) { @@ -428,12 +424,11 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule9DirectionO_9DirectionO); } - bjs["invoke_js_callback_TestModule_10TestModuleSS_SS"] = function(callbackId, param0) { + bjs["invoke_js_callback_TestModule_10TestModuleSS_SS"] = function(callbackId, param0Bytes, param0Count) { try { const callback = swift.memory.getObject(callbackId); - const param0Object = swift.memory.getObject(param0); - swift.memory.release(param0); - let ret = callback(param0Object); + const string = decodeString(param0Bytes, param0Count); + let ret = callback(string); tmpRetBytes = textEncoder.encode(ret); return tmpRetBytes.length; } catch (error) { @@ -575,14 +570,13 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq10HttpStatusO_Sq10HttpStatusO); } - bjs["invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO"] = function(callbackId, param0IsSome, param0ObjectId) { + bjs["invoke_js_callback_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO"] = function(callbackId, param0IsSome, param0Bytes, param0Count) { try { const callback = swift.memory.getObject(callbackId); let optResult; if (param0IsSome) { - const param0ObjectIdObject = swift.memory.getObject(param0ObjectId); - swift.memory.release(param0ObjectId); - optResult = param0ObjectIdObject; + const string = decodeString(param0Bytes, param0Count); + optResult = string; } else { optResult = null; } @@ -723,14 +717,13 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq9DirectionO_Sq9DirectionO); } - bjs["invoke_js_callback_TestModule_10TestModuleSqSS_SqSS"] = function(callbackId, param0IsSome, param0ObjectId) { + bjs["invoke_js_callback_TestModule_10TestModuleSqSS_SqSS"] = function(callbackId, param0IsSome, param0Bytes, param0Count) { try { const callback = swift.memory.getObject(callbackId); let optResult; if (param0IsSome) { - const param0ObjectIdObject = swift.memory.getObject(param0ObjectId); - swift.memory.release(param0ObjectId); - optResult = param0ObjectIdObject; + const string = decodeString(param0Bytes, param0Count); + optResult = string; } else { optResult = null; } @@ -888,6 +881,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index b5efd2150..21e382395 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -8,6 +8,7 @@ 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; @@ -63,8 +64,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -73,8 +73,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -100,8 +99,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -151,8 +149,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -264,6 +261,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index 617bda36b..cd2d396df 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -13,6 +13,7 @@ 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; @@ -227,8 +228,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -237,8 +237,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -264,8 +263,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -364,8 +362,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -436,6 +433,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index d00b7450d..cb161707a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -8,6 +8,7 @@ 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; @@ -49,8 +50,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -59,8 +59,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -86,8 +85,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -144,8 +142,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -219,6 +216,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js index 2c415fc31..ae9625f00 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js @@ -8,6 +8,7 @@ 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; @@ -37,8 +38,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -47,8 +47,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -74,8 +73,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -125,8 +123,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -189,6 +186,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index c141a7926..169b001cf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -8,6 +8,7 @@ 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; @@ -54,8 +55,7 @@ export async function createInstantiator(options, swift) { bjs = {}; importObject["bjs"] = bjs; bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -64,8 +64,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -91,8 +90,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -149,8 +147,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -213,6 +210,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js index f8737237e..cc6c0359b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js @@ -8,6 +8,7 @@ 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; @@ -38,8 +39,7 @@ export async function createInstantiator(options, swift) { importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { const source = swift.memory.getObject(sourceId); @@ -48,8 +48,7 @@ export async function createInstantiator(options, swift) { bytes.set(source); } bjs["swift_js_make_js_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - return swift.memory.retain(textDecoder.decode(bytes)); + return swift.memory.retain(decodeString(ptr, len)); } bjs["swift_js_init_memory_with_result"] = function(ptr, len) { const target = new Uint8Array(memory.buffer, ptr, len); @@ -75,8 +74,7 @@ export async function createInstantiator(options, swift) { f64Stack.push(v); } bjs["swift_js_push_string"] = function(ptr, len) { - const bytes = new Uint8Array(memory.buffer, ptr, len); - const value = textDecoder.decode(bytes); + const value = decodeString(ptr, len); strStack.push(value); } bjs["swift_js_pop_i32"] = function() { @@ -126,8 +124,7 @@ export async function createInstantiator(options, swift) { if (isSome === 0) { tmpRetString = null; } else { - const bytes = new Uint8Array(memory.buffer, ptr, len); - tmpRetString = textDecoder.decode(bytes); + tmpRetString = decodeString(ptr, len); } } bjs["swift_js_return_optional_object"] = function(isSome, objectId) { @@ -198,6 +195,8 @@ export async function createInstantiator(options, swift) { 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) } diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index c0de9413e..f2b2b6c34 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -348,9 +348,9 @@ extension String: _BridgedSwiftStackType { // MARK: ImportTS - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + @_spi(BridgeJS) public consuming func bridgeJSWithLoweredParameter(_ body: (Int32, Int32) -> T) -> T { return self.withUTF8 { b in - _swift_js_make_js_string(b.baseAddress.unsafelyUnwrapped, Int32(b.count)) + body(Int32(bitPattern: UInt32(UInt(bitPattern: b.baseAddress))), Int32(b.count)) } } @@ -737,7 +737,9 @@ extension _BridgedSwiftStruct { extension _BridgedSwiftEnumNoPayload where Self: RawRepresentable, RawValue == String { // MARK: ImportTS - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { rawValue.bridgeJSLowerParameter() } + @_spi(BridgeJS) public consuming func bridgeJSWithLoweredParameter(_ body: (Int32, Int32) -> T) -> T { + rawValue.bridgeJSWithLoweredParameter(body) + } @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ id: Int32) -> Self { Self(rawValue: .bridgeJSLiftReturn(id))! @@ -1507,10 +1509,17 @@ extension _BridgedAsOptional where Wrapped == Bool { } extension _BridgedAsOptional where Wrapped == String { - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> ( - isSome: Int32, value: Int32 - ) { - asOptional._bridgeJSLowerParameter(noneValue: 0, lowerWrapped: { $0.bridgeJSLowerParameter() }) + @_spi(BridgeJS) @_transparent public consuming func bridgeJSWithLoweredParameter( + _ body: (Int32, Int32, Int32) -> T + ) -> T { + switch asOptional { + case .none: + return body(0, 0, 0) + case .some(let value): + return value.bridgeJSWithLoweredParameter { bytes, count in + return body(1, bytes, count) + } + } } @_spi(BridgeJS) public static func bridgeJSLiftParameter( @@ -1683,14 +1692,16 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftCaseEnum { extension _BridgedAsOptional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == String { - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> ( - isSome: Int32, value: Int32 - ) { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSWithLoweredParameter( + _ body: (Int32, Int32, Int32) -> T + ) -> T { switch asOptional { case .none: - return (isSome: 0, value: 0) + return body(0, 0, 0) case .some(let wrapped): - return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) + return wrapped.bridgeJSWithLoweredParameter { bytes, count in + return body(1, bytes, count) + } } } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 07c065be1..13aab1455 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -72,14 +72,14 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests10H #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS(_ callback: Int32, _ param0: Int32) -> Int32 { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(callback, param0Bytes, param0Length) } #if arch(wasm32) @@ -100,8 +100,11 @@ private enum _BJS_Closure_20BridgeJSRuntimeTests5ThemeO_SS { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let param0Value = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS(callbackValue, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 return String.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -135,14 +138,14 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5Th #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb_extern(_ callback: Int32, _ param0: Int32) -> Int32 +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb_extern(_ callback: Int32, _ param0: Int32) -> Int32 { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb(_ callback: Int32, _ param0: Int32) -> Int32 { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb_extern(callback, param0Bytes, param0Length) } #if arch(wasm32) @@ -163,8 +166,11 @@ private enum _BJS_Closure_20BridgeJSRuntimeTests5ThemeO_Sb { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let param0Value = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb(callbackValue, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_Sb(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 return Bool.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -513,14 +519,14 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests9Di #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC_extern(_ callback: Int32, _ param0: Int32) -> UnsafeMutableRawPointer +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> UnsafeMutableRawPointer #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC_extern(_ callback: Int32, _ param0: Int32) -> UnsafeMutableRawPointer { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> UnsafeMutableRawPointer { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC(_ callback: Int32, _ param0: Int32) -> UnsafeMutableRawPointer { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> UnsafeMutableRawPointer { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC_extern(callback, param0Bytes, param0Length) } #if arch(wasm32) @@ -541,8 +547,11 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSS_7GreeterC { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let param0Value = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC(callbackValue, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 return Greeter.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -576,14 +585,14 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_ #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS(_ callback: Int32, _ param0: Int32) -> Int32 { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS_extern(callback, param0Bytes, param0Length) } #if arch(wasm32) @@ -604,8 +613,11 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSS_SS { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let param0Value = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS(callbackValue, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 return String.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -702,14 +714,14 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_ #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS_extern(_ callback: Int32, _ param0: Int32, _ param1: Int32, _ param2: Float64) -> Int32 +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS_extern(_ callback: Int32, _ param0: Int32, _ param1Bytes: Int32, _ param1Length: Int32, _ param2: Float64) -> Int32 #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS_extern(_ callback: Int32, _ param0: Int32, _ param1: Int32, _ param2: Float64) -> Int32 { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS_extern(_ callback: Int32, _ param0: Int32, _ param1Bytes: Int32, _ param1Length: Int32, _ param2: Float64) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS(_ callback: Int32, _ param0: Int32, _ param1: Int32, _ param2: Float64) -> Int32 { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS_extern(callback, param0, param1, param2) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS(_ callback: Int32, _ param0: Int32, _ param1Bytes: Int32, _ param1Length: Int32, _ param2: Float64) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS_extern(callback, param0, param1Bytes, param1Length, param2) } #if arch(wasm32) @@ -731,9 +743,12 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSiSSSd_SS { #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() let param0Value = param0.bridgeJSLowerParameter() - let param1Value = param1.bridgeJSLowerParameter() - let param2Value = param2.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS(callbackValue, param0Value, param1Value, param2Value) + let ret0 = param1.bridgeJSWithLoweredParameter { (param1Bytes, param1Length) in + let param2Value = param2.bridgeJSLowerParameter() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS(callbackValue, param0Value, param1Bytes, param1Length, param2Value) + return ret + } + let ret = ret0 return String.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -1020,14 +1035,14 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSi_ #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(callback, param0IsSome, param0Value) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(callback, param0IsSome, param0Bytes, param0Length) } #if arch(wasm32) @@ -1048,8 +1063,11 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSq5ThemeO_SS { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let (param0IsSome, param0Value) = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS(callbackValue, param0IsSome, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0IsSome, param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS(callbackValue, param0IsSome, param0Bytes, param0Length) + return ret + } + let ret = ret0 return String.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -1335,14 +1353,14 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq9 #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(callback, param0IsSome, param0Value) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(callback, param0IsSome, param0Bytes, param0Length) } #if arch(wasm32) @@ -1363,8 +1381,11 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSqSS_SS { return { [callback] param0 in #if arch(wasm32) let callbackValue = callback.bridgeJSLowerParameter() - let (param0IsSome, param0Value) = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(callbackValue, param0IsSome, param0Value) + let ret0 = param0.bridgeJSWithLoweredParameter { (param0IsSome, param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(callbackValue, param0IsSome, param0Bytes, param0Length) + return ret + } + let ret = ret0 return String.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -1705,9 +1726,11 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) -> Void { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let labelPrefixValue = labelPrefix.bridgeJSLowerParameter() - let labelSuffixValue = labelSuffix.bridgeJSLowerParameter() - _extern_setLabelElements(jsObjectValue, labelPrefixValue, labelSuffixValue) + labelPrefix.bridgeJSWithLoweredParameter { (labelPrefixBytes, labelPrefixLength) in + labelSuffix.bridgeJSWithLoweredParameter { (labelSuffixBytes, labelSuffixLength) in + _extern_setLabelElements(jsObjectValue, labelPrefixBytes, labelPrefixLength, labelSuffixBytes, labelSuffixLength) + } + } } func getLabel() -> String { @@ -1789,8 +1812,9 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { } set { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() - bjs_DataProcessor_optionalTag_set(jsObjectValue, newValueIsSome, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueIsSome, newValueBytes, newValueLength) in + bjs_DataProcessor_optionalTag_set(jsObjectValue, newValueIsSome, newValueBytes, newValueLength) + } } } @@ -1828,8 +1852,9 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { } set { let jsObjectValue = jsObject.bridgeJSLowerParameter() - let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() - bjs_DataProcessor_optionalTheme_set(jsObjectValue, newValueIsSome, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueIsSome, newValueBytes, newValueLength) in + bjs_DataProcessor_optionalTheme_set(jsObjectValue, newValueIsSome, newValueBytes, newValueLength) + } } } @@ -1916,14 +1941,14 @@ fileprivate func _extern_getValue_extern(_ jsObject: Int32) -> Int32 { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_setLabelElements") -fileprivate func _extern_setLabelElements_extern(_ jsObject: Int32, _ labelPrefix: Int32, _ labelSuffix: Int32) -> Void +fileprivate func _extern_setLabelElements_extern(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void #else -fileprivate func _extern_setLabelElements_extern(_ jsObject: Int32, _ labelPrefix: Int32, _ labelSuffix: Int32) -> Void { +fileprivate func _extern_setLabelElements_extern(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func _extern_setLabelElements(_ jsObject: Int32, _ labelPrefix: Int32, _ labelSuffix: Int32) -> Void { - return _extern_setLabelElements_extern(jsObject, labelPrefix, labelSuffix) +@inline(never) fileprivate func _extern_setLabelElements(_ jsObject: Int32, _ labelPrefixBytes: Int32, _ labelPrefixLength: Int32, _ labelSuffixBytes: Int32, _ labelSuffixLength: Int32) -> Void { + return _extern_setLabelElements_extern(jsObject, labelPrefixBytes, labelPrefixLength, labelSuffixBytes, labelSuffixLength) } #if arch(wasm32) @@ -2072,14 +2097,14 @@ fileprivate func bjs_DataProcessor_optionalTag_get_extern(_ jsObject: Int32) -> #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTag_set") -fileprivate func bjs_DataProcessor_optionalTag_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +fileprivate func bjs_DataProcessor_optionalTag_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_DataProcessor_optionalTag_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { +fileprivate func bjs_DataProcessor_optionalTag_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_DataProcessor_optionalTag_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { - return bjs_DataProcessor_optionalTag_set_extern(jsObject, newValueIsSome, newValueValue) +@inline(never) fileprivate func bjs_DataProcessor_optionalTag_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_DataProcessor_optionalTag_set_extern(jsObject, newValueIsSome, newValueBytes, newValueLength) } #if arch(wasm32) @@ -2144,14 +2169,14 @@ fileprivate func bjs_DataProcessor_optionalTheme_get_extern(_ jsObject: Int32) - #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTheme_set") -fileprivate func bjs_DataProcessor_optionalTheme_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +fileprivate func bjs_DataProcessor_optionalTheme_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_DataProcessor_optionalTheme_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { +fileprivate func bjs_DataProcessor_optionalTheme_set_extern(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_DataProcessor_optionalTheme_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { - return bjs_DataProcessor_optionalTheme_set_extern(jsObject, newValueIsSome, newValueValue) +@inline(never) fileprivate func bjs_DataProcessor_optionalTheme_set(_ jsObject: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_DataProcessor_optionalTheme_set_extern(jsObject, newValueIsSome, newValueBytes, newValueLength) } #if arch(wasm32) @@ -9223,14 +9248,14 @@ fileprivate func _bjs_LeakCheck_wrap_extern(_ pointer: UnsafeMutableRawPointer) #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ArrayElementObject_init") -fileprivate func bjs_ArrayElementObject_init_extern(_ id: Int32) -> Int32 +fileprivate func bjs_ArrayElementObject_init_extern(_ idBytes: Int32, _ idLength: Int32) -> Int32 #else -fileprivate func bjs_ArrayElementObject_init_extern(_ id: Int32) -> Int32 { +fileprivate func bjs_ArrayElementObject_init_extern(_ idBytes: Int32, _ idLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_ArrayElementObject_init(_ id: Int32) -> Int32 { - return bjs_ArrayElementObject_init_extern(id) +@inline(never) fileprivate func bjs_ArrayElementObject_init(_ idBytes: Int32, _ idLength: Int32) -> Int32 { + return bjs_ArrayElementObject_init_extern(idBytes, idLength) } #if arch(wasm32) @@ -9246,8 +9271,11 @@ fileprivate func bjs_ArrayElementObject_id_get_extern(_ self: Int32) -> Int32 { } func _$ArrayElementObject_init(_ id: String) throws(JSException) -> JSObject { - let idValue = id.bridgeJSLowerParameter() - let ret = bjs_ArrayElementObject_init(idValue) + let ret0 = id.bridgeJSWithLoweredParameter { (idBytes, idLength) in + let ret = bjs_ArrayElementObject_init(idBytes, idLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -9667,14 +9695,14 @@ fileprivate func bjs_ClosureSupportImports_jsApplyDouble_static_extern(_ value: #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ClosureSupportImports_jsApplyString_static") -fileprivate func bjs_ClosureSupportImports_jsApplyString_static_extern(_ value: Int32, _ transform: Int32) -> Int32 +fileprivate func bjs_ClosureSupportImports_jsApplyString_static_extern(_ valueBytes: Int32, _ valueLength: Int32, _ transform: Int32) -> Int32 #else -fileprivate func bjs_ClosureSupportImports_jsApplyString_static_extern(_ value: Int32, _ transform: Int32) -> Int32 { +fileprivate func bjs_ClosureSupportImports_jsApplyString_static_extern(_ valueBytes: Int32, _ valueLength: Int32, _ transform: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_ClosureSupportImports_jsApplyString_static(_ value: Int32, _ transform: Int32) -> Int32 { - return bjs_ClosureSupportImports_jsApplyString_static_extern(value, transform) +@inline(never) fileprivate func bjs_ClosureSupportImports_jsApplyString_static(_ valueBytes: Int32, _ valueLength: Int32, _ transform: Int32) -> Int32 { + return bjs_ClosureSupportImports_jsApplyString_static_extern(valueBytes, valueLength, transform) } #if arch(wasm32) @@ -9715,14 +9743,14 @@ fileprivate func bjs_ClosureSupportImports_jsMakeDoubleToDouble_static_extern(_ #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ClosureSupportImports_jsMakeStringToString_static") -fileprivate func bjs_ClosureSupportImports_jsMakeStringToString_static_extern(_ prefix: Int32) -> Int32 +fileprivate func bjs_ClosureSupportImports_jsMakeStringToString_static_extern(_ prefixBytes: Int32, _ prefixLength: Int32) -> Int32 #else -fileprivate func bjs_ClosureSupportImports_jsMakeStringToString_static_extern(_ prefix: Int32) -> Int32 { +fileprivate func bjs_ClosureSupportImports_jsMakeStringToString_static_extern(_ prefixBytes: Int32, _ prefixLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_ClosureSupportImports_jsMakeStringToString_static(_ prefix: Int32) -> Int32 { - return bjs_ClosureSupportImports_jsMakeStringToString_static_extern(prefix) +@inline(never) fileprivate func bjs_ClosureSupportImports_jsMakeStringToString_static(_ prefixBytes: Int32, _ prefixLength: Int32) -> Int32 { + return bjs_ClosureSupportImports_jsMakeStringToString_static_extern(prefixBytes, prefixLength) } #if arch(wasm32) @@ -9871,9 +9899,12 @@ func _$ClosureSupportImports_jsApplyDouble(_ value: Double, _ transform: JSTyped } func _$ClosureSupportImports_jsApplyString(_ value: String, _ transform: JSTypedClosure<(String) -> String>) throws(JSException) -> String { - let valueValue = value.bridgeJSLowerParameter() - let transformFuncRef = transform.bridgeJSLowerParameter() - let ret = bjs_ClosureSupportImports_jsApplyString_static(valueValue, transformFuncRef) + let ret0 = value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + let transformFuncRef = transform.bridgeJSLowerParameter() + let ret = bjs_ClosureSupportImports_jsApplyString_static(valueBytes, valueLength, transformFuncRef) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -9909,8 +9940,11 @@ func _$ClosureSupportImports_jsMakeDoubleToDouble(_ base: Double) throws(JSExcep } func _$ClosureSupportImports_jsMakeStringToString(_ prefix: String) throws(JSException) -> (String) -> String { - let prefixValue = prefix.bridgeJSLowerParameter() - let ret = bjs_ClosureSupportImports_jsMakeStringToString_static(prefixValue) + let ret0 = prefix.bridgeJSWithLoweredParameter { (prefixBytes, prefixLength) in + let ret = bjs_ClosureSupportImports_jsMakeStringToString_static(prefixBytes, prefixLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -10140,14 +10174,14 @@ func _$DictionarySupportImports_jsRoundTripDictionaryDoubleArray(_ values: [Stri #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Foo_init") -fileprivate func bjs_Foo_init_extern(_ value: Int32) -> Int32 +fileprivate func bjs_Foo_init_extern(_ valueBytes: Int32, _ valueLength: Int32) -> Int32 #else -fileprivate func bjs_Foo_init_extern(_ value: Int32) -> Int32 { +fileprivate func bjs_Foo_init_extern(_ valueBytes: Int32, _ valueLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_Foo_init(_ value: Int32) -> Int32 { - return bjs_Foo_init_extern(value) +@inline(never) fileprivate func bjs_Foo_init(_ valueBytes: Int32, _ valueLength: Int32) -> Int32 { + return bjs_Foo_init_extern(valueBytes, valueLength) } #if arch(wasm32) @@ -10163,8 +10197,11 @@ fileprivate func bjs_Foo_value_get_extern(_ self: Int32) -> Int32 { } func _$Foo_init(_ value: String) throws(JSException) -> JSObject { - let valueValue = value.bridgeJSLowerParameter() - let ret = bjs_Foo_init(valueValue) + let ret0 = value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + let ret = bjs_Foo_init(valueBytes, valueLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -10263,19 +10300,22 @@ func _$jsRoundTripBool(_ v: Bool) throws(JSException) -> Bool { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripString") -fileprivate func bjs_jsRoundTripString_extern(_ v: Int32) -> Int32 +fileprivate func bjs_jsRoundTripString_extern(_ vBytes: Int32, _ vLength: Int32) -> Int32 #else -fileprivate func bjs_jsRoundTripString_extern(_ v: Int32) -> Int32 { +fileprivate func bjs_jsRoundTripString_extern(_ vBytes: Int32, _ vLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_jsRoundTripString(_ v: Int32) -> Int32 { - return bjs_jsRoundTripString_extern(v) +@inline(never) fileprivate func bjs_jsRoundTripString(_ vBytes: Int32, _ vLength: Int32) -> Int32 { + return bjs_jsRoundTripString_extern(vBytes, vLength) } func _$jsRoundTripString(_ v: String) throws(JSException) -> String { - let vValue = v.bridgeJSLowerParameter() - let ret = bjs_jsRoundTripString(vValue) + let ret0 = v.bridgeJSWithLoweredParameter { (vBytes, vLength) in + let ret = bjs_jsRoundTripString(vBytes, vLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -10388,19 +10428,22 @@ func _$jsThrowOrString(_ shouldThrow: Bool) throws(JSException) -> String { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripFeatureFlag") -fileprivate func bjs_jsRoundTripFeatureFlag_extern(_ flag: Int32) -> Int32 +fileprivate func bjs_jsRoundTripFeatureFlag_extern(_ flagBytes: Int32, _ flagLength: Int32) -> Int32 #else -fileprivate func bjs_jsRoundTripFeatureFlag_extern(_ flag: Int32) -> Int32 { +fileprivate func bjs_jsRoundTripFeatureFlag_extern(_ flagBytes: Int32, _ flagLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_jsRoundTripFeatureFlag(_ flag: Int32) -> Int32 { - return bjs_jsRoundTripFeatureFlag_extern(flag) +@inline(never) fileprivate func bjs_jsRoundTripFeatureFlag(_ flagBytes: Int32, _ flagLength: Int32) -> Int32 { + return bjs_jsRoundTripFeatureFlag_extern(flagBytes, flagLength) } func _$jsRoundTripFeatureFlag(_ flag: FeatureFlag) throws(JSException) -> FeatureFlag { - let flagValue = flag.bridgeJSLowerParameter() - let ret = bjs_jsRoundTripFeatureFlag(flagValue) + let ret0 = flag.bridgeJSWithLoweredParameter { (flagBytes, flagLength) in + let ret = bjs_jsRoundTripFeatureFlag(flagBytes, flagLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -10449,19 +10492,22 @@ func _$_jsWeirdFunction() throws(JSException) -> Double { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_parseInt") -fileprivate func bjs_parseInt_extern(_ string: Int32) -> Float64 +fileprivate func bjs_parseInt_extern(_ stringBytes: Int32, _ stringLength: Int32) -> Float64 #else -fileprivate func bjs_parseInt_extern(_ string: Int32) -> Float64 { +fileprivate func bjs_parseInt_extern(_ stringBytes: Int32, _ stringLength: Int32) -> Float64 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_parseInt(_ string: Int32) -> Float64 { - return bjs_parseInt_extern(string) +@inline(never) fileprivate func bjs_parseInt(_ stringBytes: Int32, _ stringLength: Int32) -> Float64 { + return bjs_parseInt_extern(stringBytes, stringLength) } func _$parseInt(_ string: String) throws(JSException) -> Double { - let stringValue = string.bridgeJSLowerParameter() - let ret = bjs_parseInt(stringValue) + let ret0 = string.bridgeJSWithLoweredParameter { (stringBytes, stringLength) in + let ret = bjs_parseInt(stringBytes, stringLength) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -10470,14 +10516,14 @@ func _$parseInt(_ string: String) throws(JSException) -> Double { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JsGreeter_init") -fileprivate func bjs_JsGreeter_init_extern(_ name: Int32, _ prefix: Int32) -> Int32 +fileprivate func bjs_JsGreeter_init_extern(_ nameBytes: Int32, _ nameLength: Int32, _ prefixBytes: Int32, _ prefixLength: Int32) -> Int32 #else -fileprivate func bjs_JsGreeter_init_extern(_ name: Int32, _ prefix: Int32) -> Int32 { +fileprivate func bjs_JsGreeter_init_extern(_ nameBytes: Int32, _ nameLength: Int32, _ prefixBytes: Int32, _ prefixLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_JsGreeter_init(_ name: Int32, _ prefix: Int32) -> Int32 { - return bjs_JsGreeter_init_extern(name, prefix) +@inline(never) fileprivate func bjs_JsGreeter_init(_ nameBytes: Int32, _ nameLength: Int32, _ prefixBytes: Int32, _ prefixLength: Int32) -> Int32 { + return bjs_JsGreeter_init_extern(nameBytes, nameLength, prefixBytes, prefixLength) } #if arch(wasm32) @@ -10506,14 +10552,14 @@ fileprivate func bjs_JsGreeter_prefix_get_extern(_ self: Int32) -> Int32 { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JsGreeter_name_set") -fileprivate func bjs_JsGreeter_name_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_JsGreeter_name_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_JsGreeter_name_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_JsGreeter_name_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_JsGreeter_name_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_JsGreeter_name_set_extern(self, newValue) +@inline(never) fileprivate func bjs_JsGreeter_name_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_JsGreeter_name_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @@ -10530,20 +10576,25 @@ fileprivate func bjs_JsGreeter_greet_extern(_ self: Int32) -> Int32 { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JsGreeter_changeName") -fileprivate func bjs_JsGreeter_changeName_extern(_ self: Int32, _ name: Int32) -> Void +fileprivate func bjs_JsGreeter_changeName_extern(_ self: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void #else -fileprivate func bjs_JsGreeter_changeName_extern(_ self: Int32, _ name: Int32) -> Void { +fileprivate func bjs_JsGreeter_changeName_extern(_ self: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_JsGreeter_changeName(_ self: Int32, _ name: Int32) -> Void { - return bjs_JsGreeter_changeName_extern(self, name) +@inline(never) fileprivate func bjs_JsGreeter_changeName(_ self: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { + return bjs_JsGreeter_changeName_extern(self, nameBytes, nameLength) } func _$JsGreeter_init(_ name: String, _ prefix: String) throws(JSException) -> JSObject { - let nameValue = name.bridgeJSLowerParameter() - let prefixValue = prefix.bridgeJSLowerParameter() - let ret = bjs_JsGreeter_init(nameValue, prefixValue) + let ret0 = name.bridgeJSWithLoweredParameter { (nameBytes, nameLength) in + let ret1 = prefix.bridgeJSWithLoweredParameter { (prefixBytes, prefixLength) in + let ret = bjs_JsGreeter_init(nameBytes, nameLength, prefixBytes, prefixLength) + return ret + } + return ret1 + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -10570,8 +10621,9 @@ func _$JsGreeter_prefix_get(_ self: JSObject) throws(JSException) -> String { func _$JsGreeter_name_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_JsGreeter_name_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_JsGreeter_name_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -10588,8 +10640,9 @@ func _$JsGreeter_greet(_ self: JSObject) throws(JSException) -> String { func _$JsGreeter_changeName(_ self: JSObject, _ name: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let nameValue = name.bridgeJSLowerParameter() - bjs_JsGreeter_changeName(selfValue, nameValue) + name.bridgeJSWithLoweredParameter { (nameBytes, nameLength) in + bjs_JsGreeter_changeName(selfValue, nameBytes, nameLength) + } if let error = _swift_js_take_exception() { throw error } @@ -10761,14 +10814,14 @@ func _$StaticBox_value(_ self: JSObject) throws(JSException) -> Double { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Animal_init") -fileprivate func bjs_Animal_init_extern(_ name: Int32, _ age: Float64, _ isCat: Int32) -> Int32 +fileprivate func bjs_Animal_init_extern(_ nameBytes: Int32, _ nameLength: Int32, _ age: Float64, _ isCat: Int32) -> Int32 #else -fileprivate func bjs_Animal_init_extern(_ name: Int32, _ age: Float64, _ isCat: Int32) -> Int32 { +fileprivate func bjs_Animal_init_extern(_ nameBytes: Int32, _ nameLength: Int32, _ age: Float64, _ isCat: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_Animal_init(_ name: Int32, _ age: Float64, _ isCat: Int32) -> Int32 { - return bjs_Animal_init_extern(name, age, isCat) +@inline(never) fileprivate func bjs_Animal_init(_ nameBytes: Int32, _ nameLength: Int32, _ age: Float64, _ isCat: Int32) -> Int32 { + return bjs_Animal_init_extern(nameBytes, nameLength, age, isCat) } #if arch(wasm32) @@ -10809,14 +10862,14 @@ fileprivate func bjs_Animal_isCat_get_extern(_ self: Int32) -> Int32 { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Animal_name_set") -fileprivate func bjs_Animal_name_set_extern(_ self: Int32, _ newValue: Int32) -> Void +fileprivate func bjs_Animal_name_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void #else -fileprivate func bjs_Animal_name_set_extern(_ self: Int32, _ newValue: Int32) -> Void { +fileprivate func bjs_Animal_name_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_Animal_name_set(_ self: Int32, _ newValue: Int32) -> Void { - return bjs_Animal_name_set_extern(self, newValue) +@inline(never) fileprivate func bjs_Animal_name_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_Animal_name_set_extern(self, newValueBytes, newValueLength) } #if arch(wasm32) @@ -10868,10 +10921,13 @@ fileprivate func bjs_Animal_getIsCat_extern(_ self: Int32) -> Int32 { } func _$Animal_init(_ name: String, _ age: Double, _ isCat: Bool) throws(JSException) -> JSObject { - let nameValue = name.bridgeJSLowerParameter() - let ageValue = age.bridgeJSLowerParameter() - let isCatValue = isCat.bridgeJSLowerParameter() - let ret = bjs_Animal_init(nameValue, ageValue, isCatValue) + let ret0 = name.bridgeJSWithLoweredParameter { (nameBytes, nameLength) in + let ageValue = age.bridgeJSLowerParameter() + let isCatValue = isCat.bridgeJSLowerParameter() + let ret = bjs_Animal_init(nameBytes, nameLength, ageValue, isCatValue) + return ret + } + let ret = ret0 if let error = _swift_js_take_exception() { throw error } @@ -10907,8 +10963,9 @@ func _$Animal_isCat_get(_ self: JSObject) throws(JSException) -> Bool { func _$Animal_name_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() - let newValueValue = newValue.bridgeJSLowerParameter() - bjs_Animal_name_set(selfValue, newValueValue) + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_Animal_name_set(selfValue, newValueBytes, newValueLength) + } if let error = _swift_js_take_exception() { throw error } @@ -11348,26 +11405,26 @@ fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalNumberUndefined_s #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static") -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static_extern(_ nameIsSome: Int32, _ nameValue: Int32) -> Void +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static_extern(_ nameIsSome: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void #else -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static_extern(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static_extern(_ nameIsSome: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { - return bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static_extern(nameIsSome, nameValue) +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static(_ nameIsSome: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static_extern(nameIsSome, nameBytes, nameLength) } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static") -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static_extern(_ nameIsSome: Int32, _ nameValue: Int32) -> Void +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static_extern(_ nameIsSome: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void #else -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static_extern(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static_extern(_ nameIsSome: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static(_ nameIsSome: Int32, _ nameValue: Int32) -> Void { - return bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static_extern(nameIsSome, nameValue) +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static(_ nameIsSome: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static_extern(nameIsSome, nameBytes, nameLength) } #if arch(wasm32) @@ -11449,8 +11506,9 @@ func _$OptionalSupportImports_jsRoundTripOptionalNumberUndefined(_ value: JSUnde } func _$OptionalSupportImports_jsRoundTripOptionalStringNull(_ name: Optional) throws(JSException) -> Optional { - let (nameIsSome, nameValue) = name.bridgeJSLowerParameter() - bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static(nameIsSome, nameValue) + name.bridgeJSWithLoweredParameter { (nameIsSome, nameBytes, nameLength) in + bjs_OptionalSupportImports_jsRoundTripOptionalStringNull_static(nameIsSome, nameBytes, nameLength) + } if let error = _swift_js_take_exception() { throw error } @@ -11458,8 +11516,9 @@ func _$OptionalSupportImports_jsRoundTripOptionalStringNull(_ name: Optional) throws(JSException) -> JSUndefinedOr { - let (nameIsSome, nameValue) = name.bridgeJSLowerParameter() - bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static(nameIsSome, nameValue) + name.bridgeJSWithLoweredParameter { (nameIsSome, nameBytes, nameLength) in + bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_static(nameIsSome, nameBytes, nameLength) + } if let error = _swift_js_take_exception() { throw error } From 40fa074ba407857c98b5fd7ef97fe6f1f235e04a Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 5 Mar 2026 22:01:18 +0800 Subject: [PATCH 05/68] BridgeJS: Include properties and release() in declare global class stubs --- .../BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift | 10 ++++++++++ .../BridgeJSLinkTests/EnumNamespace.Global.d.ts | 5 +++++ .../__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts | 1 + .../BridgeJSLinkTests/Namespaces.Global.d.ts | 4 ++++ 4 files changed, 20 insertions(+) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index af2456f81..fd907e8db 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -2947,6 +2947,16 @@ extension BridgeJSLink { "\(method.name)\(renderTSSignatureCallback(method.parameters, method.returnType, method.effects));" printer.write(methodSignature) } + + let sortedProperties = klass.properties.filter { !$0.isStatic }.sorted { + $0.name < $1.name + } + for property in sortedProperties { + let readonly = property.isReadonly ? "readonly " : "" + printer.write("\(readonly)\(property.name): \(property.type.tsType);") + } + + printer.write("release(): void;") } printer.write("}") } 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 936ae6b3a..b78f0cecd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.d.ts @@ -34,6 +34,7 @@ declare global { class Converter { constructor(); format(value: number): string; + release(): void; } } namespace Networking { @@ -41,6 +42,7 @@ declare global { class HTTPServer { constructor(); call(method: Networking.API.MethodTag): void; + release(): void; } const MethodValues: { readonly Get: 0; @@ -55,6 +57,7 @@ declare global { class TestServer { constructor(); call(method: Networking.APIV2.Internal.SupportedMethodTag): void; + release(): void; } const SupportedMethodValues: { readonly Get: 0; @@ -77,6 +80,8 @@ declare global { class Converter { constructor(); toString(value: number): string; + precision: number; + release(): void; } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts index 6f18e53ed..88485232e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.d.ts @@ -11,6 +11,7 @@ declare global { class GlobalClass { constructor(); greet(): string; + release(): void; } function globalFunction(): string; } 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 25ac1ac6d..4b7851c3e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts @@ -12,6 +12,7 @@ declare global { constructor(); addItem(item: Greeter): void; getItems(): Greeter[]; + release(): void; } } namespace MyModule { @@ -24,6 +25,7 @@ declare global { class Converter { constructor(); toString(value: number): string; + release(): void; } } } @@ -32,9 +34,11 @@ declare global { class Greeter { constructor(name: string); greet(): string; + release(): void; } class UUID { uuidString(): string; + release(): void; } } } From 757f2a07ee434f59466b856ee4d1a72b1f66e40f Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 5 Mar 2026 22:21:34 +0800 Subject: [PATCH 06/68] BridgeJS: Add E2E test for instance property access via globalThis --- .../Generated/BridgeJS.swift | 21 +++++++++++++++++++ .../Generated/JavaScript/BridgeJS.json | 12 +++++++++++ .../BridgeJSGlobalTests/GlobalAPITests.swift | 2 ++ Tests/prelude.mjs | 3 +++ 4 files changed, 38 insertions(+) diff --git a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift index ca9968838..a892720ce 100644 --- a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift @@ -296,6 +296,27 @@ public func _bjs_GlobalUtils_PublicConverter_toString(_ _self: UnsafeMutableRawP #endif } +@_expose(wasm, "bjs_GlobalUtils_PublicConverter_precision_get") +@_cdecl("bjs_GlobalUtils_PublicConverter_precision_get") +public func _bjs_GlobalUtils_PublicConverter_precision_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = GlobalUtils.PublicConverter.bridgeJSLiftParameter(_self).precision + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_GlobalUtils_PublicConverter_precision_set") +@_cdecl("bjs_GlobalUtils_PublicConverter_precision_set") +public func _bjs_GlobalUtils_PublicConverter_precision_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + GlobalUtils.PublicConverter.bridgeJSLiftParameter(_self).precision = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_GlobalUtils_PublicConverter_deinit") @_cdecl("bjs_GlobalUtils_PublicConverter_deinit") public func _bjs_GlobalUtils_PublicConverter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json index 2eeb8ed2d..9403e3b0c 100644 --- a/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json @@ -156,7 +156,19 @@ "GlobalUtils" ], "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "precision", + "namespace" : [ + "GlobalUtils" + ], + "type" : { + "int" : { + } + } + } ], "swiftCallName" : "GlobalUtils.PublicConverter" } diff --git a/Tests/BridgeJSGlobalTests/GlobalAPITests.swift b/Tests/BridgeJSGlobalTests/GlobalAPITests.swift index 19087ff55..9bdb5c5e9 100644 --- a/Tests/BridgeJSGlobalTests/GlobalAPITests.swift +++ b/Tests/BridgeJSGlobalTests/GlobalAPITests.swift @@ -63,6 +63,8 @@ enum Internal { @JS enum GlobalUtils { @JS class PublicConverter { + @JS var precision: Int = 2 + @JS init() {} @JS func toString(value: Int) -> String { diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 3aeb10a8b..0170da3bc 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -1032,6 +1032,9 @@ function BridgeJSGlobalTests_runJsWorksGlobal() { const globalConverter = new globalThis.GlobalUtils.PublicConverter(); assert.equal(globalConverter.toString(99), "99"); + assert.equal(globalConverter.precision, 2); + globalConverter.precision = 5; + assert.equal(globalConverter.precision, 5); globalConverter.release(); const globalHttpServer = new globalThis.GlobalNetworking.API.TestHTTPServer(); From 86f07ab426383d4661c0897b2c560391f8a7c7e5 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Fri, 6 Mar 2026 14:03:33 +1100 Subject: [PATCH 07/68] BridgeJS: Correctly emit @JS methods in extensions --- .../BridgeJSCore/SwiftToSkeleton.swift | 60 +++++++++++++- .../BridgeJSCodegenTests.swift | 18 ++++ .../Multifile/CrossFileExtension.swift | 5 ++ .../Multifile/CrossFileExtensionClass.swift | 4 + .../Inputs/MacroSwift/StaticFunctions.swift | 12 +++ .../Inputs/MacroSwift/SwiftClass.swift | 6 ++ .../Inputs/MacroSwift/SwiftStruct.swift | 6 ++ .../CrossFileExtension.json | 82 +++++++++++++++++++ .../CrossFileExtension.swift | 60 ++++++++++++++ .../StaticFunctions.Global.json | 69 ++++++++++++++++ .../StaticFunctions.Global.swift | 22 +++++ .../BridgeJSCodegenTests/StaticFunctions.json | 69 ++++++++++++++++ .../StaticFunctions.swift | 22 +++++ .../BridgeJSCodegenTests/SwiftClass.json | 17 ++++ .../BridgeJSCodegenTests/SwiftClass.swift | 11 +++ .../BridgeJSCodegenTests/SwiftStruct.json | 16 ++++ .../BridgeJSCodegenTests/SwiftStruct.swift | 11 +++ .../BridgeJSLinkTests/SwiftClass.d.ts | 1 + .../BridgeJSLinkTests/SwiftClass.js | 6 ++ 19 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 8f1b3fa35..2ff5cecba 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -43,12 +43,14 @@ public final class SwiftToSkeleton { var perSourceErrors: [(inputFilePath: String, errors: [DiagnosticError])] = [] var importedFiles: [ImportedFileSkeleton] = [] var exported = ExportedSkeleton(functions: [], classes: [], enums: [], exposeToGlobal: exposeToGlobal) + var exportCollectors: [ExportSwiftAPICollector] = [] for (sourceFile, inputFilePath) in sourceFiles { progress.print("Processing \(inputFilePath)") let exportCollector = ExportSwiftAPICollector(parent: self) exportCollector.walk(sourceFile) + exportCollectors.append(exportCollector) let typeNameCollector = ImportSwiftMacrosJSImportTypeNameCollector(viewMode: .sourceAccurate) typeNameCollector.walk(sourceFile) @@ -74,7 +76,15 @@ public final class SwiftToSkeleton { if !importedFile.isEmpty { importedFiles.append(importedFile) } - exportCollector.finalize(&exported) + } + + // Resolve extensions against all collectors. This needs to happen at this point so we can resolve both same file and cross file extensions. + for source in exportCollectors { + source.resolveDeferredExtensions(against: exportCollectors) + } + + for collector in exportCollectors { + collector.finalize(&exported) } if !perSourceErrors.isEmpty { @@ -486,6 +496,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { var exportedStructNames: [String] = [] var exportedStructByName: [String: ExportedStruct] = [:] var errors: [DiagnosticError] = [] + /// Extensions collected during the walk, to be resolved after all files have been walked + var deferredExtensions: [ExtensionDeclSyntax] = [] func finalize(_ result: inout ExportedSkeleton) { result.functions.append(contentsOf: exportedFunctions) @@ -1388,6 +1400,52 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } + override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + // Defer until all type declarations in the module have been collected. + deferredExtensions.append(node) + return .skipChildren + } + + func resolveDeferredExtensions(against collectors: [ExportSwiftAPICollector]) { + for ext in deferredExtensions { + var resolved = false + for collector in collectors { + if collector.resolveExtension(ext) { + resolved = true + break + } + } + if !resolved { + diagnose( + node: ext.extendedType, + message: "Unsupported type '\(ext.extendedType.trimmedDescription)'.", + hint: "You can only extend `@JS` annotated types defined in the same module" + ) + } + } + } + + /// Walks extension members under the matching type’s state, returning whether the type was found + func resolveExtension(_ ext: ExtensionDeclSyntax) -> Bool { + let name = ext.extendedType.trimmedDescription + let state: State + if let entry = exportedClassByName.first(where: { $0.value.name == name }) { + state = .classBody(name: name, key: entry.key) + } else if let entry = exportedStructByName.first(where: { $0.value.name == name }) { + state = .structBody(name: name, key: entry.key) + } else if let entry = exportedEnumByName.first(where: { $0.value.name == name }) { + state = .enumBody(name: name, key: entry.key) + } else { + return false + } + stateStack.push(state: state) + for member in ext.memberBlock.members { + walk(member) + } + stateStack.pop() + return true + } + override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index 9754fbced..1b1f95f76 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -167,6 +167,24 @@ import Testing try snapshotCodegen(skeleton: skeleton, name: "CrossFileFunctionTypes.ReverseOrder") } + @Test + func codegenCrossFileExtension() throws { + let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let classURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtensionClass.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: classURL, encoding: .utf8)), + inputFilePath: "CrossFileExtensionClass.swift" + ) + let extensionURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtension.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: extensionURL, encoding: .utf8)), + inputFilePath: "CrossFileExtension.swift" + ) + let skeleton = try swiftAPI.finalize() + try snapshotCodegen(skeleton: skeleton, name: "CrossFileExtension") + } + + @Test func codegenSkipsEmptySkeletons() throws { let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift new file mode 100644 index 000000000..ce9e8e2b0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift @@ -0,0 +1,5 @@ +extension Greeter { + @JS func greetFormally() -> String { + return "Good day, " + self.name + "." + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift new file mode 100644 index 000000000..48625d42a --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift @@ -0,0 +1,4 @@ +@JS class Greeter { + @JS init(name: String) {} + @JS func greet() -> String { return "" } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift index 1d42cf415..25196d773 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift @@ -38,3 +38,15 @@ enum APIResult { } } } + +extension MathUtils { + @JS static func divide(a: Int, b: Int) -> Int { + return a / b + } +} + +extension Calculator { + @JS static func cube(value: Int) -> Int { + return value * value * value + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift index d7b5a5b8e..12004ffa8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift @@ -12,6 +12,12 @@ } } +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, " + self.name + "!!!" + } +} + @JS func takeGreeter(greeter: Greeter) { print(greeter.greet()) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift index 0d84f4736..d42b2e202 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift @@ -60,3 +60,9 @@ } @JS func roundtripContainer(_ container: Container) -> Container + +extension DataPoint { + @JS func distanceFromOrigin() -> Double { + return (x * x + y * y).squareRoot() + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json new file mode 100644 index 000000000..f77d39ad9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json @@ -0,0 +1,82 @@ +{ + "exported" : { + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Greeter_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Greeter_greet", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greet", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_greetFormally", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetFormally", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Greeter", + "properties" : [ + + ], + "swiftCallName" : "Greeter" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift new file mode 100644 index 000000000..ab73df508 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift @@ -0,0 +1,60 @@ +@_expose(wasm, "bjs_Greeter_init") +@_cdecl("bjs_Greeter_init") +public func _bjs_Greeter_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_greet") +@_cdecl("bjs_Greeter_greet") +public func _bjs_Greeter_greet(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greet() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_greetFormally") +@_cdecl("bjs_Greeter_greetFormally") +public func _bjs_Greeter_greetFormally(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetFormally() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_deinit") +@_cdecl("bjs_Greeter_deinit") +public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Greeter_wrap") +fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Greeter_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json index b0eac3313..a5fc4e7e1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -125,6 +125,45 @@ } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "int" : { + + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", @@ -182,6 +221,36 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index b6d35a215..3478eb883 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -44,6 +44,17 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +145,17 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index e4ec22855..b620fb0e2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -125,6 +125,45 @@ } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "int" : { + + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", @@ -182,6 +221,36 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index b6d35a215..3478eb883 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -44,6 +44,17 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +145,17 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index 7cebdd5e6..0245bf208 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -61,6 +61,23 @@ "returnType" : { "void" : { + } + } + }, + { + "abiName" : "bjs_Greeter_greetEnthusiastically", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetEnthusiastically", + "parameters" : [ + + ], + "returnType" : { + "string" : { + } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index 0e9434832..9f927da13 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -40,6 +40,17 @@ public func _bjs_Greeter_changeName(_ _self: UnsafeMutableRawPointer, _ nameByte #endif } +@_expose(wasm, "bjs_Greeter_greetEnthusiastically") +@_cdecl("bjs_Greeter_greetEnthusiastically") +public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 00c6af5cb..d216f10c6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -211,7 +211,23 @@ ] }, "methods" : [ + { + "abiName" : "bjs_DataPoint_distanceFromOrigin", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "distanceFromOrigin", + "parameters" : [ + ], + "returnType" : { + "double" : { + + } + } + } ], "name" : "DataPoint", "properties" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 6fccb3280..5e867f179 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -66,6 +66,17 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_distanceFromOrigin") +@_cdecl("bjs_DataPoint_distanceFromOrigin") +public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { + #if arch(wasm32) + let ret = DataPoint.bridgeJSLiftParameter().distanceFromOrigin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Address { let zipCode = Optional.bridgeJSStackPop() diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 05fc97fee..72f816bd5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -14,6 +14,7 @@ export interface SwiftHeapObject { export interface Greeter extends SwiftHeapObject { greet(): string; changeName(name: string): void; + greetEnthusiastically(): string; name: string; } export interface PublicGreeter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 9acf70de2..2596b539a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -282,6 +282,12 @@ export async function createInstantiator(options, swift) { const nameId = swift.memory.retain(nameBytes); instance.exports.bjs_Greeter_changeName(this.pointer, nameId, nameBytes.length); } + greetEnthusiastically() { + instance.exports.bjs_Greeter_greetEnthusiastically(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } get name() { instance.exports.bjs_Greeter_name_get(this.pointer); const ret = tmpRetString; From 6762c6b030795956d229544035c554ffec6dc877 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Tue, 10 Mar 2026 13:57:04 +1100 Subject: [PATCH 08/68] BridgeJS: Improve test coverage for @JS methods and properties in extensions --- .../Inputs/MacroSwift/StaticFunctions.swift | 4 + .../Inputs/MacroSwift/SwiftClass.swift | 8 + .../Inputs/MacroSwift/SwiftStruct.swift | 6 + .../StaticFunctions.Global.json | 28 +++ .../StaticFunctions.Global.swift | 22 +++ .../BridgeJSCodegenTests/StaticFunctions.json | 28 +++ .../StaticFunctions.swift | 22 +++ .../BridgeJSCodegenTests/SwiftClass.json | 47 +++++ .../BridgeJSCodegenTests/SwiftClass.swift | 33 ++++ .../BridgeJSCodegenTests/SwiftStruct.json | 37 ++++ .../BridgeJSCodegenTests/SwiftStruct.swift | 22 +++ .../StaticFunctions.Global.d.ts | 4 + .../StaticFunctions.Global.js | 18 ++ .../BridgeJSLinkTests/StaticFunctions.d.ts | 4 + .../BridgeJSLinkTests/StaticFunctions.js | 18 ++ .../BridgeJSLinkTests/SwiftClass.d.ts | 3 + .../BridgeJSLinkTests/SwiftClass.js | 16 ++ .../BridgeJSLinkTests/SwiftStruct.d.ts | 3 + .../BridgeJSLinkTests/SwiftStruct.js | 17 +- .../BridgeJSRuntimeTests/ExportAPITests.swift | 22 +++ .../Generated/BridgeJS.swift | 99 +++++++++++ .../Generated/JavaScript/BridgeJS.json | 161 ++++++++++++++++++ Tests/BridgeJSRuntimeTests/StructAPIs.swift | 12 ++ Tests/prelude.mjs | 19 +++ 24 files changed, 652 insertions(+), 1 deletion(-) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift index 25196d773..4f6296d2e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift @@ -43,10 +43,14 @@ extension MathUtils { @JS static func divide(a: Int, b: Int) -> Int { return a / b } + + @JS static var pi: Double { 3.14159 } } extension Calculator { @JS static func cube(value: Int) -> Int { return value * value * value } + + @JS static var version: String { "1.0" } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift index 12004ffa8..2fb050eeb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift @@ -16,6 +16,14 @@ extension Greeter { @JS func greetEnthusiastically() -> String { return "Hey, " + self.name + "!!!" } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } } @JS func takeGreeter(greeter: Greeter) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift index d42b2e202..4ec6525e3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift @@ -65,4 +65,10 @@ extension DataPoint { @JS func distanceFromOrigin() -> Double { return (x * x + y * y).squareRoot() } + + @JS static func origin() -> DataPoint { + return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) + } + + @JS static var dimensions: Int { 2 } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json index a5fc4e7e1..3e07317ac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -168,7 +168,21 @@ ], "name" : "MathUtils", "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "pi", + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + }, + "type" : { + "double" : { + } + } + } ], "swiftCallName" : "MathUtils" } @@ -254,7 +268,21 @@ } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index 3478eb883..aa7af111f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -55,6 +55,17 @@ public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_version_get") +@_cdecl("bjs_Calculator_static_version_get") +public func _bjs_Calculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = Calculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -156,6 +167,17 @@ public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_MathUtils_static_pi_get") +@_cdecl("bjs_MathUtils_static_pi_get") +public func _bjs_MathUtils_static_pi_get() -> Float64 { + #if arch(wasm32) + let ret = MathUtils.pi + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index b620fb0e2..a6540015f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -168,7 +168,21 @@ ], "name" : "MathUtils", "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "pi", + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + }, + "type" : { + "double" : { + } + } + } ], "swiftCallName" : "MathUtils" } @@ -254,7 +268,21 @@ } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index 3478eb883..aa7af111f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -55,6 +55,17 @@ public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_version_get") +@_cdecl("bjs_Calculator_static_version_get") +public func _bjs_Calculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = Calculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -156,6 +167,17 @@ public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_MathUtils_static_pi_get") +@_cdecl("bjs_MathUtils_static_pi_get") +public func _bjs_MathUtils_static_pi_get() -> Float64 { + #if arch(wasm32) + let ret = MathUtils.pi + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index 0245bf208..cf5156d8d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -80,6 +80,28 @@ } } + }, + { + "abiName" : "bjs_Greeter_static_greetAnonymously", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "greetAnonymously", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + } } ], "name" : "Greeter", @@ -91,6 +113,31 @@ "type" : { "string" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "nameCount", + "type" : { + "int" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + }, + "type" : { + "string" : { + } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index 9f927da13..cb61e263d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -51,6 +51,17 @@ public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) #endif } +@_expose(wasm, "bjs_Greeter_static_greetAnonymously") +@_cdecl("bjs_Greeter_static_greetAnonymously") +public func _bjs_Greeter_static_greetAnonymously() -> Void { + #if arch(wasm32) + let ret = Greeter.greetAnonymously() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -72,6 +83,28 @@ public func _bjs_Greeter_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes #endif } +@_expose(wasm, "bjs_Greeter_nameCount_get") +@_cdecl("bjs_Greeter_nameCount_get") +public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).nameCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") +@_cdecl("bjs_Greeter_static_defaultGreeting_get") +public func _bjs_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index d216f10c6..7a6421668 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -227,6 +227,28 @@ } } + }, + { + "abiName" : "bjs_DataPoint_static_origin", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "origin", + "parameters" : [ + + ], + "returnType" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + } } ], "name" : "DataPoint", @@ -290,6 +312,21 @@ "_1" : "null" } } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "dimensions", + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + }, + "type" : { + "int" : { + + } + } } ], "swiftCallName" : "DataPoint" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 5e867f179..5e17b6db2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -66,6 +66,17 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_static_dimensions_get") +@_cdecl("bjs_DataPoint_static_dimensions_get") +public func _bjs_DataPoint_static_dimensions_get() -> Int32 { + #if arch(wasm32) + let ret = DataPoint.dimensions + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_DataPoint_distanceFromOrigin") @_cdecl("bjs_DataPoint_distanceFromOrigin") public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { @@ -77,6 +88,17 @@ public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { #endif } +@_expose(wasm, "bjs_DataPoint_static_origin") +@_cdecl("bjs_DataPoint_static_origin") +public func _bjs_DataPoint_static_origin() -> Void { + #if arch(wasm32) + let ret = DataPoint.origin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Address { let zipCode = Optional.bridgeJSStackPop() 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 a2f1c7d6d..5916e1648 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts @@ -22,6 +22,8 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; + cube(value: number): number; + readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -53,6 +55,8 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; + divide(a: number, b: number): number; + readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 800b07107..df2a34ff1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -297,6 +297,14 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } + static divide(a, b) { + const ret = instance.exports.bjs_MathUtils_static_divide(a, b); + return ret; + } + static get pi() { + const ret = instance.exports.bjs_MathUtils_static_pi_get(); + return ret; + } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -314,6 +322,16 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; + }, + cube: function(value) { + const ret = instance.exports.bjs_Calculator_static_cube(value); + return ret; + }, + get version() { + instance.exports.bjs_Calculator_static_version_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts index e938ddb9a..c9cb26910 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts @@ -22,6 +22,8 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; + cube(value: number): number; + readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -43,6 +45,8 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; + divide(a: number, b: number): number; + readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index a4290f828..2e5b6e7f1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -297,6 +297,14 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } + static divide(a, b) { + const ret = instance.exports.bjs_MathUtils_static_divide(a, b); + return ret; + } + static get pi() { + const ret = instance.exports.bjs_MathUtils_static_pi_get(); + return ret; + } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -308,6 +316,16 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; + }, + cube: function(value) { + const ret = instance.exports.bjs_Calculator_static_cube(value); + return ret; + }, + get version() { + instance.exports.bjs_Calculator_static_version_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 72f816bd5..6d590950c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -16,6 +16,7 @@ export interface Greeter extends SwiftHeapObject { changeName(name: string): void; greetEnthusiastically(): string; name: string; + readonly nameCount: number; } export interface PublicGreeter extends SwiftHeapObject { } @@ -24,6 +25,8 @@ export interface PackageGreeter extends SwiftHeapObject { export type Exports = { Greeter: { new(name: string): Greeter; + greetAnonymously(): string; + readonly defaultGreeting: string; } PublicGreeter: { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 2596b539a..f6293f12a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -288,6 +288,12 @@ export async function createInstantiator(options, swift) { tmpRetString = undefined; return ret; } + static greetAnonymously() { + instance.exports.bjs_Greeter_static_greetAnonymously(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } get name() { instance.exports.bjs_Greeter_name_get(this.pointer); const ret = tmpRetString; @@ -299,6 +305,16 @@ export async function createInstantiator(options, swift) { const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } + get nameCount() { + const ret = instance.exports.bjs_Greeter_nameCount_get(this.pointer); + return ret; + } + static get defaultGreeting() { + instance.exports.bjs_Greeter_static_defaultGreeting_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } } class PublicGreeter extends SwiftHeapObject { static __construct(ptr) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts index 4a61a26e3..211661d5f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -16,6 +16,7 @@ export interface DataPoint { label: string; optCount: number | null; optFlag: boolean | null; + distanceFromOrigin(): number; } export interface Address { street: string; @@ -65,6 +66,8 @@ export type Exports = { Precision: PrecisionObject DataPoint: { init(x: number, y: number, label: string, optCount: number | null, optFlag: boolean | null): DataPoint; + readonly dimensions: number; + origin(): DataPoint; } ConfigStruct: { readonly maxRetries: number; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index cd2d396df..099f4ccc3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -73,7 +73,13 @@ export async function createInstantiator(options, swift) { const string = strStack.pop(); const f64 = f64Stack.pop(); const f641 = f64Stack.pop(); - return { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; + const instance1 = { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; + instance1.distanceFromOrigin = function() { + structHelpers.DataPoint.lower(this); + const ret = instance.exports.bjs_DataPoint_distanceFromOrigin(); + return ret; + }.bind(instance1); + return instance1; } }); const __bjs_createAddressHelpers = () => ({ @@ -546,6 +552,15 @@ export async function createInstantiator(options, swift) { const structValue = structHelpers.DataPoint.lift(); return structValue; }, + get dimensions() { + const ret = instance.exports.bjs_DataPoint_static_dimensions_get(); + return ret; + }, + origin: function() { + instance.exports.bjs_DataPoint_static_origin(); + const structValue = structHelpers.DataPoint.lift(); + return structValue; + }, }, ConfigStruct: { get maxRetries() { diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index c8ebbc8ce..6997cfd3b 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -150,6 +150,20 @@ struct TestError: Error { } } +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, \(name)!!!" + } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } +} + @JS func takeGreeter(g: Greeter, name: String) { g.changeName(name: name) } @@ -250,6 +264,14 @@ struct TestError: Error { case auto = "auto" } +extension StaticCalculator { + @JS static func doubleValue(_ value: Int) -> Int { + return value * 2 + } + + @JS static var version: String { "1.0" } +} + @JS func setDirection(_ direction: Direction) -> Direction { return direction } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 13aab1455..cde1afc59 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -3418,6 +3418,28 @@ public func _bjs_StaticCalculator_static_roundtrip(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_StaticCalculator_static_doubleValue") +@_cdecl("bjs_StaticCalculator_static_doubleValue") +public func _bjs_StaticCalculator_static_doubleValue(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = StaticCalculator.doubleValue(_: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_StaticCalculator_static_version_get") +@_cdecl("bjs_StaticCalculator_static_version_get") +public func _bjs_StaticCalculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = StaticCalculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_StaticUtils_Nested_static_roundtrip") @_cdecl("bjs_StaticUtils_Nested_static_roundtrip") public func _bjs_StaticUtils_Nested_static_roundtrip(_ valueBytes: Int32, _ valueLength: Int32) -> Void { @@ -4233,6 +4255,39 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_static_dimensions_get") +@_cdecl("bjs_DataPoint_static_dimensions_get") +public func _bjs_DataPoint_static_dimensions_get() -> Int32 { + #if arch(wasm32) + let ret = DataPoint.dimensions + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_distanceFromOrigin") +@_cdecl("bjs_DataPoint_distanceFromOrigin") +public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { + #if arch(wasm32) + let ret = DataPoint.bridgeJSLiftParameter().distanceFromOrigin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_static_origin") +@_cdecl("bjs_DataPoint_static_origin") +public func _bjs_DataPoint_static_origin() -> Void { + #if arch(wasm32) + let ret = DataPoint.origin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension PublicPoint: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PublicPoint { let y = Int.bridgeJSStackPop() @@ -6934,6 +6989,28 @@ public func _bjs_Greeter_makeCustomGreeter(_ _self: UnsafeMutableRawPointer) -> #endif } +@_expose(wasm, "bjs_Greeter_greetEnthusiastically") +@_cdecl("bjs_Greeter_greetEnthusiastically") +public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_greetAnonymously") +@_cdecl("bjs_Greeter_static_greetAnonymously") +public func _bjs_Greeter_static_greetAnonymously() -> Void { + #if arch(wasm32) + let ret = Greeter.greetAnonymously() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -6966,6 +7043,28 @@ public func _bjs_Greeter_prefix_get(_ _self: UnsafeMutableRawPointer) -> Void { #endif } +@_expose(wasm, "bjs_Greeter_nameCount_get") +@_cdecl("bjs_Greeter_nameCount_get") +public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).nameCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") +@_cdecl("bjs_Greeter_static_defaultGreeting_get") +public func _bjs_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 746e0cd3c..137fb6087 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -705,6 +705,45 @@ "useJSTypedClosure" : false } } + }, + { + "abiName" : "bjs_Greeter_greetEnthusiastically", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetEnthusiastically", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_static_greetAnonymously", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "greetAnonymously", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + } } ], "name" : "Greeter", @@ -726,6 +765,31 @@ "type" : { "string" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "nameCount", + "type" : { + "int" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + }, + "type" : { + "string" : { + } } } @@ -7620,10 +7684,54 @@ "_0" : "StaticCalculator" } } + }, + { + "abiName" : "bjs_StaticCalculator_static_doubleValue", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "doubleValue", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "StaticCalculator" + } + } } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "StaticCalculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "StaticCalculator", "tsFullPath" : "StaticCalculator" @@ -13342,7 +13450,45 @@ ] }, "methods" : [ + { + "abiName" : "bjs_DataPoint_distanceFromOrigin", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "distanceFromOrigin", + "parameters" : [ + + ], + "returnType" : { + "double" : { + } + } + }, + { + "abiName" : "bjs_DataPoint_static_origin", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "origin", + "parameters" : [ + + ], + "returnType" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + } + } ], "name" : "DataPoint", "properties" : [ @@ -13405,6 +13551,21 @@ "_1" : "null" } } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "dimensions", + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + }, + "type" : { + "int" : { + + } + } } ], "swiftCallName" : "DataPoint" diff --git a/Tests/BridgeJSRuntimeTests/StructAPIs.swift b/Tests/BridgeJSRuntimeTests/StructAPIs.swift index 0a05a517d..af925cb77 100644 --- a/Tests/BridgeJSRuntimeTests/StructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/StructAPIs.swift @@ -174,6 +174,18 @@ import JavaScriptKit } } +extension DataPoint { + @JS func distanceFromOrigin() -> Double { + return (x * x + y * y).squareRoot() + } + + @JS static func origin() -> DataPoint { + return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) + } + + @JS static var dimensions: Int { 2 } +} + @JS func roundTripDataPoint(_ data: DataPoint) -> DataPoint { return data } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 4c211e91c..94d33057d 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -269,6 +269,12 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(g.name, "Bob"); assert.equal(g.greet(), "Hello, Bob!"); + // Test class extension members + assert.equal(g.greetEnthusiastically(), "Hey, Bob!!!"); + assert.equal(g.nameCount, 3); + assert.equal(exports.Greeter.greetAnonymously(), "Hello."); + assert.equal(exports.Greeter.defaultGreeting, "Hello, world!"); + const g2 = exports.roundTripSwiftHeapObject(g) assert.equal(g2.greet(), "Hello, Bob!"); assert.equal(g2.name, "Bob"); @@ -761,6 +767,10 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(StaticCalculatorValues.Basic, 1); assert.equal(StaticCalculatorValues.Scientific, exports.StaticCalculator.Scientific); assert.equal(StaticCalculatorValues.Basic, exports.StaticCalculator.Basic); + + // Test enum extension static members + assert.equal(exports.StaticCalculator.doubleValue(21), 42); + assert.equal(exports.StaticCalculator.version, "1.0"); assert.equal(exports.StaticUtils.Nested.roundtrip("hello world"), "hello world"); assert.equal(exports.StaticUtils.Nested.roundtrip("test"), "test"); @@ -779,6 +789,15 @@ function testStructSupport(exports) { const data2 = { x: 0.0, y: 0.0, label: "", optCount: null, optFlag: null }; assert.deepEqual(exports.roundTripDataPoint(data2), data2); + // Test struct extension members + const data3 = { x: 3.0, y: 4.0, label: "Test", optCount: null, optFlag: null }; + assert.equal(exports.DataPoint.distanceFromOrigin(data3), 5.0); + const origin = exports.DataPoint.origin(); + assert.equal(origin.x, 0.0); + assert.equal(origin.y, 0.0); + assert.equal(origin.label, "origin"); + assert.equal(exports.DataPoint.dimensions, 2); + const publicPoint = { x: 9, y: -3 }; assert.deepEqual(exports.roundTripPublicPoint(publicPoint), publicPoint); From 7dd02633cb57d4dc9b43328e2cef8ab1407ff7aa Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 10 Mar 2026 22:14:28 +0000 Subject: [PATCH 09/68] BridgeJS: Use shared decodeString for JSTypedClosure error path (#696) --- Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift | 2 +- .../__Snapshots__/BridgeJSLinkTests/SwiftClosure.js | 2 +- .../__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 93814123c..8c18ced4d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -660,7 +660,7 @@ public struct BridgeJSLink { helperPrinter.write("let length = 0;") helperPrinter.write("while (bytes[length] !== 0) { length += 1; }") helperPrinter.write( - "const fileID = \(JSGlueVariableScope.reservedTextDecoder).decode(bytes.subarray(0, length));" + "const fileID = \(JSGlueVariableScope.reservedDecodeString)(state.file, length);" ) helperPrinter.write( "throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`);" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 09eb39050..a0e874907 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -70,7 +70,7 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, state.file); let length = 0; while (bytes[length] !== 0) { length += 1; } - const fileID = textDecoder.decode(bytes.subarray(0, length)); + const fileID = decodeString(state.file, length); throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); } return func(...args); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index 21e382395..42ca68e78 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -40,7 +40,7 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, state.file); let length = 0; while (bytes[length] !== 0) { length += 1; } - const fileID = textDecoder.decode(bytes.subarray(0, length)); + const fileID = decodeString(state.file, length); throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); } return func(...args); From 825f6950b2ed32de29764f131c306ec75e82f008 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Wed, 11 Mar 2026 10:58:14 +1100 Subject: [PATCH 10/68] Fix formatting --- .../Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift | 1 - Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index 1b1f95f76..dd0ce5d03 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -184,7 +184,6 @@ import Testing try snapshotCodegen(skeleton: skeleton, name: "CrossFileExtension") } - @Test func codegenSkipsEmptySkeletons() throws { let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) diff --git a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift index db093e549..e3c19a8e4 100644 --- a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift +++ b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift @@ -72,7 +72,7 @@ class JSClosureAsyncTests: XCTestCase { )!.value() XCTAssertEqual(result, 42.0) } - + func testAsyncOneshotClosureWithPriority() async throws { let priority = UnsafeSendableBox(nil) let closure = JSOneshotClosure.async(priority: .high) { _ in @@ -83,7 +83,7 @@ class JSClosureAsyncTests: XCTestCase { XCTAssertEqual(result, 42.0) XCTAssertEqual(priority.value, .high) } - + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) func testAsyncOneshotClosureWithTaskExecutor() async throws { let executor = AnyTaskExecutor() @@ -93,7 +93,7 @@ class JSClosureAsyncTests: XCTestCase { let result = try await JSPromise(from: closure.function!())!.value() XCTAssertEqual(result, 42.0) } - + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) func testAsyncOneshotClosureWithTaskExecutorPreference() async throws { let executor = AnyTaskExecutor() From a93a6869918f5610547caf6d924555f5f17dc32f Mon Sep 17 00:00:00 2001 From: William Taylor Date: Wed, 11 Mar 2026 11:53:04 +1100 Subject: [PATCH 11/68] Update test code to avoid accidentally introduced failure --- .../Inputs/MacroSwift/SwiftStruct.swift | 17 ++- .../BridgeJSCodegenTests/SwiftStruct.json | 87 ++++++++++--- .../BridgeJSCodegenTests/SwiftStruct.swift | 81 ++++++++++-- .../Generated/BridgeJS.swift | 92 ++++++++++++-- .../Generated/JavaScript/BridgeJS.json | 115 +++++++++++++++--- Tests/BridgeJSRuntimeTests/StructAPIs.swift | 24 +++- Tests/prelude.mjs | 11 +- 7 files changed, 361 insertions(+), 66 deletions(-) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift index 4ec6525e3..63bb0ff8d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift @@ -61,11 +61,22 @@ @JS func roundtripContainer(_ container: Container) -> Container -extension DataPoint { - @JS func distanceFromOrigin() -> Double { - return (x * x + y * y).squareRoot() +@JS struct Vector2D { + var dx: Double + var dy: Double +} + +extension Vector2D { + @JS func magnitude() -> Double { + return (dx * dx + dy * dy).squareRoot() } + @JS func scaled(by factor: Double) -> Vector2D { + return Vector2D(dx: dx * factor, dy: dy * factor) + } +} + +extension DataPoint { @JS static func origin() -> DataPoint { return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 7a6421668..617124701 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -211,23 +211,6 @@ ] }, "methods" : [ - { - "abiName" : "bjs_DataPoint_distanceFromOrigin", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "distanceFromOrigin", - "parameters" : [ - - ], - "returnType" : { - "double" : { - - } - } - }, { "abiName" : "bjs_DataPoint_static_origin", "effects" : { @@ -635,6 +618,76 @@ } ], "swiftCallName" : "Container" + }, + { + "methods" : [ + { + "abiName" : "bjs_Vector2D_magnitude", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "magnitude", + "parameters" : [ + + ], + "returnType" : { + "double" : { + + } + } + }, + { + "abiName" : "bjs_Vector2D_scaled", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "scaled", + "parameters" : [ + { + "label" : "by", + "name" : "factor", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Vector2D" + } + } + } + ], + "name" : "Vector2D", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dx", + "type" : { + "double" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dy", + "type" : { + "double" : { + + } + } + } + ], + "swiftCallName" : "Vector2D" } ] }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 5e17b6db2..e4cd409ae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -77,17 +77,6 @@ public func _bjs_DataPoint_static_dimensions_get() -> Int32 { #endif } -@_expose(wasm, "bjs_DataPoint_distanceFromOrigin") -@_cdecl("bjs_DataPoint_distanceFromOrigin") -public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { - #if arch(wasm32) - let ret = DataPoint.bridgeJSLiftParameter().distanceFromOrigin() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_DataPoint_static_origin") @_cdecl("bjs_DataPoint_static_origin") public func _bjs_DataPoint_static_origin() -> Void { @@ -466,6 +455,76 @@ fileprivate func _bjs_struct_lift_Container_extern() -> Int32 { return _bjs_struct_lift_Container_extern() } +extension Vector2D: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Vector2D { + let dy = Double.bridgeJSStackPop() + let dx = Double.bridgeJSStackPop() + return Vector2D(dx: dx, dy: dy) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.dx.bridgeJSStackPush() + self.dy.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Vector2D(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Vector2D())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Vector2D") +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Vector2D(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Vector2D_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Vector2D") +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Vector2D() -> Int32 { + return _bjs_struct_lift_Vector2D_extern() +} + +@_expose(wasm, "bjs_Vector2D_magnitude") +@_cdecl("bjs_Vector2D_magnitude") +public func _bjs_Vector2D_magnitude() -> Float64 { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().magnitude() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Vector2D_scaled") +@_cdecl("bjs_Vector2D_scaled") +public func _bjs_Vector2D_scaled(_ factor: Float64) -> Void { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().scaled(by: Double.bridgeJSLiftParameter(factor)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundtrip") @_cdecl("bjs_roundtrip") public func _bjs_roundtrip() -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index cde1afc59..c85dec679 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -4266,17 +4266,6 @@ public func _bjs_DataPoint_static_dimensions_get() -> Int32 { #endif } -@_expose(wasm, "bjs_DataPoint_distanceFromOrigin") -@_cdecl("bjs_DataPoint_distanceFromOrigin") -public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { - #if arch(wasm32) - let ret = DataPoint.bridgeJSLiftParameter().distanceFromOrigin() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_DataPoint_static_origin") @_cdecl("bjs_DataPoint_static_origin") public func _bjs_DataPoint_static_origin() -> Void { @@ -5089,6 +5078,87 @@ public func _bjs_ConfigStruct_static_computedSetting_get() -> Void { #endif } +extension Vector2D: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Vector2D { + let dy = Double.bridgeJSStackPop() + let dx = Double.bridgeJSStackPop() + return Vector2D(dx: dx, dy: dy) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.dx.bridgeJSStackPush() + self.dy.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Vector2D(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Vector2D())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Vector2D") +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Vector2D(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Vector2D_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Vector2D") +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Vector2D() -> Int32 { + return _bjs_struct_lift_Vector2D_extern() +} + +@_expose(wasm, "bjs_Vector2D_init") +@_cdecl("bjs_Vector2D_init") +public func _bjs_Vector2D_init(_ dx: Float64, _ dy: Float64) -> Void { + #if arch(wasm32) + let ret = Vector2D(dx: Double.bridgeJSLiftParameter(dx), dy: Double.bridgeJSLiftParameter(dy)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Vector2D_magnitude") +@_cdecl("bjs_Vector2D_magnitude") +public func _bjs_Vector2D_magnitude() -> Float64 { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().magnitude() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Vector2D_scaled") +@_cdecl("bjs_Vector2D_scaled") +public func _bjs_Vector2D_scaled(_ factor: Float64) -> Void { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().scaled(by: Double.bridgeJSLiftParameter(factor)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension JSObjectContainer: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> JSObjectContainer { let optionalObject = Optional.bridgeJSStackPop() diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 137fb6087..14cdc5dee 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -13450,23 +13450,6 @@ ] }, "methods" : [ - { - "abiName" : "bjs_DataPoint_distanceFromOrigin", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "distanceFromOrigin", - "parameters" : [ - - ], - "returnType" : { - "double" : { - - } - } - }, { "abiName" : "bjs_DataPoint_static_origin", "effects" : { @@ -14500,6 +14483,104 @@ ], "swiftCallName" : "ConfigStruct" }, + { + "constructor" : { + "abiName" : "bjs_Vector2D_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "dx", + "name" : "dx", + "type" : { + "double" : { + + } + } + }, + { + "label" : "dy", + "name" : "dy", + "type" : { + "double" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Vector2D_magnitude", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "magnitude", + "parameters" : [ + + ], + "returnType" : { + "double" : { + + } + } + }, + { + "abiName" : "bjs_Vector2D_scaled", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "scaled", + "parameters" : [ + { + "label" : "by", + "name" : "factor", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Vector2D" + } + } + } + ], + "name" : "Vector2D", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dx", + "type" : { + "double" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dy", + "type" : { + "double" : { + + } + } + } + ], + "swiftCallName" : "Vector2D" + }, { "methods" : [ diff --git a/Tests/BridgeJSRuntimeTests/StructAPIs.swift b/Tests/BridgeJSRuntimeTests/StructAPIs.swift index af925cb77..daa7ad1e2 100644 --- a/Tests/BridgeJSRuntimeTests/StructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/StructAPIs.swift @@ -175,10 +175,6 @@ import JavaScriptKit } extension DataPoint { - @JS func distanceFromOrigin() -> Double { - return (x * x + y * y).squareRoot() - } - @JS static func origin() -> DataPoint { return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) } @@ -186,6 +182,26 @@ extension DataPoint { @JS static var dimensions: Int { 2 } } +@JS struct Vector2D { + var dx: Double + var dy: Double + + @JS init(dx: Double, dy: Double) { + self.dx = dx + self.dy = dy + } +} + +extension Vector2D { + @JS func magnitude() -> Double { + return (dx * dx + dy * dy).squareRoot() + } + + @JS func scaled(by factor: Double) -> Vector2D { + return Vector2D(dx: dx * factor, dy: dy * factor) + } +} + @JS func roundTripDataPoint(_ data: DataPoint) -> DataPoint { return data } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 94d33057d..c5da33196 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -789,15 +789,20 @@ function testStructSupport(exports) { const data2 = { x: 0.0, y: 0.0, label: "", optCount: null, optFlag: null }; assert.deepEqual(exports.roundTripDataPoint(data2), data2); - // Test struct extension members - const data3 = { x: 3.0, y: 4.0, label: "Test", optCount: null, optFlag: null }; - assert.equal(exports.DataPoint.distanceFromOrigin(data3), 5.0); + // Test struct extension static members const origin = exports.DataPoint.origin(); assert.equal(origin.x, 0.0); assert.equal(origin.y, 0.0); assert.equal(origin.label, "origin"); assert.equal(exports.DataPoint.dimensions, 2); + // Test struct extension instance methods + const vec = new exports.Vector2D(3.0, 4.0); + assert.equal(vec.magnitude(), 5.0); + const scaled = vec.scaled(2.0); + assert.equal(scaled.dx, 6.0); + assert.equal(scaled.dy, 8.0); + const publicPoint = { x: 9, y: -3 }; assert.deepEqual(exports.roundTripPublicPoint(publicPoint), publicPoint); From e7b842716fc2382d3f8e4283d0d8a4acbf198af7 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 10 Mar 2026 16:40:28 +0100 Subject: [PATCH 12/68] BridgeJS: Fix protocol existential lowering in Swift-to-JS direction --- Benchmarks/Sources/Generated/BridgeJS.swift | 45 +++- .../PlayBridgeJS/Generated/BridgeJS.swift | 5 +- .../Sources/BridgeJSCore/ExportSwift.swift | 68 +++++- .../BridgeJSCodegenTests/ArrayTypes.swift | 10 +- .../CrossFileFunctionTypes.ReverseOrder.swift | 10 +- .../CrossFileFunctionTypes.swift | 10 +- ...CrossFileTypeResolution.ReverseOrder.swift | 10 +- .../CrossFileTypeResolution.swift | 10 +- .../DefaultParameters.swift | 15 +- .../DictionaryTypes.swift | 5 +- .../EnumAssociatedValue.swift | 5 +- .../EnumNamespace.Global.swift | 20 +- .../BridgeJSCodegenTests/EnumNamespace.swift | 20 +- .../BridgeJSCodegenTests/JSValue.swift | 5 +- .../BridgeJSCodegenTests/MixedGlobal.swift | 5 +- .../BridgeJSCodegenTests/MixedPrivate.swift | 5 +- .../Namespaces.Global.swift | 20 +- .../BridgeJSCodegenTests/Namespaces.swift | 20 +- .../BridgeJSCodegenTests/Optionals.swift | 10 +- .../BridgeJSCodegenTests/PropertyTypes.swift | 5 +- .../BridgeJSCodegenTests/Protocol.swift | 35 ++- .../StaticFunctions.Global.swift | 5 +- .../StaticFunctions.swift | 5 +- .../StaticProperties.Global.swift | 5 +- .../StaticProperties.swift | 5 +- .../BridgeJSCodegenTests/SwiftClass.swift | 15 +- .../BridgeJSCodegenTests/SwiftClosure.swift | 10 +- .../BridgeJSCodegenTests/SwiftStruct.swift | 5 +- .../JavaScriptKit/BridgeJSIntrinsics.swift | 19 +- .../Generated/BridgeJS.swift | 15 +- .../BridgeJSRuntimeTests/ExportAPITests.swift | 30 +++ .../Generated/BridgeJS.swift | 225 +++++++++++++++--- .../Generated/JavaScript/BridgeJS.json | 137 +++++++++++ Tests/prelude.mjs | 34 +++ 34 files changed, 740 insertions(+), 108 deletions(-) diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index 7b7c6e690..c9adb2b1a 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -491,10 +491,13 @@ public func _bjs_EnumRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension EnumRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension EnumRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_EnumRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_EnumRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -628,10 +631,13 @@ public func _bjs_ComplexResultRoundtrip_deinit(_ pointer: UnsafeMutableRawPointe #endif } -extension ComplexResultRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ComplexResultRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ComplexResultRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ComplexResultRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -688,10 +694,13 @@ public func _bjs_StringRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> V #endif } -extension StringRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension StringRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_StringRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_StringRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -815,10 +824,13 @@ public func _bjs_OptionalReturnRoundtrip_deinit(_ pointer: UnsafeMutableRawPoint #endif } -extension OptionalReturnRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension OptionalReturnRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_OptionalReturnRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_OptionalReturnRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -982,10 +994,13 @@ public func _bjs_StructRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> V #endif } -extension StructRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension StructRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_StructRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_StructRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -1126,10 +1141,13 @@ public func _bjs_SimpleClass_deinit(_ pointer: UnsafeMutableRawPointer) -> Void #endif } -extension SimpleClass: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension SimpleClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_SimpleClass_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_SimpleClass_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -1228,10 +1246,13 @@ public func _bjs_AddressClass_deinit(_ pointer: UnsafeMutableRawPointer) -> Void #endif } -extension AddressClass: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension AddressClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_AddressClass_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_AddressClass_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -1331,10 +1352,13 @@ public func _bjs_ClassRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension ClassRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ClassRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClassRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -1691,10 +1715,13 @@ public func _bjs_ArrayRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension ArrayRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ArrayRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ArrayRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ArrayRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index f1baf3aa1..056c1c27d 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift @@ -209,10 +209,13 @@ public func _bjs_PlayBridgeJS_deinit(_ pointer: UnsafeMutableRawPointer) -> Void #endif } -extension PlayBridgeJS: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PlayBridgeJS: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PlayBridgeJS_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PlayBridgeJS_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index dbe4a1312..8ccbbee76 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -167,12 +167,7 @@ public class ExportSwift { private func protocolCastSuffix(for returnType: BridgeType) -> (prefix: String, suffix: String) { switch returnType { case .swiftProtocol: - return ("", " as! \(returnType.swiftType)") - case .nullable(let wrappedType, _): - if case .swiftProtocol = wrappedType { - return ("(", ").flatMap { $0 as? \(wrappedType.swiftType) }") - } - return ("", "") + return ("", " as! _BridgedSwiftProtocolExportable") default: return ("", "") } @@ -311,6 +306,23 @@ public class ExportSwift { for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") { append(stmt) } + case .dictionary(.swiftProtocol): + let stackCodegen = StackCodegen() + for stmt in stackCodegen.lowerStatements(for: returnType, accessor: "ret", varPrefix: "ret") { + append(stmt) + } + case .swiftProtocol: + append("return ret.bridgeJSLowerAsProtocolReturn()") + case .nullable(.swiftProtocol, _): + append( + """ + if let ret { + _swift_js_return_optional_object(1, (ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + _swift_js_return_optional_object(0, 0) + } + """ + ) default: append("return ret.bridgeJSLowerReturn()") } @@ -703,10 +715,13 @@ public class ExportSwift { // If the class has an explicit access control, we need to add it to the extension declaration. let accessControl = klass.explicitAccessControl.map { "\($0) " } ?? "" let extensionDecl: DeclSyntax = """ - extension \(raw: klass.swiftCallName): ConvertibleToJSValue, _BridgedSwiftHeapObject { + extension \(raw: klass.swiftCallName): ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { \(raw: accessControl)var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: \(raw: wrapFunctionName)(Unmanaged.passRetained(self).toOpaque())))) } + \(raw: accessControl)consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + \(raw: wrapFunctionName)(Unmanaged.passRetained(self).toOpaque()) + } } """ // Build common function signature @@ -781,7 +796,9 @@ struct StackCodegen { case .jsObject(_?): return ["\(raw: accessor).jsObject.bridgeJSStackPush()"] case .swiftProtocol: - return ["(\(raw: accessor) as! \(raw: type.swiftType)).bridgeJSStackPush()"] + return [ + "_swift_js_push_i32((\(raw: accessor) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" + ] case .void, .namespaceEnum: return [] case .array(let elementType): @@ -798,7 +815,7 @@ struct StackCodegen { ) -> [CodeBlockItemSyntax] { switch elementType { case .swiftProtocol: - return ["\(raw: accessor).map { $0 as! \(raw: elementType.swiftType) }.bridgeJSStackPush()"] + return lowerProtocolArrayStatements(accessor: accessor, varPrefix: varPrefix) case .void, .namespaceEnum: fatalError("Invalid array element type: \(elementType)") default: @@ -806,6 +823,21 @@ struct StackCodegen { } } + private func lowerProtocolArrayStatements( + accessor: String, + varPrefix: String + ) -> [CodeBlockItemSyntax] { + var statements: [CodeBlockItemSyntax] = [] + let elemVar = "__bjs_elem_\(varPrefix)" + statements.append("for \(raw: elemVar) in \(raw: accessor) {") + statements.append( + " _swift_js_push_i32((\(raw: elemVar) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" + ) + statements.append("}") + statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))") + return statements + } + private func lowerDictionaryStatements( valueType: BridgeType, accessor: String, @@ -815,7 +847,7 @@ struct StackCodegen { case .jsObject(let className?) where className != "JSObject": return ["\(raw: accessor).mapValues { $0.jsObject }.bridgeJSStackPush()"] case .swiftProtocol: - return ["\(raw: accessor).mapValues { $0 as! \(raw: valueType.swiftType) }.bridgeJSStackPush()"] + return lowerProtocolDictionaryStatements(accessor: accessor, varPrefix: varPrefix) case .nullable, .closure: return lowerDictionaryStatementsInline( valueType: valueType, @@ -862,6 +894,22 @@ struct StackCodegen { statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))") return statements } + + private func lowerProtocolDictionaryStatements( + accessor: String, + varPrefix: String + ) -> [CodeBlockItemSyntax] { + var statements: [CodeBlockItemSyntax] = [] + let pairVar = "__bjs_kv_\(varPrefix)" + statements.append("for \(raw: pairVar) in \(raw: accessor) {") + statements.append(" \(raw: pairVar).key.bridgeJSStackPush()") + statements.append( + " _swift_js_push_i32((\(raw: pairVar).value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" + ) + statements.append("}") + statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))") + return statements + } } // MARK: - EnumCodegen diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift index 0d95a5b7f..cf65635d9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift @@ -414,10 +414,13 @@ public func _bjs_Item_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Item: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Item: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Item_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Item_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -477,10 +480,13 @@ public func _bjs_MultiArrayContainer_deinit(_ pointer: UnsafeMutableRawPointer) #endif } -extension MultiArrayContainer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension MultiArrayContainer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_MultiArrayContainer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_MultiArrayContainer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.swift index 4dda325bf..d12d48eef 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.swift @@ -52,10 +52,13 @@ public func _bjs_FunctionA_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -112,10 +115,13 @@ public func _bjs_FunctionB_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.swift index fcf84a88f..bf720af76 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.swift @@ -51,10 +51,13 @@ public func _bjs_FunctionB_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension FunctionB: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_FunctionB_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -112,10 +115,13 @@ public func _bjs_FunctionA_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension FunctionA: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_FunctionA_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.swift index 2868156a4..7c43c393f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.swift @@ -29,10 +29,13 @@ public func _bjs_ClassA_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension ClassA: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ClassA: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassA_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClassA_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -68,10 +71,13 @@ public func _bjs_ClassB_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension ClassB: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ClassB: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassB_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClassB_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.swift index 09070a16f..c381c7cab 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.swift @@ -19,10 +19,13 @@ public func _bjs_ClassB_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension ClassB: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ClassB: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassB_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClassB_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -68,10 +71,13 @@ public func _bjs_ClassA_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension ClassA: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ClassA: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassA_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClassA_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift index df4969fa6..4c527315b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift @@ -428,10 +428,13 @@ public func _bjs_DefaultGreeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension DefaultGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension DefaultGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_DefaultGreeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_DefaultGreeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -467,10 +470,13 @@ public func _bjs_EmptyGreeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void #endif } -extension EmptyGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension EmptyGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_EmptyGreeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_EmptyGreeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -611,10 +617,13 @@ public func _bjs_ConstructorDefaults_deinit(_ pointer: UnsafeMutableRawPointer) #endif } -extension ConstructorDefaults: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ConstructorDefaults: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ConstructorDefaults_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ConstructorDefaults_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift index 742619f39..dc0a54bcf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift @@ -63,10 +63,13 @@ public func _bjs_Box_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Box: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Box: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Box_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Box_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift index fc3a18453..1112fb5a4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift @@ -612,10 +612,13 @@ public func _bjs_User_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension User: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension User: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_User_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_User_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift index d4dfa57a9..1a8608246 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift @@ -182,10 +182,13 @@ public func _bjs_Utils_Converter_deinit(_ pointer: UnsafeMutableRawPointer) -> V #endif } -extension Utils.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Utils.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Utils_Converter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Utils_Converter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -231,10 +234,13 @@ public func _bjs_Networking_API_HTTPServer_deinit(_ pointer: UnsafeMutableRawPoi #endif } -extension Networking.API.HTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Networking.API.HTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Networking_API_HTTPServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Networking_API_HTTPServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -280,10 +286,13 @@ public func _bjs_Networking_APIV2_Internal_TestServer_deinit(_ pointer: UnsafeMu #endif } -extension Internal.TestServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Internal.TestServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Networking_APIV2_Internal_TestServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Networking_APIV2_Internal_TestServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -330,10 +339,13 @@ public func _bjs_Formatting_Converter_deinit(_ pointer: UnsafeMutableRawPointer) #endif } -extension Formatting.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Formatting.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Formatting_Converter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Formatting_Converter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift index d4dfa57a9..1a8608246 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift @@ -182,10 +182,13 @@ public func _bjs_Utils_Converter_deinit(_ pointer: UnsafeMutableRawPointer) -> V #endif } -extension Utils.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Utils.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Utils_Converter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Utils_Converter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -231,10 +234,13 @@ public func _bjs_Networking_API_HTTPServer_deinit(_ pointer: UnsafeMutableRawPoi #endif } -extension Networking.API.HTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Networking.API.HTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Networking_API_HTTPServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Networking_API_HTTPServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -280,10 +286,13 @@ public func _bjs_Networking_APIV2_Internal_TestServer_deinit(_ pointer: UnsafeMu #endif } -extension Internal.TestServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Internal.TestServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Networking_APIV2_Internal_TestServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Networking_APIV2_Internal_TestServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -330,10 +339,13 @@ public func _bjs_Formatting_Converter_deinit(_ pointer: UnsafeMutableRawPointer) #endif } -extension Formatting.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Formatting.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Formatting_Converter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Formatting_Converter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.swift index ba7fee7af..1ce288202 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.swift @@ -137,10 +137,13 @@ public func _bjs_JSValueHolder_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension JSValueHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension JSValueHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_JSValueHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_JSValueHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.swift index 802a09638..feaa7012c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.swift @@ -41,10 +41,13 @@ public func _bjs_GlobalAPI_GlobalClass_deinit(_ pointer: UnsafeMutableRawPointer #endif } -extension GlobalClass: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension GlobalClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_GlobalAPI_GlobalClass_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_GlobalAPI_GlobalClass_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.swift index 50dc9e778..184096f29 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.swift @@ -41,10 +41,13 @@ public func _bjs_PrivateAPI_PrivateClass_deinit(_ pointer: UnsafeMutableRawPoint #endif } -extension PrivateClass: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PrivateClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PrivateAPI_PrivateClass_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PrivateAPI_PrivateClass_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift index d376a2a54..86f0b8478 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift @@ -52,10 +52,13 @@ public func _bjs___Swift_Foundation_Greeter_deinit(_ pointer: UnsafeMutableRawPo #endif } -extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs___Swift_Foundation_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs___Swift_Foundation_Greeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -102,10 +105,13 @@ public func _bjs_Utils_Converters_Converter_deinit(_ pointer: UnsafeMutableRawPo #endif } -extension Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Utils_Converters_Converter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Utils_Converters_Converter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -141,10 +147,13 @@ public func _bjs___Swift_Foundation_UUID_deinit(_ pointer: UnsafeMutableRawPoint #endif } -extension UUID: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension UUID: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs___Swift_Foundation_UUID_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs___Swift_Foundation_UUID_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -201,10 +210,13 @@ public func _bjs_Collections_Container_deinit(_ pointer: UnsafeMutableRawPointer #endif } -extension Container: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Container: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Collections_Container_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Collections_Container_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift index d376a2a54..86f0b8478 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift @@ -52,10 +52,13 @@ public func _bjs___Swift_Foundation_Greeter_deinit(_ pointer: UnsafeMutableRawPo #endif } -extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs___Swift_Foundation_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs___Swift_Foundation_Greeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -102,10 +105,13 @@ public func _bjs_Utils_Converters_Converter_deinit(_ pointer: UnsafeMutableRawPo #endif } -extension Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Utils_Converters_Converter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Utils_Converters_Converter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -141,10 +147,13 @@ public func _bjs___Swift_Foundation_UUID_deinit(_ pointer: UnsafeMutableRawPoint #endif } -extension UUID: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension UUID: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs___Swift_Foundation_UUID_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs___Swift_Foundation_UUID_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -201,10 +210,13 @@ public func _bjs_Collections_Container_deinit(_ pointer: UnsafeMutableRawPointer #endif } -extension Container: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Container: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Collections_Container_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Collections_Container_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift index ca1078836..8207bd488 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift @@ -226,10 +226,13 @@ public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -328,10 +331,13 @@ public func _bjs_OptionalPropertyHolder_deinit(_ pointer: UnsafeMutableRawPointe #endif } -extension OptionalPropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension OptionalPropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_OptionalPropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_OptionalPropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.swift index de59f5166..1c7c8350f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.swift @@ -328,10 +328,13 @@ public func _bjs_PropertyHolder_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension PropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index d9cd22836..cf7464cc3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -697,7 +697,9 @@ extension Priority: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { public func _bjs_processDelegates() -> Void { #if arch(wasm32) let ret = processDelegates(_: [AnyMyViewControllerDelegate].bridgeJSStackPop()) - ret.map { $0 as! AnyMyViewControllerDelegate }.bridgeJSStackPush() + for __bjs_elem_ret in ret { + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") #endif @@ -755,10 +757,13 @@ public func _bjs_Helper_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Helper: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Helper: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Helper_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Helper_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -850,8 +855,8 @@ public func _bjs_MyViewController_sendHelper(_ _self: UnsafeMutableRawPointer, _ @_cdecl("bjs_MyViewController_delegate_get") public func _bjs_MyViewController_delegate_get(_ _self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = MyViewController.bridgeJSLiftParameter(_self).delegate as! AnyMyViewControllerDelegate - return ret.bridgeJSLowerReturn() + let ret = MyViewController.bridgeJSLiftParameter(_self).delegate as! _BridgedSwiftProtocolExportable + return ret.bridgeJSLowerAsProtocolReturn() #else fatalError("Only available on WebAssembly") #endif @@ -871,8 +876,12 @@ public func _bjs_MyViewController_delegate_set(_ _self: UnsafeMutableRawPointer, @_cdecl("bjs_MyViewController_secondDelegate_get") public func _bjs_MyViewController_secondDelegate_get(_ _self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = (MyViewController.bridgeJSLiftParameter(_self).secondDelegate).flatMap { $0 as? AnyMyViewControllerDelegate } - return ret.bridgeJSLowerReturn() + let ret = MyViewController.bridgeJSLiftParameter(_self).secondDelegate + if let ret { + _swift_js_return_optional_object(1, (ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + _swift_js_return_optional_object(0, 0) + } #else fatalError("Only available on WebAssembly") #endif @@ -898,10 +907,13 @@ public func _bjs_MyViewController_deinit(_ pointer: UnsafeMutableRawPointer) -> #endif } -extension MyViewController: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension MyViewController: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_MyViewController_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_MyViewController_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -942,7 +954,9 @@ public func _bjs_DelegateManager_notifyAll(_ _self: UnsafeMutableRawPointer) -> public func _bjs_DelegateManager_delegates_get(_ _self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) let ret = DelegateManager.bridgeJSLiftParameter(_self).delegates - ret.map { $0 as! AnyMyViewControllerDelegate }.bridgeJSStackPush() + for __bjs_elem_ret in ret { + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") #endif @@ -968,10 +982,13 @@ public func _bjs_DelegateManager_deinit(_ pointer: UnsafeMutableRawPointer) -> V #endif } -extension DelegateManager: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension DelegateManager: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_DelegateManager_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_DelegateManager_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index b6d35a215..60d7fa83c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -144,10 +144,13 @@ public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension MathUtils: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension MathUtils: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_MathUtils_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_MathUtils_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index b6d35a215..60d7fa83c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -144,10 +144,13 @@ public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension MathUtils: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension MathUtils: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_MathUtils_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_MathUtils_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift index 43b1861ca..faec8821b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift @@ -319,10 +319,13 @@ public func _bjs_PropertyClass_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension PropertyClass: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PropertyClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PropertyClass_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PropertyClass_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift index 43b1861ca..faec8821b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift @@ -319,10 +319,13 @@ public func _bjs_PropertyClass_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension PropertyClass: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PropertyClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PropertyClass_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PropertyClass_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index 0e9434832..aab0eb308 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -71,10 +71,13 @@ public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -99,10 +102,13 @@ public func _bjs_PublicGreeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension PublicGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PublicGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { public var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PublicGreeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + public consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PublicGreeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -127,10 +133,13 @@ public func _bjs_PackageGreeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension PackageGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PackageGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { package var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PackageGreeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + package consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PackageGreeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index e2cf9e09b..472987fee 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -1610,10 +1610,13 @@ public func _bjs_Person_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Person: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Person: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { public var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Person_wrap(Unmanaged.passRetained(self).toOpaque())))) } + public consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Person_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -1649,10 +1652,13 @@ public func _bjs_TestProcessor_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension TestProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension TestProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_TestProcessor_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_TestProcessor_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 6fccb3280..236937db9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -508,10 +508,13 @@ public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index f2b2b6c34..9ef28f844 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -567,7 +567,7 @@ extension _JSBridgedClass { /// A protocol that Swift protocol wrappers exposed from JavaScript must conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. -public protocol _BridgedSwiftProtocolWrapper: _BridgedSwiftStackType { +public protocol _BridgedSwiftProtocolWrapper: _BridgedSwiftStackType, _BridgedSwiftProtocolExportable { var jsObject: JSObject { get } static func bridgeJSLiftParameter(_ value: Int32) -> Self } @@ -595,6 +595,21 @@ extension _BridgedSwiftProtocolWrapper { } } +/// A protocol that allows any BridgeJS-exported type to be lowered to a JSObject ID +/// for protocol existential bridging in the Swift-to-JS direction. +/// +/// Both `_BridgedSwiftProtocolWrapper` (JS-originated protocol objects) and `@JS class` +/// types conform to this, enabling runtime dispatch when a protocol existential is returned. +public protocol _BridgedSwiftProtocolExportable { + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 +} + +extension _BridgedSwiftProtocolExportable where Self: _BridgedSwiftProtocolWrapper { + @_spi(BridgeJS) public consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + jsObject.bridgeJSLowerReturn() + } +} + /// A protocol that Swift enum types that do not have a payload can conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. @@ -1023,7 +1038,7 @@ private func _swift_js_return_optional_object_extern(_ isSome: Int32, _ objectId _onlyAvailableOnWasm() } #endif -@inline(never) func _swift_js_return_optional_object(_ isSome: Int32, _ objectId: Int32) { +@_spi(BridgeJS) @inline(never) public func _swift_js_return_optional_object(_ isSome: Int32, _ objectId: Int32) { _swift_js_return_optional_object_extern(isSome, objectId) } diff --git a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift index a892720ce..7816681da 100644 --- a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift @@ -207,10 +207,13 @@ public func _bjs_GlobalNetworking_API_TestHTTPServer_deinit(_ pointer: UnsafeMut #endif } -extension GlobalNetworking.API.TestHTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension GlobalNetworking.API.TestHTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_GlobalNetworking_API_TestHTTPServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_GlobalNetworking_API_TestHTTPServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -256,10 +259,13 @@ public func _bjs_GlobalNetworking_APIV2_Internal_TestInternalServer_deinit(_ poi #endif } -extension Internal.TestInternalServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Internal.TestInternalServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_GlobalNetworking_APIV2_Internal_TestInternalServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_GlobalNetworking_APIV2_Internal_TestInternalServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -327,10 +333,13 @@ public func _bjs_GlobalUtils_PublicConverter_deinit(_ pointer: UnsafeMutableRawP #endif } -extension GlobalUtils.PublicConverter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension GlobalUtils.PublicConverter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_GlobalUtils_PublicConverter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_GlobalUtils_PublicConverter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index c8ebbc8ce..6407a175b 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -1026,6 +1026,36 @@ enum GraphOperations { } } +@JS class ProtocolReturnTests { + @JS static func createNativeProcessor() -> DataProcessor { + return SwiftDataProcessor() + } + + @JS static func createNativeProcessorOptional() -> DataProcessor? { + return SwiftDataProcessor() + } + + @JS static func createNativeProcessorNil() -> DataProcessor? { + return nil + } + + @JS static func createNativeProcessorArray() -> [DataProcessor] { + let p1 = SwiftDataProcessor() + p1.count = 10 + let p2 = SwiftDataProcessor() + p2.count = 20 + return [p1, p2] + } + + @JS static func createNativeProcessorDictionary() -> [String: DataProcessor] { + let p1 = SwiftDataProcessor() + p1.count = 10 + let p2 = SwiftDataProcessor() + p2.count = 20 + return ["first": p1, "second": p2] + } +} + // MARK: - Closure Tests // @JS func makeFormatter(prefix: String) -> (String) -> String { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 13aab1455..db3132c37 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -2467,7 +2467,9 @@ public func _bjs_ArraySupportExports_static_roundTripNamespacedSwiftClassArray() public func _bjs_ArraySupportExports_static_roundTripProtocolArray() -> Void { #if arch(wasm32) let ret = ArraySupportExports.roundTripProtocolArray(_: [AnyArrayElementProtocol].bridgeJSStackPop()) - ret.map { $0 as! AnyArrayElementProtocol }.bridgeJSStackPush() + for __bjs_elem_ret in ret { + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") #endif @@ -6685,10 +6687,13 @@ public func _bjs_ClosureSupportExports_deinit(_ pointer: UnsafeMutableRawPointer #endif } -extension ClosureSupportExports: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension ClosureSupportExports: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_ClosureSupportExports_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClosureSupportExports_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -6840,10 +6845,13 @@ public func _bjs_DefaultArgumentConstructorDefaults_deinit(_ pointer: UnsafeMuta #endif } -extension DefaultArgumentConstructorDefaults: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension DefaultArgumentConstructorDefaults: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_DefaultArgumentConstructorDefaults_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_DefaultArgumentConstructorDefaults_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -6976,10 +6984,13 @@ public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { public var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + public consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7026,10 +7037,13 @@ public func _bjs_Calculator_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Calculator: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Calculator: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Calculator_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Calculator_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7054,10 +7068,13 @@ public func _bjs_InternalGreeter_deinit(_ pointer: UnsafeMutableRawPointer) -> V #endif } -extension InternalGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension InternalGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { internal var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_InternalGreeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + internal consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_InternalGreeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7082,10 +7099,13 @@ public func _bjs_PublicGreeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension PublicGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PublicGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { public var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PublicGreeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + public consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PublicGreeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7110,10 +7130,13 @@ public func _bjs_PackageGreeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension PackageGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PackageGreeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { package var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PackageGreeter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + package consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PackageGreeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7181,10 +7204,13 @@ public func _bjs_Utils_Converter_deinit(_ pointer: UnsafeMutableRawPointer) -> V #endif } -extension Utils.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Utils.Converter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Utils_Converter_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Utils_Converter_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7230,10 +7256,13 @@ public func _bjs_Networking_API_HTTPServer_deinit(_ pointer: UnsafeMutableRawPoi #endif } -extension Networking.API.HTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Networking.API.HTTPServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Networking_API_HTTPServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Networking_API_HTTPServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7280,10 +7309,13 @@ public func _bjs___Swift_Foundation_UUID_deinit(_ pointer: UnsafeMutableRawPoint #endif } -extension UUID: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension UUID: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs___Swift_Foundation_UUID_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs___Swift_Foundation_UUID_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7329,10 +7361,13 @@ public func _bjs_Networking_APIV2_Internal_TestServer_deinit(_ pointer: UnsafeMu #endif } -extension Internal.TestServer: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Internal.TestServer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Networking_APIV2_Internal_TestServer_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Networking_APIV2_Internal_TestServer_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7389,10 +7424,13 @@ public func _bjs_SimplePropertyHolder_deinit(_ pointer: UnsafeMutableRawPointer) #endif } -extension SimplePropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension SimplePropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_SimplePropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_SimplePropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7715,10 +7753,13 @@ public func _bjs_PropertyHolder_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension PropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension PropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_PropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_PropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -7765,10 +7806,13 @@ public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension MathUtils: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension MathUtils: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_MathUtils_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_MathUtils_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -8015,10 +8059,13 @@ public func _bjs_StaticPropertyHolder_deinit(_ pointer: UnsafeMutableRawPointer) #endif } -extension StaticPropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension StaticPropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_StaticPropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_StaticPropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -8259,8 +8306,8 @@ public func _bjs_DataProcessorManager_setProcessorAPIResult(_ _self: UnsafeMutab @_cdecl("bjs_DataProcessorManager_processor_get") public func _bjs_DataProcessorManager_processor_get(_ _self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = DataProcessorManager.bridgeJSLiftParameter(_self).processor as! AnyDataProcessor - return ret.bridgeJSLowerReturn() + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).processor as! _BridgedSwiftProtocolExportable + return ret.bridgeJSLowerAsProtocolReturn() #else fatalError("Only available on WebAssembly") #endif @@ -8280,8 +8327,12 @@ public func _bjs_DataProcessorManager_processor_set(_ _self: UnsafeMutableRawPoi @_cdecl("bjs_DataProcessorManager_backupProcessor_get") public func _bjs_DataProcessorManager_backupProcessor_get(_ _self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = (DataProcessorManager.bridgeJSLiftParameter(_self).backupProcessor).flatMap { $0 as? AnyDataProcessor } - return ret.bridgeJSLowerReturn() + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).backupProcessor + if let ret { + _swift_js_return_optional_object(1, (ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + _swift_js_return_optional_object(0, 0) + } #else fatalError("Only available on WebAssembly") #endif @@ -8307,10 +8358,13 @@ public func _bjs_DataProcessorManager_deinit(_ pointer: UnsafeMutableRawPointer) #endif } -extension DataProcessorManager: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension DataProcessorManager: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_DataProcessorManager_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_DataProcessorManager_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -8664,10 +8718,13 @@ public func _bjs_SwiftDataProcessor_deinit(_ pointer: UnsafeMutableRawPointer) - #endif } -extension SwiftDataProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension SwiftDataProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_SwiftDataProcessor_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_SwiftDataProcessor_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -8682,6 +8739,105 @@ fileprivate func _bjs_SwiftDataProcessor_wrap_extern(_ pointer: UnsafeMutableRaw return _bjs_SwiftDataProcessor_wrap_extern(pointer) } +@_expose(wasm, "bjs_ProtocolReturnTests_static_createNativeProcessor") +@_cdecl("bjs_ProtocolReturnTests_static_createNativeProcessor") +public func _bjs_ProtocolReturnTests_static_createNativeProcessor() -> Int32 { + #if arch(wasm32) + let ret = ProtocolReturnTests.createNativeProcessor() as! _BridgedSwiftProtocolExportable + return ret.bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ProtocolReturnTests_static_createNativeProcessorOptional") +@_cdecl("bjs_ProtocolReturnTests_static_createNativeProcessorOptional") +public func _bjs_ProtocolReturnTests_static_createNativeProcessorOptional() -> Void { + #if arch(wasm32) + let ret = ProtocolReturnTests.createNativeProcessorOptional() + if let ret { + _swift_js_return_optional_object(1, (ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + _swift_js_return_optional_object(0, 0) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ProtocolReturnTests_static_createNativeProcessorNil") +@_cdecl("bjs_ProtocolReturnTests_static_createNativeProcessorNil") +public func _bjs_ProtocolReturnTests_static_createNativeProcessorNil() -> Void { + #if arch(wasm32) + let ret = ProtocolReturnTests.createNativeProcessorNil() + if let ret { + _swift_js_return_optional_object(1, (ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + _swift_js_return_optional_object(0, 0) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ProtocolReturnTests_static_createNativeProcessorArray") +@_cdecl("bjs_ProtocolReturnTests_static_createNativeProcessorArray") +public func _bjs_ProtocolReturnTests_static_createNativeProcessorArray() -> Void { + #if arch(wasm32) + let ret = ProtocolReturnTests.createNativeProcessorArray() + for __bjs_elem_ret in ret { + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32(Int32(ret.count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ProtocolReturnTests_static_createNativeProcessorDictionary") +@_cdecl("bjs_ProtocolReturnTests_static_createNativeProcessorDictionary") +public func _bjs_ProtocolReturnTests_static_createNativeProcessorDictionary() -> Void { + #if arch(wasm32) + let ret = ProtocolReturnTests.createNativeProcessorDictionary() + for __bjs_kv_ret in ret { + __bjs_kv_ret.key.bridgeJSStackPush() + _swift_js_push_i32((__bjs_kv_ret.value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32(Int32(ret.count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ProtocolReturnTests_deinit") +@_cdecl("bjs_ProtocolReturnTests_deinit") +public func _bjs_ProtocolReturnTests_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension ProtocolReturnTests: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_ProtocolReturnTests_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ProtocolReturnTests_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ProtocolReturnTests_wrap") +fileprivate func _bjs_ProtocolReturnTests_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_ProtocolReturnTests_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_ProtocolReturnTests_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_ProtocolReturnTests_wrap_extern(pointer) +} + @_expose(wasm, "bjs_TextProcessor_init") @_cdecl("bjs_TextProcessor_init") public func _bjs_TextProcessor_init(_ transform: Int32) -> UnsafeMutableRawPointer { @@ -8923,10 +9079,13 @@ public func _bjs_TextProcessor_deinit(_ pointer: UnsafeMutableRawPointer) -> Voi #endif } -extension TextProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension TextProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_TextProcessor_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_TextProcessor_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -9004,10 +9163,13 @@ public func _bjs_OptionalHolder_deinit(_ pointer: UnsafeMutableRawPointer) -> Vo #endif } -extension OptionalHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension OptionalHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_OptionalHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_OptionalHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -9106,10 +9268,13 @@ public func _bjs_OptionalPropertyHolder_deinit(_ pointer: UnsafeMutableRawPointe #endif } -extension OptionalPropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension OptionalPropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_OptionalPropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_OptionalPropertyHolder_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -9189,10 +9354,13 @@ public func _bjs_Container_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension Container: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension Container: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_Container_wrap(Unmanaged.passRetained(self).toOpaque())))) } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Container_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) @@ -9228,10 +9396,13 @@ public func _bjs_LeakCheck_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { #endif } -extension LeakCheck: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension LeakCheck: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { public var jsValue: JSValue { return .object(JSObject(id: UInt32(bitPattern: _bjs_LeakCheck_wrap(Unmanaged.passRetained(self).toOpaque())))) } + public consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_LeakCheck_wrap(Unmanaged.passRetained(self).toOpaque()) + } } #if arch(wasm32) diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 746e0cd3c..da05bc5ae 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -2577,6 +2577,143 @@ ], "swiftCallName" : "SwiftDataProcessor" }, + { + "methods" : [ + { + "abiName" : "bjs_ProtocolReturnTests_static_createNativeProcessor", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "createNativeProcessor", + "parameters" : [ + + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + }, + "staticContext" : { + "className" : { + "_0" : "ProtocolReturnTests" + } + } + }, + { + "abiName" : "bjs_ProtocolReturnTests_static_createNativeProcessorOptional", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "createNativeProcessorOptional", + "parameters" : [ + + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + }, + "_1" : "null" + } + }, + "staticContext" : { + "className" : { + "_0" : "ProtocolReturnTests" + } + } + }, + { + "abiName" : "bjs_ProtocolReturnTests_static_createNativeProcessorNil", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "createNativeProcessorNil", + "parameters" : [ + + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + }, + "_1" : "null" + } + }, + "staticContext" : { + "className" : { + "_0" : "ProtocolReturnTests" + } + } + }, + { + "abiName" : "bjs_ProtocolReturnTests_static_createNativeProcessorArray", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "createNativeProcessorArray", + "parameters" : [ + + ], + "returnType" : { + "array" : { + "_0" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + } + }, + "staticContext" : { + "className" : { + "_0" : "ProtocolReturnTests" + } + } + }, + { + "abiName" : "bjs_ProtocolReturnTests_static_createNativeProcessorDictionary", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "createNativeProcessorDictionary", + "parameters" : [ + + ], + "returnType" : { + "dictionary" : { + "_0" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + } + }, + "staticContext" : { + "className" : { + "_0" : "ProtocolReturnTests" + } + } + } + ], + "name" : "ProtocolReturnTests", + "properties" : [ + + ], + "swiftCallName" : "ProtocolReturnTests" + }, { "constructor" : { "abiName" : "bjs_TextProcessor_init", diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 4c211e91c..ca2da4324 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -1409,4 +1409,38 @@ function testProtocolSupport(exports) { managerWithOptional.release(); swiftBackup.release(); + + const nativeProcessor = exports.ProtocolReturnTests.createNativeProcessor(); + assert.notEqual(nativeProcessor, undefined, "createNativeProcessor should return a value"); + assert.equal(typeof nativeProcessor.increment, "function", "should have increment method"); + nativeProcessor.increment(1); + assert.equal(nativeProcessor.count, 1, "count should be 1 after increment"); + nativeProcessor.release(); + + const optProcessor = exports.ProtocolReturnTests.createNativeProcessorOptional(); + assert.notEqual(optProcessor, null, "optional processor should not be null"); + optProcessor.increment(1); + assert.equal(optProcessor.count, 1, "optional processor count should be 1 after increment"); + optProcessor.release(); + + const nilProcessor = exports.ProtocolReturnTests.createNativeProcessorNil(); + assert.equal(nilProcessor, null, "nil processor should be null"); + + const nativeArray = exports.ProtocolReturnTests.createNativeProcessorArray(); + assert.equal(nativeArray.length, 2, "array should have 2 elements"); + assert.equal(nativeArray[0].count, 10, "first element count should be 10"); + assert.equal(nativeArray[1].count, 20, "second element count should be 20"); + nativeArray[0].increment(1); + assert.equal(nativeArray[0].count, 11, "first element count should be 11 after increment"); + nativeArray[0].release(); + nativeArray[1].release(); + + const nativeDict = exports.ProtocolReturnTests.createNativeProcessorDictionary(); + assert.notEqual(nativeDict, undefined, "dictionary should not be undefined"); + assert.equal(nativeDict["first"].count, 10, "first entry count should be 10"); + assert.equal(nativeDict["second"].count, 20, "second entry count should be 20"); + nativeDict["first"].increment(5); + assert.equal(nativeDict["first"].count, 15, "first entry count should be 15 after increment"); + nativeDict["first"].release(); + nativeDict["second"].release(); } From 4c1c32caa352f512142ef62b1015d506acf726fb Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 11 Mar 2026 19:52:52 +0800 Subject: [PATCH 13/68] Fix CI: update snapshots, formatting, runtime test, add docs and review feedback --- .../BridgeJSCore/SwiftToSkeleton.swift | 14 +++++- .../BridgeJSLinkTests/SwiftStruct.d.ts | 7 ++- .../BridgeJSLinkTests/SwiftStruct.js | 41 +++++++++++++--- .../Exporting-Swift/Exporting-Swift-Class.md | 48 +++++++++++++++++++ .../Exporting-Swift/Exporting-Swift-Enum.md | 1 + .../Exporting-Swift/Exporting-Swift-Struct.md | 1 + .../JSClosure+AsyncTests.swift | 6 +-- Tests/prelude.mjs | 2 +- 8 files changed, 107 insertions(+), 13 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 2ff5cecba..a28192d4b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -1425,7 +1425,12 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } - /// Walks extension members under the matching type’s state, returning whether the type was found + /// Walks extension members under the matching type’s state, returning whether the type was found. + /// + /// Note: The lookup scans dictionaries keyed by `makeKey(name:namespace:)`, matching only by + /// plain name. If two types share a name but differ by namespace, `.first(where:)` picks + /// whichever comes first. This is acceptable today since namespace collisions are unlikely, + /// but may need refinement if namespace-qualified extension resolution is added. func resolveExtension(_ ext: ExtensionDeclSyntax) -> Bool { let name = ext.extendedType.trimmedDescription let state: State @@ -1435,6 +1440,13 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { state = .structBody(name: name, key: entry.key) } else if let entry = exportedEnumByName.first(where: { $0.value.name == name }) { state = .enumBody(name: name, key: entry.key) + } else if exportedProtocolByName.values.contains(where: { $0.name == name }) { + diagnose( + node: ext.extendedType, + message: "Protocol extensions are not supported by BridgeJS.", + hint: "You cannot extend `@JS` protocol '\(name)' with additional members" + ) + return true } else { return false } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts index 211661d5f..bf4ebc71f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -16,7 +16,6 @@ export interface DataPoint { label: string; optCount: number | null; optFlag: boolean | null; - distanceFromOrigin(): number; } export interface Address { street: string; @@ -44,6 +43,12 @@ export interface Container { object: any; optionalObject: any | null; } +export interface Vector2D { + dx: number; + dy: number; + magnitude(): number; + scaled(factor: number): Vector2D; +} export type PrecisionObject = typeof PrecisionValues; /// Represents a Swift heap object like a class instance or an actor instance. diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index 099f4ccc3..b9889f156 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -73,13 +73,7 @@ export async function createInstantiator(options, swift) { const string = strStack.pop(); const f64 = f64Stack.pop(); const f641 = f64Stack.pop(); - const instance1 = { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; - instance1.distanceFromOrigin = function() { - structHelpers.DataPoint.lower(this); - const ret = instance.exports.bjs_DataPoint_distanceFromOrigin(); - return ret; - }.bind(instance1); - return instance1; + return { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; } }); const __bjs_createAddressHelpers = () => ({ @@ -225,6 +219,29 @@ export async function createInstantiator(options, swift) { return { object: value, optionalObject: optValue }; } }); + const __bjs_createVector2DHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.dx); + f64Stack.push(value.dy); + }, + lift: () => { + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + const instance1 = { dx: f641, dy: f64 }; + instance1.magnitude = function() { + structHelpers.Vector2D.lower(this); + const ret = instance.exports.bjs_Vector2D_magnitude(); + return ret; + }.bind(instance1); + instance1.scaled = function(factor) { + structHelpers.Vector2D.lower(this); + const ret = instance.exports.bjs_Vector2D_scaled(factor); + const structValue = structHelpers.Vector2D.lift(); + return structValue; + }.bind(instance1); + return instance1; + } + }); return { /** @@ -336,6 +353,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Container.lift(); return swift.memory.retain(value); } + bjs["swift_js_struct_lower_Vector2D"] = function(objectId) { + structHelpers.Vector2D.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Vector2D"] = function() { + const value = structHelpers.Vector2D.lift(); + return swift.memory.retain(value); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -527,6 +551,9 @@ export async function createInstantiator(options, swift) { const ContainerHelpers = __bjs_createContainerHelpers(); structHelpers.Container = ContainerHelpers; + const Vector2DHelpers = __bjs_createVector2DHelpers(); + structHelpers.Vector2D = Vector2DHelpers; + const exports = { Greeter, roundtrip: function bjs_roundtrip(session) { diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md index 9cd4a2224..a16c81286 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md @@ -77,6 +77,53 @@ export type Exports = { } ``` +## Adding Members via Extensions + +You can add exported methods, computed properties, and static members to a `@JS` class using extensions. The extension block itself does not need `@JS` - only the individual members do: + +```swift +@JS class Greeter { + @JS var name: String + + @JS init(name: String) { + self.name = name + } + + @JS func greet() -> String { + return "Hello, " + self.name + "!" + } +} + +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, " + self.name + "!!!" + } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } +} +``` + +This also works across files within the same module: + +```swift +// GreeterExtension.swift +extension Greeter { + @JS func greetFormally() -> String { + return "Good day, " + self.name + "." + } +} +``` + +All `@JS`-annotated members in extensions are merged into the same generated TypeScript interface as the original class declaration. + +> Note: Extensions must target `@JS`-annotated types from the same module. + ## How It Works Classes use **reference semantics** when crossing the Swift/JavaScript boundary: @@ -103,5 +150,6 @@ This differs from structs, which use copy semantics and transfer data by value. | Static / class properties: `static var`, `class let` | ✅ (See )| | Methods: `func` | ✅ (See ) | | Static/class methods: `static func`, `class func` | ✅ (See ) | +| Extension methods/properties | ✅ | | Subscripts: `subscript()` | ❌ | | Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md index 2220d457c..68996b27b 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md @@ -514,4 +514,5 @@ This differs from classes, which use reference semantics and share state across | Associated values: `JSObject` | ✅ | | Associated values: Arrays | ✅ | | Associated values: Optionals of all supported types | ✅ | +| Extension static functions/properties | ✅ | | Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md index 32bb79ed3..c4a9524d9 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md @@ -165,6 +165,7 @@ This differs from classes, which use reference semantics and share state across | Instance methods | ✅ | | Static methods | ✅ | | Static properties | ✅ | +| Extension methods/properties | ✅ | | Property observers (`willSet`, `didSet`) | ❌ | | Generics | ❌ | | Conformances | ❌ | diff --git a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift index e3c19a8e4..db093e549 100644 --- a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift +++ b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift @@ -72,7 +72,7 @@ class JSClosureAsyncTests: XCTestCase { )!.value() XCTAssertEqual(result, 42.0) } - + func testAsyncOneshotClosureWithPriority() async throws { let priority = UnsafeSendableBox(nil) let closure = JSOneshotClosure.async(priority: .high) { _ in @@ -83,7 +83,7 @@ class JSClosureAsyncTests: XCTestCase { XCTAssertEqual(result, 42.0) XCTAssertEqual(priority.value, .high) } - + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) func testAsyncOneshotClosureWithTaskExecutor() async throws { let executor = AnyTaskExecutor() @@ -93,7 +93,7 @@ class JSClosureAsyncTests: XCTestCase { let result = try await JSPromise(from: closure.function!())!.value() XCTAssertEqual(result, 42.0) } - + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) func testAsyncOneshotClosureWithTaskExecutorPreference() async throws { let executor = AnyTaskExecutor() diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index c5da33196..bed4ac02f 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -797,7 +797,7 @@ function testStructSupport(exports) { assert.equal(exports.DataPoint.dimensions, 2); // Test struct extension instance methods - const vec = new exports.Vector2D(3.0, 4.0); + const vec = exports.Vector2D.init(3.0, 4.0); assert.equal(vec.magnitude(), 5.0); const scaled = vec.scaled(2.0); assert.equal(scaled.dx, 6.0); From 3398ff7f622b0e5326e4eb5bdd05dfac24b8a014 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 11 Mar 2026 22:06:03 +0800 Subject: [PATCH 14/68] BridgeJS: Support protocol types in closure parameters and returns --- .../Sources/BridgeJSCore/ClosureCodegen.swift | 25 +- .../Sources/BridgeJSCore/ExportSwift.swift | 10 + .../Sources/BridgeJSCore/ImportTS.swift | 36 +- .../Inputs/MacroSwift/ProtocolInClosure.swift | 18 + .../ProtocolInClosure.json | 281 +++++++++++ .../ProtocolInClosure.swift | 388 ++++++++++++++++ .../BridgeJSLinkTests/ProtocolInClosure.d.ts | 38 ++ .../BridgeJSLinkTests/ProtocolInClosure.js | 436 ++++++++++++++++++ .../JavaScriptKit/BridgeJSIntrinsics.swift | 4 + .../BridgeJSRuntimeTests/ExportAPITests.swift | 28 ++ .../Generated/BridgeJS.swift | 300 ++++++++++++ .../Generated/JavaScript/BridgeJS.json | 183 ++++++++ .../JavaScript/ClosureSupportTests.mjs | 126 +++-- 13 files changed, 1841 insertions(+), 32 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ProtocolInClosure.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index e5648ccf7..142050f56 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -12,9 +12,9 @@ public struct ClosureCodegen { public init() {} private func swiftClosureType(for signature: ClosureSignature) -> String { - let closureParams = signature.parameters.map { "\($0.swiftType)" }.joined(separator: ", ") + let closureParams = signature.parameters.map { "\($0.closureSwiftType)" }.joined(separator: ", ") let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "") - let swiftReturnType = signature.returnType.swiftType + let swiftReturnType = signature.returnType.closureSwiftType return "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)" } @@ -158,7 +158,26 @@ public struct ClosureCodegen { printer.write(closureCallExpr.description) } else { printer.write("let result = \(closureCallExpr)") - printer.write("return result.bridgeJSLowerReturn()") + switch signature.returnType { + case .swiftProtocol: + printer.write( + "return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()" + ) + case .nullable(.swiftProtocol, _): + printer.write("if let result {") + printer.indent { + printer.write( + "_swift_js_return_optional_object(1, (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" + ) + } + printer.write("} else {") + printer.indent { + printer.write("_swift_js_return_optional_object(0, 0)") + } + printer.write("}") + default: + printer.write("return result.bridgeJSLowerReturn()") + } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 8ccbbee76..eab3a0831 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -1454,6 +1454,16 @@ extension BridgeType { } } + var closureSwiftType: String { + switch self { + case .swiftProtocol(let name): return "any \(name)" + case .nullable(let wrappedType, let kind): + let wrappedClosureType = wrappedType.closureSwiftType + return kind == .null ? "Optional<\(wrappedClosureType)>" : "JSUndefinedOr<\(wrappedClosureType)>" + default: return swiftType + } + } + var isClosureType: Bool { if case .closure = self { return true } return false diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 1b7dce434..7d9a6f087 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -163,8 +163,28 @@ public struct ImportTS { } ) ) + } else if case .nullable(.swiftProtocol, _) = param.type, context == .exportSwift { + body.write("let \(pattern): (Int32, Int32)") + body.write("if let \(param.name) {") + body.indent { + body.write( + "\(pattern) = (1, (\(param.name) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" + ) + } + body.write("} else {") + body.indent { + body.write("\(pattern) = (0, 0)") + } + body.write("}") } else { - let initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()") + let initializerExpr: ExprSyntax + if case .swiftProtocol = param.type, context == .exportSwift { + initializerExpr = ExprSyntax( + "(\(raw: param.name) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()" + ) + } else { + initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()") + } if loweringInfo.loweredParameters.isEmpty { stackLoweringStmts.insert("let _ = \(initializerExpr)", at: 0) @@ -817,7 +837,12 @@ extension BridgeType { case .swiftHeapObject: return LoweringParameterInfo(loweredParameters: [("pointer", .pointer)]) case .swiftProtocol: - throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + switch context { + case .importTS: + throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + case .exportSwift: + return LoweringParameterInfo(loweredParameters: [("objectId", .i32)]) + } case .caseEnum: switch context { case .importTS: @@ -891,7 +916,12 @@ extension BridgeType { case .swiftHeapObject: return LiftingReturnInfo(valueToLift: .pointer) case .swiftProtocol: - throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + switch context { + case .importTS: + throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") + case .exportSwift: + return LiftingReturnInfo(valueToLift: .i32) + } case .caseEnum: switch context { case .importTS: diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ProtocolInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ProtocolInClosure.swift new file mode 100644 index 000000000..cb814adf2 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ProtocolInClosure.swift @@ -0,0 +1,18 @@ +import JavaScriptKit + +@JS protocol Renderable { + func render() -> String +} + +@JS class Widget { + @JS var name: String + + @JS init(name: String) { + self.name = name + } +} + +@JS func processRenderable(_ item: Renderable, transform: (Renderable) -> String) -> String +@JS func makeRenderableFactory(defaultName: String) -> () -> Renderable +@JS func roundtripRenderable(_ callback: (Renderable) -> Renderable) -> (Renderable) -> Renderable +@JS func processOptionalRenderable(_ callback: (Renderable?) -> String) -> String diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json new file mode 100644 index 000000000..4ba7ba9a5 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json @@ -0,0 +1,281 @@ +{ + "exported" : { + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Widget_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Widget", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Widget" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_processRenderable", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processRenderable", + "parameters" : [ + { + "label" : "_", + "name" : "item", + "type" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + { + "label" : "transform", + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule10RenderableP_SS", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_makeRenderableFactory", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeRenderableFactory", + "parameters" : [ + { + "label" : "defaultName", + "name" : "defaultName", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModuley_10RenderableP", + "moduleName" : "TestModule", + "parameters" : [ + + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_roundtripRenderable", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripRenderable", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule10RenderableP_10RenderableP", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule10RenderableP_10RenderableP", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_processOptionalRenderable", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalRenderable", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModuleSq10RenderableP_SS", + "moduleName" : "TestModule", + "parameters" : [ + { + "nullable" : { + "_0" : { + "swiftProtocol" : { + "_0" : "Renderable" + } + }, + "_1" : "null" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + ], + "protocols" : [ + { + "methods" : [ + { + "abiName" : "bjs_Renderable_render", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "render", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Renderable", + "properties" : [ + + ] + } + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift new file mode 100644 index 000000000..26c3d1db0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.swift @@ -0,0 +1,388 @@ +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP") +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP") +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule10RenderableP_10RenderableP { + static func bridgeJSLift(_ callbackId: Int32) -> (any Renderable) -> any Renderable { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP(callbackValue, param0ObjectId) + return AnyRenderable.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any Renderable) -> any Renderable { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any Renderable) -> any Renderable) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP") +@_cdecl("invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP") +public func _invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any Renderable) -> any Renderable>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyRenderable.bridgeJSLiftParameter(param0)) + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule10RenderableP_SS") +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule10RenderableP_SS(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModule10RenderableP_SS_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule10RenderableP_SS") +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule10RenderableP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule10RenderableP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (any Renderable) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_TestModule_10TestModule10RenderableP_SS(callbackValue, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any Renderable) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any Renderable) -> String) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule10RenderableP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule10RenderableP_SS") +@_cdecl("invoke_swift_closure_TestModule_10TestModule10RenderableP_SS") +public func _invoke_swift_closure_TestModule_10TestModule10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any Renderable) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyRenderable.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS") +fileprivate func invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS_extern(callback, param0IsSome, param0ObjectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS") +fileprivate func make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleSq10RenderableP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0ObjectId): (Int32, Int32) + if let param0 { + (param0IsSome, param0ObjectId) = (1, (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + (param0IsSome, param0ObjectId) = (0, 0) + } + let ret = invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS(callbackValue, param0IsSome, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Optional) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS") +public func _invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuley_10RenderableP") +fileprivate func invoke_js_callback_TestModule_10TestModuley_10RenderableP_extern(_ callback: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModuley_10RenderableP_extern(_ callback: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuley_10RenderableP(_ callback: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuley_10RenderableP_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuley_10RenderableP") +fileprivate func make_swift_closure_TestModule_10TestModuley_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuley_10RenderableP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuley_10RenderableP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuley_10RenderableP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuley_10RenderableP { + static func bridgeJSLift(_ callbackId: Int32) -> () -> any Renderable { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret = invoke_js_callback_TestModule_10TestModuley_10RenderableP(callbackValue) + return AnyRenderable.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == () -> any Renderable { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping () -> any Renderable) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuley_10RenderableP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuley_10RenderableP") +@_cdecl("invoke_swift_closure_TestModule_10TestModuley_10RenderableP") +public func _invoke_swift_closure_TestModule_10TestModuley_10RenderableP(_ boxPtr: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<() -> any Renderable>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure() + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +struct AnyRenderable: Renderable, _BridgedSwiftProtocolWrapper { + let jsObject: JSObject + + func render() -> String { + let jsObjectValue = jsObject.bridgeJSLowerParameter() + let ret = _extern_render(jsObjectValue) + return String.bridgeJSLiftReturn(ret) + } + + static func bridgeJSLiftParameter(_ value: Int32) -> Self { + return AnyRenderable(jsObject: JSObject(id: UInt32(bitPattern: value))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Renderable_render") +fileprivate func _extern_render_extern(_ jsObject: Int32) -> Int32 +#else +fileprivate func _extern_render_extern(_ jsObject: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _extern_render(_ jsObject: Int32) -> Int32 { + return _extern_render_extern(jsObject) +} + +@_expose(wasm, "bjs_processRenderable") +@_cdecl("bjs_processRenderable") +public func _bjs_processRenderable(_ item: Int32, _ transform: Int32) -> Void { + #if arch(wasm32) + let ret = processRenderable(_: AnyRenderable.bridgeJSLiftParameter(item), transform: _BJS_Closure_10TestModule10RenderableP_SS.bridgeJSLift(transform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeRenderableFactory") +@_cdecl("bjs_makeRenderableFactory") +public func _bjs_makeRenderableFactory(_ defaultNameBytes: Int32, _ defaultNameLength: Int32) -> Int32 { + #if arch(wasm32) + let ret = makeRenderableFactory(defaultName: String.bridgeJSLiftParameter(defaultNameBytes, defaultNameLength)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundtripRenderable") +@_cdecl("bjs_roundtripRenderable") +public func _bjs_roundtripRenderable(_ callback: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundtripRenderable(_: _BJS_Closure_10TestModule10RenderableP_10RenderableP.bridgeJSLift(callback)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_processOptionalRenderable") +@_cdecl("bjs_processOptionalRenderable") +public func _bjs_processOptionalRenderable(_ callback: Int32) -> Void { + #if arch(wasm32) + let ret = processOptionalRenderable(_: _BJS_Closure_10TestModuleSq10RenderableP_SS.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_init") +@_cdecl("bjs_Widget_init") +public func _bjs_Widget_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Widget(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_name_get") +@_cdecl("bjs_Widget_name_get") +public func _bjs_Widget_name_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Widget.bridgeJSLiftParameter(_self).name + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_name_set") +@_cdecl("bjs_Widget_name_set") +public func _bjs_Widget_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + Widget.bridgeJSLiftParameter(_self).name = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Widget_deinit") +@_cdecl("bjs_Widget_deinit") +public func _bjs_Widget_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Widget: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Widget_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Widget_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Widget_wrap") +fileprivate func _bjs_Widget_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Widget_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Widget_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Widget_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts new file mode 100644 index 000000000..6b7a9d28d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.d.ts @@ -0,0 +1,38 @@ +// 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 interface Renderable { + render(): string; +} + +/// 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 Widget extends SwiftHeapObject { + name: string; +} +export type Exports = { + Widget: { + new(name: string): Widget; + } + processRenderable(item: Renderable, transform: (arg0: Renderable) => string): string; + makeRenderableFactory(defaultName: string): () => Renderable; + roundtripRenderable(callback: (arg0: Renderable) => Renderable): (arg0: Renderable) => Renderable; + processOptionalRenderable(callback: (arg0: Renderable | null) => string): string; +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js new file mode 100644 index 000000000..ffdac6fa6 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -0,0 +1,436 @@ +// 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 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 f32Stack = []; + let f64Stack = []; + let ptrStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.unregistered) { return; } + instance?.exports?.bjs_release_swift_closure(state.pointer); + }); + const makeClosure = (pointer, file, line, func) => { + const state = { pointer, file, line, unregistered: false }; + const real = (...args) => { + if (state.unregistered) { + const bytes = new Uint8Array(memory.buffer, state.file); + let length = 0; + while (bytes[length] !== 0) { length += 1; } + const fileID = decodeString(state.file, length); + throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); + } + return func(...args); + }; + real.__unregister = () => { + if (state.unregistered) { return; } + state.unregistered = true; + swiftClosureRegistry.unregister(state); + }; + swiftClosureRegistry.register(real, state, state); + return swift.memory.retain(real); + }; + + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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_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) {} + bjs["swift_js_closure_unregister"] = function(funcRef) { + const func = swift.memory.getObject(funcRef); + func.__unregister(); + } + bjs["invoke_js_callback_TestModule_10TestModule10RenderableP_10RenderableP"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(swift.memory.getObject(param0)); + return swift.memory.retain(ret); + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule10RenderableP_10RenderableP = function(param0) { + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModule10RenderableP_10RenderableP(boxPtr, swift.memory.retain(param0)); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule10RenderableP_10RenderableP); + } + bjs["invoke_js_callback_TestModule_10TestModule10RenderableP_SS"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(swift.memory.getObject(param0)); + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModule10RenderableP_SS"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule10RenderableP_SS = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModule10RenderableP_SS(boxPtr, swift.memory.retain(param0)); + const ret = tmpRetString; + tmpRetString = undefined; + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule10RenderableP_SS); + } + bjs["invoke_js_callback_TestModule_10TestModuleSq10RenderableP_SS"] = function(callbackId, param0IsSome, param0ObjectId) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(param0IsSome ? swift.memory.getObject(param0ObjectId) : null); + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModuleSq10RenderableP_SS"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleSq10RenderableP_SS = function(param0) { + const isSome = param0 != null; + let result; + if (isSome) { + result = swift.memory.retain(param0); + } else { + result = 0; + } + instance.exports.invoke_swift_closure_TestModule_10TestModuleSq10RenderableP_SS(boxPtr, +isSome, result); + const ret = tmpRetString; + tmpRetString = undefined; + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq10RenderableP_SS); + } + bjs["invoke_js_callback_TestModule_10TestModuley_10RenderableP"] = function(callbackId) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(); + return swift.memory.retain(ret); + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModuley_10RenderableP"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuley_10RenderableP = function() { + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuley_10RenderableP(boxPtr); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuley_10RenderableP); + } + // Wrapper functions for module: TestModule + if (!importObject["TestModule"]) { + importObject["TestModule"] = {}; + } + importObject["TestModule"]["bjs_Widget_wrap"] = function(pointer) { + const obj = _exports['Widget'].__construct(pointer); + return swift.memory.retain(obj); + }; + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_Renderable_render"] = function bjs_Renderable_render(self) { + try { + let ret = swift.memory.getObject(self).render(); + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } 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) + } + }, + /** @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.deinit(state.pointer); + }); + + /// Represents a Swift heap object like a class instance or an actor instance. + class SwiftHeapObject { + static __wrap(pointer, deinit, prototype) { + const obj = Object.create(prototype); + const state = { pointer, deinit, hasReleased: false }; + obj.pointer = pointer; + obj.__swiftHeapObjectState = state; + swiftHeapObjectFinalizationRegistry.register(obj, state, state); + return obj; + } + + release() { + const state = this.__swiftHeapObjectState; + if (state.hasReleased) { + return; + } + state.hasReleased = true; + swiftHeapObjectFinalizationRegistry.unregister(state); + state.deinit(state.pointer); + } + } + class Widget extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Widget_deinit, Widget.prototype); + } + + constructor(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const ret = instance.exports.bjs_Widget_init(nameId, nameBytes.length); + return Widget.__construct(ret); + } + get name() { + instance.exports.bjs_Widget_name_get(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + set name(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_Widget_name_set(this.pointer, valueId, valueBytes.length); + } + } + const exports = { + Widget, + processRenderable: function bjs_processRenderable(item, transform) { + const callbackId = swift.memory.retain(transform); + instance.exports.bjs_processRenderable(swift.memory.retain(item), callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + makeRenderableFactory: function bjs_makeRenderableFactory(defaultName) { + const defaultNameBytes = textEncoder.encode(defaultName); + const defaultNameId = swift.memory.retain(defaultNameBytes); + const ret = instance.exports.bjs_makeRenderableFactory(defaultNameId, defaultNameBytes.length); + return swift.memory.getObject(ret); + }, + roundtripRenderable: function bjs_roundtripRenderable(callback) { + const callbackId = swift.memory.retain(callback); + const ret = instance.exports.bjs_roundtripRenderable(callbackId); + return swift.memory.getObject(ret); + }, + processOptionalRenderable: function bjs_processOptionalRenderable(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_processOptionalRenderable(callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 9ef28f844..c2d1c4cd8 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -578,6 +578,10 @@ extension _BridgedSwiftProtocolWrapper { bridgeJSStackPop() } + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Self { + bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Int32 { jsObject.bridgeJSLowerReturn() } diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 6407a175b..d2fe49db2 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -1206,6 +1206,34 @@ enum GraphOperations { } } } + + @JS func processDataProcessor(_ callback: (DataProcessor) -> String) -> String { + let processor = SwiftDataProcessor() + processor.increment(by: 42) + return callback(processor) + } + + @JS func makeDataProcessorFactory() -> () -> DataProcessor { + var count = 0 + return { + count += 1 + let p = SwiftDataProcessor() + p.increment(by: count * 10) + return p + } + } + + @JS func roundtripDataProcessor( + _ callback: @escaping (DataProcessor) -> DataProcessor + ) -> (DataProcessor) -> DataProcessor { + return callback + } + + @JS func processOptionalDataProcessor(_ callback: (DataProcessor?) -> String) -> String { + let processor = SwiftDataProcessor() + processor.increment(by: 7) + return callback(processor) + " | " + callback(nil) + } } class ExportAPITests: XCTestCase { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index db3132c37..e9c0e7653 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -70,6 +70,132 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests10H #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP { + static func bridgeJSLift(_ callbackId: Int32) -> (any DataProcessor) -> any DataProcessor { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(callbackValue, param0ObjectId) + return AnyDataProcessor.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any DataProcessor) -> any DataProcessor { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any DataProcessor) -> any DataProcessor) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any DataProcessor) -> any DataProcessor>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyDataProcessor.bridgeJSLiftParameter(param0)) + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ callback: Int32, _ param0: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(_ callback: Int32, _ param0: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (any DataProcessor) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0ObjectId = (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(callbackValue, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (any DataProcessor) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (any DataProcessor) -> String) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(any DataProcessor) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(AnyDataProcessor.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTests5ThemeO_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 @@ -1033,6 +1159,74 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSi_ #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0ObjectId: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(callback, param0IsSome, param0ObjectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsSq13DataProcessorP_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0ObjectId): (Int32, Int32) + if let param0 { + (param0IsSome, param0ObjectId) = (1, (param0 as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } else { + (param0IsSome, param0ObjectId) = (0, 0) + } + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(callbackValue, param0IsSome, param0ObjectId) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Optional) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq13DataProcessorP_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSq5ThemeO_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 @@ -1480,6 +1674,68 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqS #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ callback: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ callback: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(_ callback: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsy_13DataProcessorP { + static func bridgeJSLift(_ callbackId: Int32) -> () -> any DataProcessor { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(callbackValue) + return AnyDataProcessor.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == () -> any DataProcessor { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping () -> any DataProcessor) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP(_ boxPtr: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<() -> any DataProcessor>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure() + return (result as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_Sb") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_Sb_extern(_ callback: Int32) -> Int32 @@ -9069,6 +9325,50 @@ public func _bjs_TextProcessor_makeOptionalDirectionFormatter(_ _self: UnsafeMut #endif } +@_expose(wasm, "bjs_TextProcessor_processDataProcessor") +@_cdecl("bjs_TextProcessor_processDataProcessor") +public func _bjs_TextProcessor_processDataProcessor(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processDataProcessor(_: _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_SS.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeDataProcessorFactory") +@_cdecl("bjs_TextProcessor_makeDataProcessorFactory") +public func _bjs_TextProcessor_makeDataProcessorFactory(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeDataProcessorFactory() + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_roundtripDataProcessor") +@_cdecl("bjs_TextProcessor_roundtripDataProcessor") +public func _bjs_TextProcessor_roundtripDataProcessor(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Int32 { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).roundtripDataProcessor(_: _BJS_Closure_20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP.bridgeJSLift(callback)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalDataProcessor") +@_cdecl("bjs_TextProcessor_processOptionalDataProcessor") +public func _bjs_TextProcessor_processOptionalDataProcessor(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalDataProcessor(_: _BJS_Closure_20BridgeJSRuntimeTestsSq13DataProcessorP_SS.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_TextProcessor_deinit") @_cdecl("bjs_TextProcessor_deinit") public func _bjs_TextProcessor_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index da05bc5ae..8a3656b65 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -3595,6 +3595,189 @@ "useJSTypedClosure" : false } } + }, + { + "abiName" : "bjs_TextProcessor_processDataProcessor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processDataProcessor", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTests13DataProcessorP_SS", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_makeDataProcessorFactory", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeDataProcessorFactory", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsy_13DataProcessorP", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_TextProcessor_roundtripDataProcessor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripDataProcessor", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTests13DataProcessorP_13DataProcessorP", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + ], + "returnType" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + } + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_TextProcessor_processOptionalDataProcessor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalDataProcessor", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsSq13DataProcessorP_SS", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "nullable" : { + "_0" : { + "swiftProtocol" : { + "_0" : "DataProcessor" + } + }, + "_1" : "null" + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } } ], "name" : "TextProcessor", diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs index 0d5560fae..ebe00548b 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs @@ -77,15 +77,23 @@ export function getImports(importsContext) { } }, jsOptionalInvoke: (fn) => { - if (fn == null) { return false; } + if (fn == null) { + return false; + } return fn(); }, - jsStoreClosure: (fn) => { globalThis.__storedClosure = fn; }, - jsCallStoredClosure: () => { return globalThis.__storedClosure?.(); }, + jsStoreClosure: (fn) => { + globalThis.__storedClosure = fn; + }, + jsCallStoredClosure: () => { + return globalThis.__storedClosure?.(); + }, runJsClosureSupportTests: () => { const exports = importsContext.getExports(); - if (!exports) { throw new Error("No exports!?"); } + if (!exports) { + throw new Error("No exports!?"); + } runJsClosureSupportTests(exports); }, }; @@ -103,19 +111,32 @@ export function runJsClosureSupportTests(exports) { const multiParamTransform = (count, text, ratio) => { return `${text.toUpperCase()}-${count}-${ratio.toFixed(2)}`; }; - assert.equal(processor.processWithCustom("world", multiParamTransform), "WORLD-42-3.14"); + assert.equal( + processor.processWithCustom("world", multiParamTransform), + "WORLD-42-3.14", + ); assert.equal(processor.process("test"), "TEST"); const greeterForClosure = new exports.Greeter("World"); const greeterCaller = new exports.Greeter("Caller"); - const customGreeting = (greeter) => `Custom greeting for ${greeter.name}: ${greeter.greet()}`; - const greetResult = greeterCaller.greetWith(greeterForClosure, customGreeting); + const customGreeting = (greeter) => + `Custom greeting for ${greeter.name}: ${greeter.greet()}`; + const greetResult = greeterCaller.greetWith( + greeterForClosure, + customGreeting, + ); assert.equal(greetResult, "Custom greeting for World: Hello, World!"); greeterForClosure.release(); greeterCaller.release(); - assert.equal(exports.formatName("ada", (name) => name.toUpperCase()), "ADA"); - assert.equal(exports.formatName("grace", (name) => `Dr. ${name}`), "Dr. grace"); + assert.equal( + exports.formatName("ada", (name) => name.toUpperCase()), + "ADA", + ); + assert.equal( + exports.formatName("grace", (name) => `Dr. ${name}`), + "Dr. grace", + ); const addDr = exports.makeFormatter("Dr."); assert.equal(addDr("Ada"), "Dr. Ada"); @@ -137,8 +158,14 @@ export function runJsClosureSupportTests(exports) { const greeterForFormatter = new exports.Greeter("Formatter"); const greeterFormatter = greeterForFormatter.makeFormatter(" [suffix]"); - assert.equal(greeterFormatter("test"), "Hello, Formatter! - test - [suffix]"); - assert.equal(greeterFormatter("data"), "Hello, Formatter! - data - [suffix]"); + assert.equal( + greeterFormatter("test"), + "Hello, Formatter! - test - [suffix]", + ); + assert.equal( + greeterFormatter("data"), + "Hello, Formatter! - data - [suffix]", + ); greeterForFormatter.release(); const greeterCreator = exports.Greeter.makeCreator("Default"); @@ -206,11 +233,16 @@ export function runJsClosureSupportTests(exports) { const dirResult = processor.processDirection((dir) => { switch (dir) { - case exports.Direction.North: return "Going North"; - case exports.Direction.South: return "Going South"; - case exports.Direction.East: return "Going East"; - case exports.Direction.West: return "Going West"; - default: return "Unknown"; + case exports.Direction.North: + return "Going North"; + case exports.Direction.South: + return "Going South"; + case exports.Direction.East: + return "Going East"; + case exports.Direction.West: + return "Going West"; + default: + return "Unknown"; } }); assert.equal(dirResult, "Going North"); @@ -251,12 +283,27 @@ export function runJsClosureSupportTests(exports) { assert.equal(statusExtractor(exports.HttpStatus.Unknown), -1); const apiHandler = processor.makeAPIResultHandler(); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Success, param0: "done" }), "Success: done"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Failure, param0: 500 }), "Failure: 500"); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Success, param0: "done" }), + "Success: done", + ); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Failure, param0: 500 }), + "Failure: 500", + ); assert.equal(apiHandler({ tag: exports.APIResult.Tag.Info }), "Info"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Flag, param0: true }), "Flag: true"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Rate, param0: 1.5 }), "Rate: 1.5"); - assert.equal(apiHandler({ tag: exports.APIResult.Tag.Precise, param0: 3.14159 }), "Precise: 3.14159"); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Flag, param0: true }), + "Flag: true", + ); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Rate, param0: 1.5 }), + "Rate: 1.5", + ); + assert.equal( + apiHandler({ tag: exports.APIResult.Tag.Precise, param0: 3.14159 }), + "Precise: 3.14159", + ); const optDirResult = processor.processOptionalDirection((dir) => { return dir !== null ? `Dir: ${dir}` : "Dir: null"; @@ -284,28 +331,55 @@ export function runJsClosureSupportTests(exports) { assert.equal(optDirFormatter(exports.Direction.West), "W"); assert.equal(optDirFormatter(null), "nil"); - processor.release(); + const dpResult = processor.processDataProcessor((dp) => { + return `Value: ${dp.getValue()}`; + }); + assert.equal(dpResult, "Value: 42"); + const dpFactory = processor.makeDataProcessorFactory(); + const dp1 = dpFactory(); + assert.equal(dp1.getValue(), 10); + const dp2 = dpFactory(); + assert.equal(dp2.getValue(), 20); + + const dpRoundtrip = processor.roundtripDataProcessor((dp) => { + dp.increment(100); + return dp; + }); + const testDp = new exports.SwiftDataProcessor(); + const roundtrippedDp = dpRoundtrip(testDp); + assert.equal(roundtrippedDp.getValue(), 100); + + const optDpResult = processor.processOptionalDataProcessor((dp) => { + return dp !== null ? `DP: ${dp.getValue()}` : "DP: null"; + }); + assert.equal(optDpResult, "DP: 7 | DP: null"); + + processor.release(); const intToInt = exports.ClosureSupportExports.makeIntToInt(10); assert.equal(intToInt(0), 10); assert.equal(intToInt(32), 42); - const doubleToDouble = exports.ClosureSupportExports.makeDoubleToDouble(10.0); + const doubleToDouble = + exports.ClosureSupportExports.makeDoubleToDouble(10.0); assert.equal(doubleToDouble(0.0), 10.0); assert.equal(doubleToDouble(32.0), 42.0); - const stringToString = exports.ClosureSupportExports.makeStringToString("Hello, "); + const stringToString = + exports.ClosureSupportExports.makeStringToString("Hello, "); assert.equal(stringToString("world!"), "Hello, world!"); const jsIntToInt = exports.ClosureSupportExports.makeJSIntToInt(10); assert.equal(jsIntToInt(0), 10); assert.equal(jsIntToInt(32), 42); - const jsDoubleToDouble = exports.ClosureSupportExports.makeJSDoubleToDouble(10.0); + const jsDoubleToDouble = + exports.ClosureSupportExports.makeJSDoubleToDouble(10.0); assert.equal(jsDoubleToDouble(0.0), 10.0); assert.equal(jsDoubleToDouble(32.0), 42.0); - const jsStringToString = exports.ClosureSupportExports.makeJSStringToString("Hello, "); + const jsStringToString = + exports.ClosureSupportExports.makeJSStringToString("Hello, "); assert.equal(jsStringToString("world!"), "Hello, world!"); } From bd36090d8c9e578500f89c324d4a1f415a864a07 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 12 Mar 2026 16:27:19 +0000 Subject: [PATCH 15/68] BridgeJS: expand integer type support --- .../Generated/JavaScript/BridgeJS.json | 231 +- .../Generated/JavaScript/BridgeJS.json | 28 +- .../Sources/BridgeJSCore/ExportSwift.swift | 19 +- .../Sources/BridgeJSCore/ImportTS.swift | 4 +- .../BridgeJSCore/SwiftToSkeleton.swift | 8 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 15 +- .../Sources/BridgeJSLink/JSGlueGen.swift | 123 +- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 192 +- .../MacroSwift/FixedWidthIntegers.swift | 19 + .../Inputs/MacroSwift/Optionals.swift | 30 + .../BridgeJSCodegenTests/ArrayTypes.json | 112 +- .../BridgeJSCodegenTests/Async.json | 14 +- .../CrossFileSkipsEmptySkeletons.json | 7 +- .../DefaultParameters.json | 77 +- .../BridgeJSCodegenTests/DictionaryTypes.json | 28 +- .../EnumAssociatedValue.json | 84 +- .../EnumNamespace.Global.json | 56 +- .../BridgeJSCodegenTests/EnumNamespace.json | 56 +- .../BridgeJSCodegenTests/EnumRawType.swift | 14 +- .../FixedWidthIntegers.json | 471 +++ .../FixedWidthIntegers.swift | 255 ++ .../BridgeJSCodegenTests/ImportArray.json | 14 +- .../Namespaces.Global.json | 7 +- .../BridgeJSCodegenTests/Namespaces.json | 7 +- .../BridgeJSCodegenTests/Optionals.json | 344 ++- .../BridgeJSCodegenTests/Optionals.swift | 66 + .../PrimitiveParameters.json | 14 +- .../BridgeJSCodegenTests/PrimitiveReturn.json | 14 +- .../BridgeJSCodegenTests/PropertyTypes.json | 42 +- .../BridgeJSCodegenTests/Protocol.json | 42 +- .../StaticFunctions.Global.json | 84 +- .../BridgeJSCodegenTests/StaticFunctions.json | 84 +- .../StaticProperties.Global.json | 28 +- .../StaticProperties.json | 28 +- .../BridgeJSCodegenTests/SwiftClosure.json | 63 +- .../SwiftClosureImports.json | 49 +- .../BridgeJSCodegenTests/SwiftStruct.json | 42 +- .../SwiftStructImports.json | 28 +- .../BridgeJSLinkTests/ArrayTypes.js | 7 + .../__Snapshots__/BridgeJSLinkTests/Async.js | 7 + .../BridgeJSLinkTests/DefaultParameters.js | 7 + .../BridgeJSLinkTests/DictionaryTypes.js | 7 + .../BridgeJSLinkTests/EnumAssociatedValue.js | 7 + .../BridgeJSLinkTests/EnumCase.js | 7 + .../BridgeJSLinkTests/EnumNamespace.Global.js | 7 + .../BridgeJSLinkTests/EnumNamespace.js | 7 + .../BridgeJSLinkTests/EnumRawType.d.ts | 14 +- .../BridgeJSLinkTests/EnumRawType.js | 47 +- .../BridgeJSLinkTests/FixedWidthIntegers.d.ts | 33 + .../BridgeJSLinkTests/FixedWidthIntegers.js | 317 ++ .../BridgeJSLinkTests/GlobalGetter.js | 7 + .../BridgeJSLinkTests/GlobalThisImports.js | 7 + .../BridgeJSLinkTests/ImportArray.js | 7 + .../ImportedTypeInExportedInterface.js | 7 + .../BridgeJSLinkTests/InvalidPropertyNames.js | 7 + .../BridgeJSLinkTests/JSClass.js | 7 + .../JSClassStaticFunctions.js | 7 + .../BridgeJSLinkTests/JSValue.js | 7 + .../BridgeJSLinkTests/MixedGlobal.js | 7 + .../BridgeJSLinkTests/MixedModules.js | 7 + .../BridgeJSLinkTests/MixedPrivate.js | 7 + .../BridgeJSLinkTests/Namespaces.Global.js | 7 + .../BridgeJSLinkTests/Namespaces.js | 7 + .../BridgeJSLinkTests/Optionals.d.ts | 6 + .../BridgeJSLinkTests/Optionals.js | 49 + .../BridgeJSLinkTests/PrimitiveParameters.js | 7 + .../BridgeJSLinkTests/PrimitiveReturn.js | 7 + .../BridgeJSLinkTests/PropertyTypes.js | 7 + .../BridgeJSLinkTests/Protocol.js | 7 + .../BridgeJSLinkTests/ProtocolInClosure.js | 7 + .../StaticFunctions.Global.js | 7 + .../BridgeJSLinkTests/StaticFunctions.js | 7 + .../StaticProperties.Global.js | 7 + .../BridgeJSLinkTests/StaticProperties.js | 7 + .../BridgeJSLinkTests/StringParameter.js | 7 + .../BridgeJSLinkTests/StringReturn.js | 7 + .../BridgeJSLinkTests/SwiftClass.js | 7 + .../BridgeJSLinkTests/SwiftClosure.js | 7 + .../BridgeJSLinkTests/SwiftClosureImports.js | 7 + .../BridgeJSLinkTests/SwiftStruct.js | 7 + .../BridgeJSLinkTests/SwiftStructImports.js | 7 + .../__Snapshots__/BridgeJSLinkTests/Throws.js | 7 + .../BridgeJSLinkTests/UnsafePointer.js | 7 + .../VoidParameterVoidReturn.js | 7 + Plugins/PackageToJS/Templates/instantiate.js | 2 + .../JavaScriptKit/BridgeJSIntrinsics.swift | 266 +- .../Generated/JavaScript/BridgeJS.json | 21 +- .../ArraySupportTests.swift | 4 + .../BridgeJSRuntimeTests/ExportAPITests.swift | 35 +- .../Generated/BridgeJS.swift | 477 ++- .../Generated/JavaScript/BridgeJS.json | 2551 ++++++++++++++--- .../IntegerTypesSupportTests.swift | 73 + .../JavaScript/ArraySupportTests.mjs | 8 +- .../JavaScript/IntegerTypesSupportTests.mjs | 175 ++ .../JavaScript/OptionalSupportTests.mjs | 6 +- .../OptionalSupportTests.swift | 2 + Tests/prelude.mjs | 18 +- 97 files changed, 6088 insertions(+), 1095 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/FixedWidthIntegers.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js create mode 100644 Tests/BridgeJSRuntimeTests/IntegerTypesSupportTests.swift create mode 100644 Tests/BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs diff --git a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json index eacd18cb3..95c4ac18e 100644 --- a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json +++ b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json @@ -451,8 +451,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -473,8 +476,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -930,8 +936,11 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -984,8 +993,11 @@ "isStatic" : false, "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1053,8 +1065,11 @@ "label" : "zipCode", "name" : "zipCode", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1090,8 +1105,11 @@ "isStatic" : false, "name" : "zipCode", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1280,8 +1298,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1308,8 +1329,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1330,8 +1354,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1341,8 +1368,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1362,8 +1392,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1656,8 +1689,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1688,8 +1724,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1714,8 +1753,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1729,8 +1771,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1854,8 +1899,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1887,8 +1935,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1914,8 +1965,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1930,8 +1984,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -2060,8 +2117,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2093,8 +2153,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2119,8 +2182,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2146,8 +2212,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2162,8 +2231,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2199,8 +2271,11 @@ "associatedValues" : [ { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2286,8 +2361,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2331,8 +2409,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -2390,15 +2471,21 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -2504,8 +2591,11 @@ "isStatic" : false, "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -2573,8 +2663,11 @@ "isStatic" : false, "name" : "zipCode", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2602,8 +2695,11 @@ "isStatic" : false, "name" : "age", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -2646,8 +2742,11 @@ "isStatic" : false, "name" : "id", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json index 3046e1f01..60eb694ff 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json @@ -147,8 +147,11 @@ "isStatic" : false, "name" : "startLine", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -157,8 +160,11 @@ "isStatic" : false, "name" : "startColumn", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -167,8 +173,11 @@ "isStatic" : false, "name" : "endLine", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -177,8 +186,11 @@ "isStatic" : false, "name" : "endColumn", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index eab3a0831..5b6c7d1ff 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -748,7 +748,7 @@ struct StackCodegen { /// - Returns: An ExprSyntax representing the lift expression func liftExpression(for type: BridgeType) -> ExprSyntax { switch type { - case .string, .int, .uint, .bool, .float, .double, + case .string, .integer, .bool, .float, .double, .jsObject(nil), .jsValue, .swiftStruct, .swiftHeapObject, .unsafePointer, .swiftProtocol, .caseEnum, .associatedValueEnum, .rawValueEnum, .array, .dictionary: return "\(raw: type.swiftType).bridgeJSStackPop()" @@ -766,7 +766,7 @@ struct StackCodegen { private func liftNullableExpression(wrappedType: BridgeType, kind: JSOptionalKind) -> ExprSyntax { let typeName = kind == .null ? "Optional" : "JSUndefinedOr" switch wrappedType { - case .string, .int, .uint, .bool, .float, .double, .jsObject(nil), .jsValue, + case .string, .integer, .bool, .float, .double, .jsObject(nil), .jsValue, .swiftStruct, .swiftHeapObject, .caseEnum, .associatedValueEnum, .rawValueEnum, .array, .dictionary: return "\(raw: typeName)<\(raw: wrappedType.swiftType)>.bridgeJSStackPop()" @@ -789,7 +789,7 @@ struct StackCodegen { varPrefix: String ) -> [CodeBlockItemSyntax] { switch type { - case .string, .int, .uint, .bool, .float, .double, .jsValue, + case .string, .integer, .bool, .float, .double, .jsValue, .jsObject(nil), .swiftHeapObject, .unsafePointer, .closure, .caseEnum, .rawValueEnum, .associatedValueEnum, .swiftStruct, .nullable: return ["\(raw: accessor).bridgeJSStackPush()"] @@ -1425,8 +1425,7 @@ extension BridgeType { var swiftType: String { switch self { case .bool: return "Bool" - case .int: return "Int" - case .uint: return "UInt" + case .integer(let t): return t.swiftTypeName case .float: return "Float" case .double: return "Double" case .string: return "String" @@ -1502,7 +1501,7 @@ extension BridgeType { func liftParameterInfo() throws -> LiftingIntrinsicInfo { switch self { case .bool: return .bool - case .int, .uint: return .int + case .integer(let t): return LiftingIntrinsicInfo(parameters: [("value", t.wasmCoreType)]) case .float: return .float case .double: return .double case .string: return .string @@ -1560,7 +1559,7 @@ extension BridgeType { func loweringReturnInfo() throws -> LoweringIntrinsicInfo { switch self { case .bool: return .bool - case .int, .uint: return .int + case .integer(let t): return LoweringIntrinsicInfo(returnType: t.wasmCoreType) case .float: return .float case .double: return .double case .string: return .string @@ -1592,7 +1591,8 @@ extension SwiftEnumRawType { var liftingIntrinsicInfo: BridgeType.LiftingIntrinsicInfo { switch self { case .bool: return .bool - case .int, .int32, .int64, .uint, .uint32, .uint64: return .int + case .integer(let integerType): + return .init(parameters: [("value", integerType.wasmCoreType)]) case .float: return .float case .double: return .double case .string: return .string @@ -1602,7 +1602,8 @@ extension SwiftEnumRawType { var loweringIntrinsicInfo: BridgeType.LoweringIntrinsicInfo { switch self { case .bool: return .bool - case .int, .int32, .int64, .uint, .uint32, .uint64: return .int + case .integer(let integerType): + return .init(returnType: integerType.wasmCoreType) case .float: return .float case .double: return .double case .string: return .string diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 7d9a6f087..1d1fe3aa9 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -822,7 +822,7 @@ extension BridgeType { func loweringParameterInfo(context: BridgeContext = .importTS) throws -> LoweringParameterInfo { switch self { case .bool: return .bool - case .int, .uint: return .int + case .integer(let t): return LoweringParameterInfo(loweredParameters: [("value", t.wasmCoreType)]) case .float: return .float case .double: return .double case .string: return .string @@ -901,7 +901,7 @@ extension BridgeType { ) throws -> LiftingReturnInfo { switch self { case .bool: return .bool - case .int, .uint: return .int + case .integer(let t): return LiftingReturnInfo(valueToLift: t.wasmCoreType) case .float: return .float case .double: return .double case .string: return .string diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 8f1b3fa35..81ad32813 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -442,7 +442,7 @@ public final class SwiftToSkeleton { } private enum ExportSwiftConstants { - static let supportedRawTypes = SwiftEnumRawType.allCases.map { $0.rawValue } + static let supportedRawTypes = SwiftEnumRawType.supportedTypeNames } extension AttributeSyntax { @@ -828,7 +828,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { let intValue = Int(intLiteral.literal.text) { let value = DefaultValue.int(isNegative ? -intValue : intValue) - if let type = type, !type.isCompatibleWith(.int) { + if let type = type, !type.isCompatibleWith(.integer(.int)) { return nil } return value @@ -1489,12 +1489,12 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { for enumCase in exportedEnum.cases { for associatedValue in enumCase.associatedValues { switch associatedValue.type { - case .string, .int, .float, .double, .bool, .caseEnum, .rawValueEnum, + case .string, .integer, .float, .double, .bool, .caseEnum, .rawValueEnum, .swiftStruct, .swiftHeapObject, .jsObject, .associatedValueEnum, .array: break case .nullable(let wrappedType, _): switch wrappedType { - case .string, .int, .float, .double, .bool, .caseEnum, .rawValueEnum, + case .string, .integer, .float, .double, .bool, .caseEnum, .rawValueEnum, .swiftStruct, .swiftHeapObject, .jsObject, .associatedValueEnum, .array: break default: diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 8c18ced4d..f69a4b266 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -302,6 +302,7 @@ public struct BridgeJSLink { "let \(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject);", "let \(JSGlueVariableScope.reservedStringStack) = [];", "let \(JSGlueVariableScope.reservedI32Stack) = [];", + "let \(JSGlueVariableScope.reservedI64Stack) = [];", "let \(JSGlueVariableScope.reservedF32Stack) = [];", "let \(JSGlueVariableScope.reservedF64Stack) = [];", "let \(JSGlueVariableScope.reservedPointerStack) = [];", @@ -437,6 +438,16 @@ public struct BridgeJSLink { printer.write("return \(JSGlueVariableScope.reservedPointerStack).pop();") } printer.write("}") + printer.write("bjs[\"swift_js_push_i64\"] = function(v) {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedI64Stack).push(v);") + } + printer.write("}") + printer.write("bjs[\"swift_js_pop_i64\"] = function() {") + printer.indent { + printer.write("return \(JSGlueVariableScope.reservedI64Stack).pop();") + } + printer.write("}") if !allStructs.isEmpty { for structDef in allStructs { printer.write("bjs[\"swift_js_struct_lower_\(structDef.abiName)\"] = function(objectId) {") @@ -3508,8 +3519,8 @@ extension BridgeType { return "void" case .string: return "string" - case .int, .uint: - return "number" + case .integer(let t): + return t.tsTypeName case .float: return "number" case .double: diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index bec5ce3e9..599b6df39 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -26,6 +26,7 @@ final class JSGlueVariableScope { static let reservedTextDecoder = "textDecoder" static let reservedStringStack = "strStack" static let reservedI32Stack = "i32Stack" + static let reservedI64Stack = "i64Stack" static let reservedF32Stack = "f32Stack" static let reservedF64Stack = "f64Stack" static let reservedPointerStack = "ptrStack" @@ -54,6 +55,7 @@ final class JSGlueVariableScope { reservedTextDecoder, reservedStringStack, reservedI32Stack, + reservedI64Stack, reservedF32Stack, reservedF64Stack, reservedPointerStack, @@ -100,6 +102,9 @@ extension JSGlueVariableScope { func emitPushI32Parameter(_ value: String, printer: CodeFragmentPrinter) { printer.write("\(JSGlueVariableScope.reservedI32Stack).push(\(value));") } + func emitPushI64Parameter(_ value: String, printer: CodeFragmentPrinter) { + printer.write("\(JSGlueVariableScope.reservedI64Stack).push(\(value));") + } func emitPushF64Parameter(_ value: String, printer: CodeFragmentPrinter) { printer.write("\(JSGlueVariableScope.reservedF64Stack).push(\(value));") } @@ -117,6 +122,9 @@ extension JSGlueVariableScope { func popI32() -> String { return "\(JSGlueVariableScope.reservedI32Stack).pop()" } + func popI64() -> String { + return "\(JSGlueVariableScope.reservedI64Stack).pop()" + } func popF64() -> String { return "\(JSGlueVariableScope.reservedF64Stack).pop()" } @@ -238,6 +246,14 @@ struct IntrinsicJSFragment: Sendable { ) static let uintLiftParameter = uintLiftReturn + static let uint64LiftReturn = IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, _ in + return ["BigInt.asUintN(64, \(arguments[0]))"] + } + ) + static let uint64LiftParameter = uint64LiftReturn + // MARK: - String Fragments static let stringLowerParameter = IntrinsicJSFragment( @@ -650,7 +666,12 @@ struct IntrinsicJSFragment: Sendable { ) } - let innerFragment = try liftParameter(type: wrappedType, context: bridgeContext) + let innerFragment = + if wrappedType.optionalConvention == .stackABI { + try stackLiftFragment(elementType: wrappedType) + } else { + try liftParameter(type: wrappedType, context: bridgeContext) + } return compositeOptionalLiftParameter( wrappedType: wrappedType, kind: kind, @@ -738,7 +759,12 @@ struct IntrinsicJSFragment: Sendable { ) } - let innerFragment = try lowerParameter(type: wrappedType) + let innerFragment = + if wrappedType.optionalConvention == .stackABI { + try stackLowerFragment(elementType: wrappedType) + } else { + try lowerParameter(type: wrappedType) + } return try compositeOptionalLowerParameter( wrappedType: wrappedType, kind: kind, @@ -832,7 +858,12 @@ struct IntrinsicJSFragment: Sendable { let isSomeVar = scope.variable("isSome") printer.write("const \(isSomeVar) = \(scope.popI32());") - let innerFragment = try liftReturn(type: wrappedType) + let innerFragment = + if wrappedType.optionalConvention == .stackABI { + try stackLiftFragment(elementType: wrappedType) + } else { + try liftReturn(type: wrappedType) + } let innerPrinter = CodeFragmentPrinter() let innerResults = try innerFragment.printCode([], context.with(\.printer, innerPrinter)) @@ -1077,6 +1108,15 @@ struct IntrinsicJSFragment: Sendable { return optionalLowerReturnToSideChannel(mode: mode, kind: kind) } + if wrappedType.optionalConvention == .stackABI { + let innerFragment = try stackLowerFragment(elementType: wrappedType) + return stackOptionalLower( + wrappedType: wrappedType, + kind: kind, + innerFragment: innerFragment + ) + } + if wrappedType.nilSentinel.hasSentinel { let innerFragment = try lowerReturn(type: wrappedType, context: .exportSwift) return sentinelOptionalLowerReturn( @@ -1183,10 +1223,10 @@ struct IntrinsicJSFragment: Sendable { private static func popExpression(for wasmType: WasmCoreType, scope: JSGlueVariableScope) -> String { switch wasmType { case .i32: return scope.popI32() + case .i64: return scope.popI64() case .f32: return scope.popF32() case .f64: return scope.popF64() case .pointer: return scope.popPointer() - case .i64: return scope.popI32() } } @@ -1198,10 +1238,10 @@ struct IntrinsicJSFragment: Sendable { ) { switch wasmType { case .i32: scope.emitPushI32Parameter(value, printer: printer) + case .i64: scope.emitPushI64Parameter(value, printer: printer) case .f32: scope.emitPushF32Parameter(value, printer: printer) case .f64: scope.emitPushF64Parameter(value, printer: printer) case .pointer: scope.emitPushPointerParameter(value, printer: printer) - case .i64: scope.emitPushI32Parameter(value, printer: printer) } } @@ -1243,7 +1283,7 @@ struct IntrinsicJSFragment: Sendable { /// Returns a fragment that lowers a JS value to Wasm core values for parameters static func lowerParameter(type: BridgeType) throws -> IntrinsicJSFragment { switch type { - case .bool, .int, .uint, .float, .double, .unsafePointer, .caseEnum: + case .bool, .integer, .float, .double, .unsafePointer, .caseEnum: return .identity case .rawValueEnum(_, let rawType) where rawType != .string: return .identity @@ -1291,9 +1331,19 @@ struct IntrinsicJSFragment: Sendable { switch type { case .bool, .rawValueEnum(_, .bool): return .boolLiftReturn - case .uint: + case .integer(let t) where !t.is64Bit && !t.isSigned: + return .uintLiftReturn + case .integer(let t) where t.is64Bit && !t.isSigned: + return .uint64LiftReturn + case .rawValueEnum(_, let rawType) + where rawType.integerType?.is64Bit == false + && rawType.integerType?.isSigned == false: return .uintLiftReturn - case .int, .float, .double, .unsafePointer, .caseEnum: + case .rawValueEnum(_, let rawType) + where rawType.integerType?.is64Bit == true + && rawType.integerType?.isSigned == false: + return .uint64LiftReturn + case .integer, .float, .double, .unsafePointer, .caseEnum: return .identity case .rawValueEnum(_, let rawType) where rawType != .string && rawType != .bool: return .identity @@ -1340,9 +1390,19 @@ struct IntrinsicJSFragment: Sendable { switch type { case .bool, .rawValueEnum(_, .bool): return .boolLiftParameter - case .uint: + case .integer(let t) where !t.is64Bit && !t.isSigned: + return .uintLiftParameter + case .integer(let t) where t.is64Bit && !t.isSigned: + return .uint64LiftParameter + case .rawValueEnum(_, let rawType) + where rawType.integerType?.is64Bit == false + && rawType.integerType?.isSigned == false: return .uintLiftParameter - case .int, .float, .double, .unsafePointer, .caseEnum: + case .rawValueEnum(_, let rawType) + where rawType.integerType?.is64Bit == true + && rawType.integerType?.isSigned == false: + return .uint64LiftParameter + case .integer, .float, .double, .unsafePointer, .caseEnum: return .identity case .rawValueEnum(_, let rawType) where rawType != .string && rawType != .bool: return .identity @@ -1426,7 +1486,7 @@ struct IntrinsicJSFragment: Sendable { switch type { case .bool, .rawValueEnum(_, .bool): return .boolLowerReturn - case .int, .uint, .float, .double, .unsafePointer, .caseEnum: + case .integer, .float, .double, .unsafePointer, .caseEnum: return .identity case .rawValueEnum(_, let rawType) where rawType != .string && rawType != .bool: return .identity @@ -2577,8 +2637,10 @@ private extension BridgeType { switch self { case .bool: return .inlineFlag - case .int, .uint: + case .integer(let t) where !t.is64Bit: return .sideChannelReturn(.none) + case .integer: + return .stackABI case .float: return .sideChannelReturn(.none) case .double: @@ -2605,7 +2667,9 @@ private extension BridgeType { return .sideChannelReturn(.none) case .bool: return .inlineFlag - case .int, .int32, .int64, .uint, .uint32, .uint64: + case .integer(let integerType) where integerType.is64Bit: + return .stackABI + case .integer: return .sideChannelReturn(.none) } case .associatedValueEnum: @@ -2637,9 +2701,10 @@ private extension BridgeType { var optionalScalarKind: OptionalScalarKind? { switch self { case .bool, .rawValueEnum(_, .bool): return .bool - case .int, .uint, .caseEnum, - .rawValueEnum(_, .int), .rawValueEnum(_, .int32), .rawValueEnum(_, .int64), - .rawValueEnum(_, .uint), .rawValueEnum(_, .uint32), .rawValueEnum(_, .uint64): + case .integer(let t) where !t.is64Bit: return .int + case .caseEnum: + return .int + case .rawValueEnum(_, let rawType) where rawType.integerType?.is64Bit == false: return .int case .float, .rawValueEnum(_, .float): return .float case .double, .rawValueEnum(_, .double): return .double @@ -2650,8 +2715,10 @@ private extension BridgeType { var wasmParams: [(name: String, type: WasmCoreType)] { switch self { - case .bool, .int, .uint: + case .bool: return [("value", .i32)] + case .integer(let t): + return [("value", t.wasmCoreType)] case .float: return [("value", .f32)] case .double: @@ -2678,8 +2745,10 @@ private extension BridgeType { return [("value", .f32)] case .double: return [("value", .f64)] - case .bool, .int, .int32, .int64, .uint, .uint32, .uint64: + case .bool: return [("value", .i32)] + case .integer(let integerType): + return [("value", integerType.wasmCoreType)] } case .associatedValueEnum: return [("caseId", .i32)] @@ -2694,7 +2763,7 @@ private extension BridgeType { var isSingleParamScalar: Bool { switch self { - case .bool, .int, .uint, .float, .double, .unsafePointer, .caseEnum: return true + case .bool, .integer, .float, .double, .unsafePointer, .caseEnum: return true case .rawValueEnum(_, let rawType): return rawType != .string default: return false } @@ -2703,9 +2772,11 @@ private extension BridgeType { var stackLowerCoerce: String? { switch self { case .bool, .rawValueEnum(_, .bool): return "$0 ? 1 : 0" - case .int, .uint, .unsafePointer, .caseEnum, - .rawValueEnum(_, .int), .rawValueEnum(_, .int32), .rawValueEnum(_, .int64), - .rawValueEnum(_, .uint), .rawValueEnum(_, .uint32), .rawValueEnum(_, .uint64): + case .integer(let t) where !t.is64Bit: return "($0 | 0)" + case .integer: return nil // 64-bit integers pass through directly + case .unsafePointer, .caseEnum: + return "($0 | 0)" + case .rawValueEnum(_, let rawType) where rawType.integerType?.is64Bit == false: return "($0 | 0)" case .float, .rawValueEnum(_, .float): return "Math.fround($0)" case .double, .rawValueEnum(_, .double): return nil @@ -2716,7 +2787,11 @@ private extension BridgeType { var liftCoerce: String? { switch self { case .bool, .rawValueEnum(_, .bool): return "$0 !== 0" - case .uint: return "$0 >>> 0" + case .integer(let t) where !t.is64Bit && !t.isSigned: return "$0 >>> 0" + case .rawValueEnum(_, let rawType) + where rawType.integerType?.is64Bit == false + && rawType.integerType?.isSigned == false: + return "$0 >>> 0" default: return nil } } @@ -2731,7 +2806,7 @@ private extension BridgeType { var varHint: String { switch self { case .bool: return "bool" - case .int, .uint: return "int" + case .integer: return "int" case .float: return "f32" case .double: return "f64" case .unsafePointer: return "pointer" diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 967215f6c..1f03e09ba 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -164,8 +164,65 @@ public enum JSOptionalKind: String, Codable, Equatable, Hashable, Sendable { } } +public enum IntegerWidth: String, Codable, Equatable, Hashable, Sendable { + case word // Int / UInt (ptr-sized, 32-bit on wasm32) + case w8, w16, w32, w64 +} + +public struct BridgeIntegerType: Codable, Equatable, Hashable, Sendable { + public let width: IntegerWidth + public let isSigned: Bool + + public static let int = BridgeIntegerType(width: .word, isSigned: true) + public static let uint = BridgeIntegerType(width: .word, isSigned: false) + public static let int8 = BridgeIntegerType(width: .w8, isSigned: true) + public static let uint8 = BridgeIntegerType(width: .w8, isSigned: false) + public static let int16 = BridgeIntegerType(width: .w16, isSigned: true) + public static let uint16 = BridgeIntegerType(width: .w16, isSigned: false) + public static let int32 = BridgeIntegerType(width: .w32, isSigned: true) + public static let uint32 = BridgeIntegerType(width: .w32, isSigned: false) + public static let int64 = BridgeIntegerType(width: .w64, isSigned: true) + public static let uint64 = BridgeIntegerType(width: .w64, isSigned: false) + + public var is64Bit: Bool { width == .w64 } + public var wasmCoreType: WasmCoreType { is64Bit ? .i64 : .i32 } + + public var swiftTypeName: String { + switch (width, isSigned) { + case (.word, true): return "Int" + case (.word, false): return "UInt" + case (.w8, true): return "Int8" + case (.w8, false): return "UInt8" + case (.w16, true): return "Int16" + case (.w16, false): return "UInt16" + case (.w32, true): return "Int32" + case (.w32, false): return "UInt32" + case (.w64, true): return "Int64" + case (.w64, false): return "UInt64" + } + } + + public var tsTypeName: String { is64Bit ? "bigint" : "number" } + + public var mangleTypeName: String { + switch (width, isSigned) { + case (.word, true): return "Si" + case (.word, false): return "Su" + case (.w8, true): return "s8" + case (.w8, false): return "u8" + case (.w16, true): return "s16" + case (.w16, false): return "u16" + case (.w32, true): return "s32" + case (.w32, false): return "u32" + case (.w64, true): return "s64" + case (.w64, false): return "u64" + } + } +} + public enum BridgeType: Codable, Equatable, Hashable, Sendable { - case int, uint, float, double, string, bool, jsObject(String?), jsValue, swiftHeapObject(String), void + case integer(BridgeIntegerType), float, double, string, bool, jsObject(String?), jsValue, swiftHeapObject(String), + void case unsafePointer(UnsafePointerType) indirect case nullable(BridgeType, JSOptionalKind) indirect case array(BridgeType) @@ -183,26 +240,53 @@ public enum WasmCoreType: String, Codable, Sendable { case i32, i64, f32, f64, pointer } -public enum SwiftEnumRawType: String, CaseIterable, Codable, Sendable { - case string = "String" - case bool = "Bool" - case int = "Int" - case int32 = "Int32" - case int64 = "Int64" - case uint = "UInt" - case uint32 = "UInt32" - case uint64 = "UInt64" - case float = "Float" - case double = "Double" +public enum SwiftEnumRawType: RawRepresentable, Codable, Equatable, Hashable, Sendable { + case string + case bool + case integer(BridgeIntegerType) + case float + case double + + private static let integerTypeMappings: [(name: String, type: BridgeIntegerType)] = [ + ("Int", .int), + ("Int32", .int32), + ("Int64", .int64), + ("UInt", .uint), + ("UInt32", .uint32), + ("UInt64", .uint64), + ] + + public static let supportedTypeNames = + [ + "String", + "Bool", + "Float", + "Double", + ] + integerTypeMappings.map(\.name) + + public var rawValue: String { + switch self { + case .string: + return "String" + case .bool: + return "Bool" + case .integer(let integerType): + return integerType.swiftTypeName + case .float: + return "Float" + case .double: + return "Double" + } + } public var wasmCoreType: WasmCoreType? { switch self { case .string: return nil - case .bool, .int, .int32, .uint, .uint32: + case .bool: return .i32 - case .int64, .uint64: - return .i64 + case .integer(let integerType): + return integerType.wasmCoreType case .float: return .f32 case .double: @@ -210,13 +294,54 @@ public enum SwiftEnumRawType: String, CaseIterable, Codable, Sendable { } } + public var integerType: BridgeIntegerType? { + guard case .integer(let integerType) = self else { + return nil + } + return integerType + } + + public init?(rawValue: String) { + if let integerType = Self.integerTypeMappings.first(where: { $0.name == rawValue })?.type { + self = .integer(integerType) + return + } + switch rawValue { + case "String": + self = .string + case "Bool": + self = .bool + case "Float": + self = .float + case "Double": + self = .double + default: + return nil + } + } + public init?(_ rawTypeString: String?) { - guard let rawTypeString = rawTypeString, - let match = Self.allCases.first(where: { $0.rawValue == rawTypeString }) - else { + guard let rawTypeString else { return nil } - self = match + self.init(rawValue: rawTypeString) + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(String.self) + guard let value = Self(rawValue: rawValue) else { + throw DecodingError.dataCorruptedError( + in: container, + debugDescription: "Unknown Swift enum raw type: \(rawValue)" + ) + } + self = value + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) } } @@ -495,8 +620,10 @@ extension EnumCase { return "\"\(rawValue)\"" case .bool: return rawValue.lowercased() == "true" ? "true" : "false" - case .float, .double, .int, .int32, .int64, .uint, .uint32, .uint64: + case .float, .double: return rawValue + case .integer(let integerType): + return integerType.is64Bit ? "\(rawValue)n" : rawValue } } } @@ -1056,10 +1183,16 @@ extension BridgeType { /// Maps Swift primitive type names to BridgeType. Returns nil for unknown types. public init?(swiftType: String) { switch swiftType { - case "Int": - self = .int - case "UInt": - self = .uint + case "Int": self = .integer(.int) + case "UInt": self = .integer(.uint) + case "Int8": self = .integer(.int8) + case "UInt8": self = .integer(.uint8) + case "Int16": self = .integer(.int16) + case "UInt16": self = .integer(.uint16) + case "Int32": self = .integer(.int32) + case "UInt32": self = .integer(.uint32) + case "Int64": self = .integer(.int64) + case "UInt64": self = .integer(.uint64) case "Float": self = .float case "Double": @@ -1089,7 +1222,7 @@ extension BridgeType { switch self { case .void: return nil case .bool: return .i32 - case .int, .uint: return .i32 + case .integer(let t): return t.wasmCoreType case .float: return .f32 case .double: return .f64 case .string: return nil @@ -1138,8 +1271,7 @@ extension BridgeType { /// https://github.com/swiftlang/swift/blob/main/docs/ABI/Mangling.rst#types public var mangleTypeName: String { switch self { - case .int: return "Si" - case .uint: return "Su" + case .integer(let t): return t.mangleTypeName case .float: return "Sf" case .double: return "Sd" case .string: return "SS" @@ -1206,12 +1338,14 @@ extension BridgeType { } switch wrappedType { - case .string, .int, .float, .double, .jsObject, .swiftProtocol: + case .string, .integer, .float, .double, .jsObject, .swiftProtocol: return true case .rawValueEnum(_, let rawType): switch rawType { - case .string, .int, .float, .double: + case .string, .float, .double: return true + case .integer(let integerType): + return !integerType.is64Bit default: return false } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/FixedWidthIntegers.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/FixedWidthIntegers.swift new file mode 100644 index 000000000..8f984acf0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/FixedWidthIntegers.swift @@ -0,0 +1,19 @@ +import JavaScriptKit + +@JS public func roundTripInt8(_ v: Int8) -> Int8 { v } +@JS public func roundTripUInt8(_ v: UInt8) -> UInt8 { v } +@JS public func roundTripInt16(_ v: Int16) -> Int16 { v } +@JS public func roundTripUInt16(_ v: UInt16) -> UInt16 { v } +@JS public func roundTripInt32(_ v: Int32) -> Int32 { v } +@JS public func roundTripUInt32(_ v: UInt32) -> UInt32 { v } +@JS public func roundTripInt64(_ v: Int64) -> Int64 { v } +@JS public func roundTripUInt64(_ v: UInt64) -> UInt64 { v } + +@JSFunction func roundTripInt8(_ v: Int8) throws(JSException) -> Int8 +@JSFunction func roundTripUInt8(_ v: UInt8) throws(JSException) -> UInt8 +@JSFunction func roundTripInt16(_ v: Int16) throws(JSException) -> Int16 +@JSFunction func roundTripUInt16(_ v: UInt16) throws(JSException) -> UInt16 +@JSFunction func roundTripInt32(_ v: Int32) throws(JSException) -> Int32 +@JSFunction func roundTripUInt32(_ v: UInt32) throws(JSException) -> UInt32 +@JSFunction func roundTripInt64(_ v: Int64) throws(JSException) -> Int64 +@JSFunction func roundTripUInt64(_ v: UInt64) throws(JSException) -> UInt64 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift index 57d994519..927fac6a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift @@ -40,6 +40,36 @@ func roundTripInt(value: Int?) -> Int? { return value } +@JS +func roundTripInt8(value: Int8?) -> Int8? { + return value +} + +@JS +func roundTripUInt8(value: UInt8?) -> UInt8? { + return value +} + +@JS +func roundTripInt16(value: Int16?) -> Int16? { + return value +} + +@JS +func roundTripUInt16(value: UInt16?) -> UInt16? { + return value +} + +@JS +func roundTripInt32(value: Int32?) -> Int32? { + return value +} + +@JS +func roundTripUInt32(value: UInt32?) -> UInt32? { + return value +} + @JS func roundTripBool(flag: Bool?) -> Bool? { return flag diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json index 32bdb3374..3664fa339 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json @@ -26,8 +26,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -60,8 +63,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -178,8 +184,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -189,8 +198,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -411,8 +423,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -420,8 +435,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -591,8 +609,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -607,8 +628,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -677,8 +701,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -693,8 +720,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -851,8 +881,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -866,8 +899,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1163,8 +1199,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1185,8 +1224,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1207,8 +1249,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1237,8 +1282,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json index a780871ba..a2b95cc24 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json @@ -38,15 +38,21 @@ "label" : "_", "name" : "v", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json index 10c079b27..4d7495a7c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json @@ -9,8 +9,11 @@ ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json index 8c088a35e..f8a23c33d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json @@ -92,8 +92,11 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -167,8 +170,11 @@ "isStatic" : false, "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -296,15 +302,21 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -510,8 +522,11 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -776,8 +791,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -787,8 +805,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -978,8 +999,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -989,8 +1013,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1046,8 +1073,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1100,8 +1130,11 @@ "isStatic" : false, "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json index af5b83dc7..c740dc46f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json @@ -32,8 +32,11 @@ "type" : { "dictionary" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -43,8 +46,11 @@ "returnType" : { "dictionary" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -110,8 +116,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -125,8 +134,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json index 3c624fa12..b92cee954 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json @@ -31,8 +31,11 @@ "associatedValues" : [ { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -118,8 +121,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -137,8 +143,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -196,15 +205,21 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -304,8 +319,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -323,8 +341,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -378,8 +399,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -426,8 +450,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -467,8 +494,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -705,8 +735,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -811,8 +844,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json index b519748d4..46dbe8917 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json @@ -30,8 +30,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -56,8 +59,11 @@ "Utils" ], "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -201,8 +207,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -509,15 +518,21 @@ "label" : "rootId", "name" : "rootId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -544,15 +559,21 @@ "label" : "graphId", "name" : "graphId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -579,8 +600,11 @@ "label" : "graphId", "name" : "graphId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json index a468b2e2c..a57703b09 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json @@ -30,8 +30,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -56,8 +59,11 @@ "Utils" ], "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -201,8 +207,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -509,15 +518,21 @@ "label" : "rootId", "name" : "rootId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -544,15 +559,21 @@ "label" : "graphId", "name" : "graphId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -579,8 +600,11 @@ "label" : "graphId", "name" : "graphId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift index 4511ed1df..e70a6b0aa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.swift @@ -228,7 +228,7 @@ public func _bjs_roundTripOptionalPriority(_ inputIsSome: Int32, _ inputValue: I @_expose(wasm, "bjs_setFileSize") @_cdecl("bjs_setFileSize") -public func _bjs_setFileSize(_ size: Int32) -> Void { +public func _bjs_setFileSize(_ size: Int64) -> Void { #if arch(wasm32) setFileSize(_: FileSize.bridgeJSLiftParameter(size)) #else @@ -238,7 +238,7 @@ public func _bjs_setFileSize(_ size: Int32) -> Void { @_expose(wasm, "bjs_getFileSize") @_cdecl("bjs_getFileSize") -public func _bjs_getFileSize() -> Int32 { +public func _bjs_getFileSize() -> Int64 { #if arch(wasm32) let ret = getFileSize() return ret.bridgeJSLowerReturn() @@ -249,7 +249,7 @@ public func _bjs_getFileSize() -> Int32 { @_expose(wasm, "bjs_roundTripOptionalFileSize") @_cdecl("bjs_roundTripOptionalFileSize") -public func _bjs_roundTripOptionalFileSize(_ inputIsSome: Int32, _ inputValue: Int32) -> Void { +public func _bjs_roundTripOptionalFileSize(_ inputIsSome: Int32, _ inputValue: Int64) -> Void { #if arch(wasm32) let ret = roundTripOptionalFileSize(_: Optional.bridgeJSLiftParameter(inputIsSome, inputValue)) return ret.bridgeJSLowerReturn() @@ -324,7 +324,7 @@ public func _bjs_roundTripOptionalTokenId(_ inputIsSome: Int32, _ inputValue: In @_expose(wasm, "bjs_setSessionId") @_cdecl("bjs_setSessionId") -public func _bjs_setSessionId(_ session: Int32) -> Void { +public func _bjs_setSessionId(_ session: Int64) -> Void { #if arch(wasm32) setSessionId(_: SessionId.bridgeJSLiftParameter(session)) #else @@ -334,7 +334,7 @@ public func _bjs_setSessionId(_ session: Int32) -> Void { @_expose(wasm, "bjs_getSessionId") @_cdecl("bjs_getSessionId") -public func _bjs_getSessionId() -> Int32 { +public func _bjs_getSessionId() -> Int64 { #if arch(wasm32) let ret = getSessionId() return ret.bridgeJSLowerReturn() @@ -345,7 +345,7 @@ public func _bjs_getSessionId() -> Int32 { @_expose(wasm, "bjs_roundTripOptionalSessionId") @_cdecl("bjs_roundTripOptionalSessionId") -public func _bjs_roundTripOptionalSessionId(_ inputIsSome: Int32, _ inputValue: Int32) -> Void { +public func _bjs_roundTripOptionalSessionId(_ inputIsSome: Int32, _ inputValue: Int64) -> Void { #if arch(wasm32) let ret = roundTripOptionalSessionId(_: Optional.bridgeJSLiftParameter(inputIsSome, inputValue)) return ret.bridgeJSLowerReturn() @@ -442,7 +442,7 @@ public func _bjs_convertPriority(_ status: Int32) -> Int32 { @_expose(wasm, "bjs_validateSession") @_cdecl("bjs_validateSession") -public func _bjs_validateSession(_ session: Int32) -> Void { +public func _bjs_validateSession(_ session: Int64) -> Void { #if arch(wasm32) let ret = validateSession(_: SessionId.bridgeJSLiftParameter(session)) return ret.bridgeJSLowerReturn() diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json new file mode 100644 index 000000000..bef9cbc88 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json @@ -0,0 +1,471 @@ +{ + "exported" : { + "classes" : [ + + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_roundTripInt8", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripInt8", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + } + }, + { + "abiName" : "bjs_roundTripUInt8", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripUInt8", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + } + }, + { + "abiName" : "bjs_roundTripInt16", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripInt16", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + } + }, + { + "abiName" : "bjs_roundTripUInt16", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripUInt16", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + } + }, + { + "abiName" : "bjs_roundTripInt32", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripInt32", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + } + }, + { + "abiName" : "bjs_roundTripUInt32", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripUInt32", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + } + }, + { + "abiName" : "bjs_roundTripInt64", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripInt64", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + } + }, + { + "abiName" : "bjs_roundTripUInt64", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripUInt64", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "imported" : { + "children" : [ + { + "functions" : [ + { + "name" : "roundTripInt8", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + } + }, + { + "name" : "roundTripUInt8", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + } + }, + { + "name" : "roundTripInt16", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + } + }, + { + "name" : "roundTripUInt16", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + } + }, + { + "name" : "roundTripInt32", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + } + }, + { + "name" : "roundTripUInt32", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + } + }, + { + "name" : "roundTripInt64", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + } + }, + { + "name" : "roundTripUInt64", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + } + } + ], + "types" : [ + + ] + } + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.swift new file mode 100644 index 000000000..544a15e7c --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.swift @@ -0,0 +1,255 @@ +@_expose(wasm, "bjs_roundTripInt8") +@_cdecl("bjs_roundTripInt8") +public func _bjs_roundTripInt8(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundTripInt8(_: Int8.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripUInt8") +@_cdecl("bjs_roundTripUInt8") +public func _bjs_roundTripUInt8(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundTripUInt8(_: UInt8.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripInt16") +@_cdecl("bjs_roundTripInt16") +public func _bjs_roundTripInt16(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundTripInt16(_: Int16.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripUInt16") +@_cdecl("bjs_roundTripUInt16") +public func _bjs_roundTripUInt16(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundTripUInt16(_: UInt16.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripInt32") +@_cdecl("bjs_roundTripInt32") +public func _bjs_roundTripInt32(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundTripInt32(_: Int32.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripUInt32") +@_cdecl("bjs_roundTripUInt32") +public func _bjs_roundTripUInt32(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundTripUInt32(_: UInt32.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripInt64") +@_cdecl("bjs_roundTripInt64") +public func _bjs_roundTripInt64(_ v: Int64) -> Int64 { + #if arch(wasm32) + let ret = roundTripInt64(_: Int64.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripUInt64") +@_cdecl("bjs_roundTripUInt64") +public func _bjs_roundTripUInt64(_ v: Int64) -> Int64 { + #if arch(wasm32) + let ret = roundTripUInt64(_: UInt64.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripInt8") +fileprivate func bjs_roundTripInt8_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_roundTripInt8_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripInt8(_ v: Int32) -> Int32 { + return bjs_roundTripInt8_extern(v) +} + +func _$roundTripInt8(_ v: Int8) throws(JSException) -> Int8 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripInt8(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int8.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripUInt8") +fileprivate func bjs_roundTripUInt8_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_roundTripUInt8_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripUInt8(_ v: Int32) -> Int32 { + return bjs_roundTripUInt8_extern(v) +} + +func _$roundTripUInt8(_ v: UInt8) throws(JSException) -> UInt8 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripUInt8(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt8.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripInt16") +fileprivate func bjs_roundTripInt16_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_roundTripInt16_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripInt16(_ v: Int32) -> Int32 { + return bjs_roundTripInt16_extern(v) +} + +func _$roundTripInt16(_ v: Int16) throws(JSException) -> Int16 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripInt16(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int16.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripUInt16") +fileprivate func bjs_roundTripUInt16_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_roundTripUInt16_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripUInt16(_ v: Int32) -> Int32 { + return bjs_roundTripUInt16_extern(v) +} + +func _$roundTripUInt16(_ v: UInt16) throws(JSException) -> UInt16 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripUInt16(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt16.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripInt32") +fileprivate func bjs_roundTripInt32_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_roundTripInt32_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripInt32(_ v: Int32) -> Int32 { + return bjs_roundTripInt32_extern(v) +} + +func _$roundTripInt32(_ v: Int32) throws(JSException) -> Int32 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripInt32(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int32.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripUInt32") +fileprivate func bjs_roundTripUInt32_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_roundTripUInt32_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripUInt32(_ v: Int32) -> Int32 { + return bjs_roundTripUInt32_extern(v) +} + +func _$roundTripUInt32(_ v: UInt32) throws(JSException) -> UInt32 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripUInt32(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt32.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripInt64") +fileprivate func bjs_roundTripInt64_extern(_ v: Int64) -> Int64 +#else +fileprivate func bjs_roundTripInt64_extern(_ v: Int64) -> Int64 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripInt64(_ v: Int64) -> Int64 { + return bjs_roundTripInt64_extern(v) +} + +func _$roundTripInt64(_ v: Int64) throws(JSException) -> Int64 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripInt64(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int64.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripUInt64") +fileprivate func bjs_roundTripUInt64_extern(_ v: Int64) -> Int64 +#else +fileprivate func bjs_roundTripUInt64_extern(_ v: Int64) -> Int64 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripUInt64(_ v: Int64) -> Int64 { + return bjs_roundTripUInt64_extern(v) +} + +func _$roundTripUInt64(_ v: UInt64) throws(JSException) -> UInt64 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_roundTripUInt64(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt64.bridgeJSLiftReturn(ret) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json index b884e0cb9..7f79a8146 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json @@ -11,8 +11,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -22,8 +25,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json index 29cbddeb7..9ca72009d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json @@ -76,8 +76,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json index 619fe0689..0713a2f30 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json @@ -76,8 +76,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json index 9c99bb8c4..67d97821c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json @@ -134,8 +134,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -286,8 +289,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -298,8 +304,257 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripInt8", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripInt8", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripUInt8", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripUInt8", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripInt16", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripInt16", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripUInt16", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripUInt16", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripInt32", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripInt32", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripUInt32", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripUInt32", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } } }, "_1" : "null" @@ -601,8 +856,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -613,8 +871,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -699,8 +960,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -858,8 +1122,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -871,8 +1138,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "undefined" @@ -1057,8 +1327,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1069,8 +1342,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1085,8 +1361,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "undefined" @@ -1097,8 +1376,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "undefined" @@ -1198,8 +1480,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1212,8 +1497,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "undefined" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift index 8207bd488..0c6a79bf5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift @@ -42,6 +42,72 @@ public func _bjs_roundTripInt(_ valueIsSome: Int32, _ valueValue: Int32) -> Void #endif } +@_expose(wasm, "bjs_roundTripInt8") +@_cdecl("bjs_roundTripInt8") +public func _bjs_roundTripInt8(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripInt8(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripUInt8") +@_cdecl("bjs_roundTripUInt8") +public func _bjs_roundTripUInt8(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripUInt8(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripInt16") +@_cdecl("bjs_roundTripInt16") +public func _bjs_roundTripInt16(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripInt16(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripUInt16") +@_cdecl("bjs_roundTripUInt16") +public func _bjs_roundTripUInt16(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripUInt16(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripInt32") +@_cdecl("bjs_roundTripInt32") +public func _bjs_roundTripInt32(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripInt32(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripUInt32") +@_cdecl("bjs_roundTripUInt32") +public func _bjs_roundTripUInt32(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripUInt32(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundTripBool") @_cdecl("bjs_roundTripBool") public func _bjs_roundTripBool(_ flagIsSome: Int32, _ flagValue: Int32) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json index 8b586dbe0..f75bf7610 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json @@ -21,8 +21,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -30,8 +33,11 @@ "label" : "b", "name" : "b", "type" : { - "uint" : { - + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json index aae09ea49..cded9a973 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json @@ -20,8 +20,11 @@ ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -37,8 +40,11 @@ ], "returnType" : { - "uint" : { - + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json index 1c71b2b8f..24e3f44cd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json @@ -14,8 +14,11 @@ "label" : "intValue", "name" : "intValue", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -92,8 +95,11 @@ "isStatic" : false, "name" : "intValue", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -142,8 +148,11 @@ "isStatic" : false, "name" : "readonlyInt", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -222,8 +231,11 @@ "isStatic" : false, "name" : "computedReadonly", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -242,8 +254,11 @@ "isStatic" : false, "name" : "observedProperty", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -269,8 +284,11 @@ "label" : "intValue", "name" : "intValue", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json index e9f5264cd..757115c59 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json @@ -14,8 +14,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -47,8 +50,11 @@ "isStatic" : false, "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -131,8 +137,11 @@ "label" : "_", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -399,8 +408,11 @@ "associatedValues" : [ { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -550,8 +562,11 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -774,8 +789,11 @@ "isReadonly" : false, "name" : "eventCount", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json index b0eac3313..c241595a3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -27,8 +27,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -36,15 +39,21 @@ "label" : "b", "name" : "b", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -66,8 +75,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -75,15 +87,21 @@ "label" : "b", "name" : "b", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -105,8 +123,11 @@ "label" : "x", "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -114,15 +135,21 @@ "label" : "y", "name" : "y", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -166,15 +193,21 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -208,8 +241,11 @@ "associatedValues" : [ { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index e4ec22855..7c5df25b7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -27,8 +27,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -36,15 +39,21 @@ "label" : "b", "name" : "b", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -66,8 +75,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -75,15 +87,21 @@ "label" : "b", "name" : "b", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -105,8 +123,11 @@ "label" : "x", "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -114,15 +135,21 @@ "label" : "y", "name" : "y", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -166,15 +193,21 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -208,8 +241,11 @@ "associatedValues" : [ { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json index bb9e48091..d14f9b0a3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json @@ -43,8 +43,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -103,8 +106,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -179,8 +185,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -280,8 +289,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json index d385e3887..35d740dff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json @@ -43,8 +43,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -103,8 +106,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -179,8 +185,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -280,8 +289,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json index 11c6cb893..f610d4bde 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json @@ -215,8 +215,11 @@ "associatedValues" : [ { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -362,14 +365,20 @@ "moduleName" : "TestModule", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -387,14 +396,20 @@ "moduleName" : "TestModule", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -689,8 +704,11 @@ { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -700,8 +718,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -724,8 +745,11 @@ { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -735,8 +759,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json index 0013c810c..4359b50ec 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json @@ -9,8 +9,11 @@ { "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -25,14 +28,20 @@ "moduleName" : "TestModule", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -42,8 +51,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -53,8 +65,11 @@ { "name" : "base", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -68,14 +83,20 @@ "moduleName" : "TestModule", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 00c6af5cb..eeb567d4a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -186,8 +186,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -252,8 +255,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -311,8 +317,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -343,8 +352,11 @@ "isStatic" : false, "name" : "age", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -387,8 +399,11 @@ "isStatic" : false, "name" : "id", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -496,8 +511,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json index 50af441a9..c1329cd79 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json @@ -25,8 +25,11 @@ "isStatic" : false, "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -35,8 +38,11 @@ "isStatic" : false, "name" : "y", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -63,16 +69,22 @@ { "name" : "dx", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, { "name" : "dy", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index fcd29e31a..85e9c749a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -34,6 +34,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -116,6 +117,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_struct_lower_Point"] = function(objectId) { structHelpers.Point.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index d274e5606..bf368738e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index 67e73fb33..004320e4b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -27,6 +27,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -133,6 +134,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_struct_lower_Config"] = function(objectId) { structHelpers.Config.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 7c31ce220..1e9059e34 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 18cc2c945..eb474d3b0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -102,6 +102,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -824,6 +825,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_struct_lower_Point"] = function(objectId) { structHelpers.Point.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index a79d508a0..fe94c046f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -45,6 +45,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -115,6 +116,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index e52cf02d5..948039cf9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -65,6 +65,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -135,6 +136,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index 2d05a7a2d..5201350b2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -46,6 +46,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -116,6 +117,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts index 50a45a58d..fbd5ad637 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.d.ts @@ -46,10 +46,10 @@ export const PriorityValues: { export type PriorityTag = typeof PriorityValues[keyof typeof PriorityValues]; export const FileSizeValues: { - readonly Tiny: 1024; - readonly Small: 10240; - readonly Medium: 102400; - readonly Large: 1048576; + readonly Tiny: 1024n; + readonly Small: 10240n; + readonly Medium: 102400n; + readonly Large: 1048576n; }; export type FileSizeTag = typeof FileSizeValues[keyof typeof FileSizeValues]; @@ -68,9 +68,9 @@ export const TokenIdValues: { export type TokenIdTag = typeof TokenIdValues[keyof typeof TokenIdValues]; export const SessionIdValues: { - readonly None: 0; - readonly Active: 9876543210; - readonly Expired: 1234567890; + readonly None: 0n; + readonly Active: 9876543210n; + readonly Expired: 1234567890n; }; export type SessionIdTag = typeof SessionIdValues[keyof typeof SessionIdValues]; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 5d28ce60b..7e5334811 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -42,10 +42,10 @@ export const PriorityValues = { }; export const FileSizeValues = { - Tiny: 1024, - Small: 10240, - Medium: 102400, - Large: 1048576, + Tiny: 1024n, + Small: 10240n, + Medium: 102400n, + Large: 1048576n, }; export const UserIdValues = { @@ -61,9 +61,9 @@ export const TokenIdValues = { }; export const SessionIdValues = { - None: 0, - Active: 9876543210, - Expired: 1234567890, + None: 0n, + Active: 9876543210n, + Expired: 1234567890n, }; export const PrecisionValues = { @@ -96,6 +96,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -167,6 +168,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -426,8 +433,14 @@ export async function createInstantiator(options, swift) { roundTripOptionalFileSize: function bjs_roundTripOptionalFileSize(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalFileSize(+isSome, isSome ? input : 0); - const optResult = tmpRetOptionalInt; - tmpRetOptionalInt = undefined; + const isSome1 = i32Stack.pop(); + let optResult; + if (isSome1) { + const rawValue = i64Stack.pop(); + optResult = rawValue; + } else { + optResult = null; + } return optResult; }, setUserId: function bjs_setUserId(id) { @@ -435,7 +448,7 @@ export async function createInstantiator(options, swift) { }, getUserId: function bjs_getUserId() { const ret = instance.exports.bjs_getUserId(); - return ret; + return ret >>> 0; }, roundTripOptionalUserId: function bjs_roundTripOptionalUserId(input) { const isSome = input != null; @@ -449,7 +462,7 @@ export async function createInstantiator(options, swift) { }, getTokenId: function bjs_getTokenId() { const ret = instance.exports.bjs_getTokenId(); - return ret; + return ret >>> 0; }, roundTripOptionalTokenId: function bjs_roundTripOptionalTokenId(input) { const isSome = input != null; @@ -463,13 +476,19 @@ export async function createInstantiator(options, swift) { }, getSessionId: function bjs_getSessionId() { const ret = instance.exports.bjs_getSessionId(); - return ret; + return BigInt.asUintN(64, ret); }, roundTripOptionalSessionId: function bjs_roundTripOptionalSessionId(input) { const isSome = input != null; instance.exports.bjs_roundTripOptionalSessionId(+isSome, isSome ? input : 0); - const optResult = tmpRetOptionalInt; - tmpRetOptionalInt = undefined; + const isSome1 = i32Stack.pop(); + let optResult; + if (isSome1) { + const rawValue = i64Stack.pop(); + optResult = rawValue; + } else { + optResult = null; + } return optResult; }, setPrecision: function 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 new file mode 100644 index 000000000..d6ab5aa8f --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.d.ts @@ -0,0 +1,33 @@ +// 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 type Exports = { + roundTripInt8(v: number): number; + roundTripUInt8(v: number): number; + roundTripInt16(v: number): number; + roundTripUInt16(v: number): number; + roundTripInt32(v: number): number; + roundTripUInt32(v: number): number; + roundTripInt64(v: bigint): bigint; + roundTripUInt64(v: bigint): bigint; +} +export type Imports = { + roundTripInt8(v: number): number; + roundTripUInt8(v: number): number; + roundTripInt16(v: number): number; + roundTripUInt16(v: number): number; + roundTripInt32(v: number): number; + roundTripUInt32(v: number): number; + roundTripInt64(v: bigint): bigint; + roundTripUInt64(v: bigint): bigint; +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js new file mode 100644 index 000000000..53ddd7301 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js @@ -0,0 +1,317 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + + 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); + 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, len); + 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(); + } + 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) {} + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_roundTripInt8"] = function bjs_roundTripInt8(v) { + try { + let ret = imports.roundTripInt8(v); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_roundTripUInt8"] = function bjs_roundTripUInt8(v) { + try { + let ret = imports.roundTripUInt8(v >>> 0); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_roundTripInt16"] = function bjs_roundTripInt16(v) { + try { + let ret = imports.roundTripInt16(v); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_roundTripUInt16"] = function bjs_roundTripUInt16(v) { + try { + let ret = imports.roundTripUInt16(v >>> 0); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_roundTripInt32"] = function bjs_roundTripInt32(v) { + try { + let ret = imports.roundTripInt32(v); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_roundTripUInt32"] = function bjs_roundTripUInt32(v) { + try { + let ret = imports.roundTripUInt32(v >>> 0); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_roundTripInt64"] = function bjs_roundTripInt64(v) { + try { + let ret = imports.roundTripInt64(v); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_roundTripUInt64"] = function bjs_roundTripUInt64(v) { + try { + let ret = imports.roundTripUInt64(BigInt.asUintN(64, v)); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + }, + 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const exports = { + roundTripInt8: function bjs_roundTripInt8(v) { + const ret = instance.exports.bjs_roundTripInt8(v); + return ret; + }, + roundTripUInt8: function bjs_roundTripUInt8(v) { + const ret = instance.exports.bjs_roundTripUInt8(v); + return ret >>> 0; + }, + roundTripInt16: function bjs_roundTripInt16(v) { + const ret = instance.exports.bjs_roundTripInt16(v); + return ret; + }, + roundTripUInt16: function bjs_roundTripUInt16(v) { + const ret = instance.exports.bjs_roundTripUInt16(v); + return ret >>> 0; + }, + roundTripInt32: function bjs_roundTripInt32(v) { + const ret = instance.exports.bjs_roundTripInt32(v); + return ret; + }, + roundTripUInt32: function bjs_roundTripUInt32(v) { + const ret = instance.exports.bjs_roundTripUInt32(v); + return ret >>> 0; + }, + roundTripInt64: function bjs_roundTripInt64(v) { + const ret = instance.exports.bjs_roundTripInt64(v); + return ret; + }, + roundTripUInt64: function bjs_roundTripUInt64(v) { + const ret = instance.exports.bjs_roundTripUInt64(v); + return BigInt.asUintN(64, ret); + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js index 4d1e7abdf..346b74eac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js index e4a17ebd0..f74095374 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 7a97a47ff..06cf6550e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index cfb0f75e7..c469fcb58 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -130,6 +131,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_struct_lower_FooContainer"] = function(objectId) { structHelpers.FooContainer.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js index ca54d8f16..952197c2a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js index 7e97170e9..88a5adb38 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js index 39a859e4a..10fafb7a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 9ed0b93f2..08675da6a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -181,6 +182,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index 1b5651765..f4fe4dd61 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index 840a7a107..4ce318f40 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index 672d5ef7b..025a6fc8a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index 8401e96b4..4a6ee1990 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 9efb38ffa..267d96152 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts index b1a67ccde..a5a6e16fb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts @@ -50,6 +50,12 @@ export type Exports = { testOptionalPropertyRoundtrip(holder: OptionalPropertyHolder | null): OptionalPropertyHolder | null; roundTripString(name: string | null): string | null; roundTripInt(value: number | null): number | null; + roundTripInt8(value: number | null): number | null; + roundTripUInt8(value: number | null): number | null; + roundTripInt16(value: number | null): number | null; + roundTripUInt16(value: number | null): number | null; + roundTripInt32(value: number | null): number | null; + roundTripUInt32(value: number | null): number | null; roundTripBool(flag: boolean | null): boolean | null; roundTripFloat(number: number | null): number | null; roundTripDouble(precision: number | null): number | null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index f247c8efc..37408a42d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -661,6 +668,48 @@ export async function createInstantiator(options, swift) { tmpRetOptionalInt = undefined; return optResult; }, + roundTripInt8: function bjs_roundTripInt8(value) { + const isSome = value != null; + instance.exports.bjs_roundTripInt8(+isSome, isSome ? value : 0); + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return optResult; + }, + roundTripUInt8: function bjs_roundTripUInt8(value) { + const isSome = value != null; + instance.exports.bjs_roundTripUInt8(+isSome, isSome ? value : 0); + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return optResult; + }, + roundTripInt16: function bjs_roundTripInt16(value) { + const isSome = value != null; + instance.exports.bjs_roundTripInt16(+isSome, isSome ? value : 0); + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return optResult; + }, + roundTripUInt16: function bjs_roundTripUInt16(value) { + const isSome = value != null; + instance.exports.bjs_roundTripUInt16(+isSome, isSome ? value : 0); + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return optResult; + }, + roundTripInt32: function bjs_roundTripInt32(value) { + const isSome = value != null; + instance.exports.bjs_roundTripInt32(+isSome, isSome ? value : 0); + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return optResult; + }, + roundTripUInt32: function bjs_roundTripUInt32(value) { + const isSome = value != null; + instance.exports.bjs_roundTripUInt32(+isSome, isSome ? value : 0); + const optResult = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return optResult; + }, roundTripBool: function bjs_roundTripBool(flag) { const isSome = flag != null; instance.exports.bjs_roundTripBool(+isSome, isSome ? flag ? 1 : 0 : 0); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js index 770212417..490f2b4e2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js index 0efb2d2b5..bec07b959 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index 338e87f9a..658702a39 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 79711d878..e606c3a77 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -45,6 +45,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -148,6 +149,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js index ffdac6fa6..13070a3cc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -116,6 +117,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 800b07107..073784583 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -32,6 +32,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -135,6 +136,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index a4290f828..173bd6c27 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -32,6 +32,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -135,6 +136,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 056293ff7..9928804eb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -26,6 +26,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -96,6 +97,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index 06f032555..f82ac20df 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -26,6 +26,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -96,6 +97,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js index d602d4e5a..033f08cd2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js index b2241d6ca..8187b9e92 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 9acf70de2..4dd231e0e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index a0e874907..7e90c9415 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -51,6 +51,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -207,6 +208,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index 42ca68e78..d9df868ec 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -117,6 +118,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index cd2d396df..4334bec62 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -26,6 +26,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -281,6 +282,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_struct_lower_DataPoint"] = function(objectId) { structHelpers.DataPoint.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index cb161707a..d4f1160f3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -103,6 +104,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_struct_lower_Point"] = function(objectId) { structHelpers.Point.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js index ae9625f00..b2c381a03 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -91,6 +92,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index 169b001cf..ef81ef69e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -108,6 +109,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_struct_lower_PointerFields"] = function(objectId) { structHelpers.PointerFields.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js index cc6c0359b..97948b286 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js @@ -21,6 +21,7 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalHeapObject; let strStack = []; let i32Stack = []; + let i64Stack = []; let f32Stack = []; let f64Stack = []; let ptrStack = []; @@ -92,6 +93,12 @@ export async function createInstantiator(options, swift) { 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(); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index fd183583b..3dda6b28e 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -65,6 +65,8 @@ async function createInstantiator(options, swift) { swift_js_get_optional_heap_object_pointer: unexpectedBjsCall, swift_js_push_pointer: unexpectedBjsCall, swift_js_pop_pointer: unexpectedBjsCall, + swift_js_push_i64: unexpectedBjsCall, + swift_js_pop_i64: unexpectedBjsCall, swift_js_closure_unregister: unexpectedBjsCall, }; }, diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index c2d1c4cd8..180567ed1 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -261,39 +261,139 @@ extension UInt: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftSta } } -extension Int32: _BridgedSwiftStackType { +extension Int8: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { Int32(self) } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Int8 { + Int8(truncatingIfNeeded: value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Int8 { + Int8(truncatingIfNeeded: value) + } + @_spi(BridgeJS) public static func bridgeJSStackPop() -> Int8 { bridgeJSLiftParameter(_swift_js_pop_i32()) } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { Int32(self) } + @_spi(BridgeJS) public consuming func bridgeJSStackPush() { _swift_js_push_i32(Int32(self)) } +} + +extension UInt8: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { Int32(self) } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> UInt8 { + UInt8(truncatingIfNeeded: value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> UInt8 { + UInt8(truncatingIfNeeded: value) + } + @_spi(BridgeJS) public static func bridgeJSStackPop() -> UInt8 { bridgeJSLiftParameter(_swift_js_pop_i32()) } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { Int32(self) } + @_spi(BridgeJS) public consuming func bridgeJSStackPush() { _swift_js_push_i32(Int32(self)) } +} + +extension Int16: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { Int32(self) } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Int16 { + Int16(truncatingIfNeeded: value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Int16 { + Int16(truncatingIfNeeded: value) + } + @_spi(BridgeJS) public static func bridgeJSStackPop() -> Int16 { bridgeJSLiftParameter(_swift_js_pop_i32()) } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { Int32(self) } + @_spi(BridgeJS) public consuming func bridgeJSStackPush() { _swift_js_push_i32(Int32(self)) } +} + +extension UInt16: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { Int32(self) } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> UInt16 { + UInt16(truncatingIfNeeded: value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> UInt16 { + UInt16(truncatingIfNeeded: value) + } + @_spi(BridgeJS) public static func bridgeJSStackPop() -> UInt16 { bridgeJSLiftParameter(_swift_js_pop_i32()) } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { Int32(self) } + @_spi(BridgeJS) public consuming func bridgeJSStackPush() { _swift_js_push_i32(Int32(self)) } +} + +extension Int32: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { self } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Int32 { value } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Int32 { value } @_spi(BridgeJS) public static func bridgeJSStackPop() -> Int32 { _swift_js_pop_i32() } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { self } @_spi(BridgeJS) public consuming func bridgeJSStackPush() { _swift_js_push_i32(self) } } -extension Int64: _BridgedSwiftStackType { - @_spi(BridgeJS) public static func bridgeJSStackPop() -> Int64 { - Int64(_swift_js_pop_i32()) +extension UInt32: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { Int32(bitPattern: self) } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> UInt32 { + UInt32(bitPattern: value) } - @_spi(BridgeJS) public consuming func bridgeJSStackPush() { - _swift_js_push_i32(Int32(self)) + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> UInt32 { + UInt32(bitPattern: value) } -} - -extension UInt32: _BridgedSwiftStackType { @_spi(BridgeJS) public static func bridgeJSStackPop() -> UInt32 { UInt32(bitPattern: _swift_js_pop_i32()) } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { Int32(bitPattern: self) } @_spi(BridgeJS) public consuming func bridgeJSStackPush() { _swift_js_push_i32(Int32(bitPattern: self)) } } -extension UInt64: _BridgedSwiftStackType { +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_push_i64") +private func _swift_js_push_i64_extern(_ v: Int64) +#else +private func _swift_js_push_i64_extern(_ v: Int64) { + _onlyAvailableOnWasm() +} +#endif +@_spi(BridgeJS) @inline(never) public func _swift_js_push_i64(_ v: Int64) { + _swift_js_push_i64_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_pop_i64") +private func _swift_js_pop_i64_extern() -> Int64 +#else +private func _swift_js_pop_i64_extern() -> Int64 { + _onlyAvailableOnWasm() +} +#endif +@_spi(BridgeJS) @inline(never) public func _swift_js_pop_i64() -> Int64 { + return _swift_js_pop_i64_extern() +} + +extension Int64: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int64 { self } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int64) -> Int64 { value } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int64) -> Int64 { value } + @_spi(BridgeJS) public static func bridgeJSStackPop() -> Int64 { + Int64(bitPattern: UInt64(bitPattern: _swift_js_pop_i64())) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int64 { self } + @_spi(BridgeJS) public consuming func bridgeJSStackPush() { + _swift_js_push_i64(self) + } +} + +extension UInt64: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, _BridgedSwiftStackType { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int64 { Int64(bitPattern: self) } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int64) -> UInt64 { + UInt64(bitPattern: value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int64) -> UInt64 { + UInt64(bitPattern: value) + } @_spi(BridgeJS) public static func bridgeJSStackPop() -> UInt64 { - UInt64(UInt32(bitPattern: _swift_js_pop_i32())) + UInt64(bitPattern: _swift_js_pop_i64()) } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int64 { Int64(bitPattern: self) } @_spi(BridgeJS) public consuming func bridgeJSStackPush() { - _swift_js_push_i32(Int32(bitPattern: UInt32(self))) + _swift_js_push_i64(Int64(bitPattern: self)) } } @@ -1319,15 +1419,10 @@ public protocol _BridgedSwiftOptionalScalarSideChannelBridge: _BridgedSwiftOptio @_spi(BridgeJS) static func bridgeJSReadOptionalSideChannelPayload() -> WasmCoreType } -extension Bool: _BridgedSwiftOptionalScalarBridge { - @_spi(BridgeJS) public static func bridgeJSPopOptionalScalarPayload() -> Int32 { _swift_js_pop_i32() } - @_spi(BridgeJS) public static var bridgeJSOptionalScalarNonePayload: Int32 { 0 } - @_spi(BridgeJS) public static func bridgeJSWriteOptionalReturn(_ isSome: Int32, _ value: Int32) { - _swift_js_return_optional_bool(isSome, value) - } -} +private protocol _BridgedSwiftOptionalInt32SideChannelBridge: _BridgedSwiftOptionalScalarSideChannelBridge +where WasmCoreType == Int32 {} -extension Int: _BridgedSwiftOptionalScalarSideChannelBridge { +extension _BridgedSwiftOptionalInt32SideChannelBridge { @_spi(BridgeJS) public static func bridgeJSPopOptionalScalarPayload() -> Int32 { _swift_js_pop_i32() } @_spi(BridgeJS) public static var bridgeJSOptionalScalarNonePayload: Int32 { 0 } @_spi(BridgeJS) public static func bridgeJSWriteOptionalReturn(_ isSome: Int32, _ value: Int32) { @@ -1341,20 +1436,23 @@ extension Int: _BridgedSwiftOptionalScalarSideChannelBridge { } } -extension UInt: _BridgedSwiftOptionalScalarSideChannelBridge { +extension Bool: _BridgedSwiftOptionalScalarBridge { @_spi(BridgeJS) public static func bridgeJSPopOptionalScalarPayload() -> Int32 { _swift_js_pop_i32() } @_spi(BridgeJS) public static var bridgeJSOptionalScalarNonePayload: Int32 { 0 } @_spi(BridgeJS) public static func bridgeJSWriteOptionalReturn(_ isSome: Int32, _ value: Int32) { - _swift_js_return_optional_int(isSome, value) - } - @_spi(BridgeJS) public static func bridgeJSReadOptionalSideChannelPresence() -> Int32 { - _swift_js_get_optional_int_presence() - } - @_spi(BridgeJS) public static func bridgeJSReadOptionalSideChannelPayload() -> Int32 { - _swift_js_get_optional_int_value() + _swift_js_return_optional_bool(isSome, value) } } +extension Int: _BridgedSwiftOptionalInt32SideChannelBridge {} +extension UInt: _BridgedSwiftOptionalInt32SideChannelBridge {} +extension Int8: _BridgedSwiftOptionalInt32SideChannelBridge {} +extension UInt8: _BridgedSwiftOptionalInt32SideChannelBridge {} +extension Int16: _BridgedSwiftOptionalInt32SideChannelBridge {} +extension UInt16: _BridgedSwiftOptionalInt32SideChannelBridge {} +extension Int32: _BridgedSwiftOptionalInt32SideChannelBridge {} +extension UInt32: _BridgedSwiftOptionalInt32SideChannelBridge {} + extension Float: _BridgedSwiftOptionalScalarSideChannelBridge { @_spi(BridgeJS) public static func bridgeJSPopOptionalScalarPayload() -> Float32 { _swift_js_pop_f32() } @_spi(BridgeJS) public static var bridgeJSOptionalScalarNonePayload: Float32 { 0.0 } @@ -1750,115 +1848,69 @@ where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.Ra } extension _BridgedAsOptional -where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Int { - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> (isSome: Int32, value: Int32) { - switch asOptional { - case .none: - return (isSome: 0, value: 0) - case .some(let value): - return (isSome: 1, value: value.bridgeJSLowerParameter()) - } - } - - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Self { - let optionalRawValue = Optional.bridgeJSLiftParameter(isSome, wrappedValue) - return Self(optional: optionalRawValue.flatMap { Wrapped(rawValue: $0) }) - } - - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { - let isSome = _swift_js_get_optional_int_presence() - if isSome == 0 { - return Self(optional: nil) - } else { - let rawValue = _swift_js_get_optional_int_value() - return Self(optional: Wrapped(rawValue: Int(rawValue))) - } - } - - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - let optionalRawValue: Int? = asOptional?.rawValue - optionalRawValue.bridgeJSLowerReturn() +where + Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, + Wrapped.RawValue: _BridgedSwiftOptionalScalarBridge +{ + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> ( + isSome: Int32, value: Wrapped.RawValue.WasmCoreType + ) { + let optionalRawValue: Wrapped.RawValue? = asOptional?.rawValue + return optionalRawValue.bridgeJSLowerParameter() } -} -extension _BridgedAsOptional -where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Bool { - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Self { - let optionalRawValue = Optional.bridgeJSLiftParameter(isSome, wrappedValue) + @_spi(BridgeJS) public static func bridgeJSLiftParameter( + _ isSome: Int32, + _ wrappedValue: Wrapped.RawValue.WasmCoreType + ) -> Self { + let optionalRawValue = Optional.bridgeJSLiftParameter(isSome, wrappedValue) return Self(optional: optionalRawValue.flatMap { Wrapped(rawValue: $0) }) } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - let optionalRawValue: Bool? = asOptional?.rawValue + let optionalRawValue: Wrapped.RawValue? = asOptional?.rawValue optionalRawValue.bridgeJSLowerReturn() } } extension _BridgedAsOptional -where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Float { - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> ( - isSome: Int32, value: Float32 +where + Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: _BridgedSwiftRawValueEnum, Wrapped: RawRepresentable, + Wrapped.RawValue: _BridgedSwiftStackType, + Wrapped.RawValue: _BridgedSwiftTypeLoweredIntoSingleWasmCoreType, + Wrapped.RawValue.WasmCoreType == Int64 +{ + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> ( + isSome: Int32, value: Int64 ) { switch asOptional { case .none: - return (isSome: 0, value: 0.0) + return (isSome: 0, value: 0) case .some(let wrapped): return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) } } - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float32) -> Self { - let optionalRawValue = Optional.bridgeJSLiftParameter(isSome, wrappedValue) - return Self(optional: optionalRawValue.flatMap { Wrapped(rawValue: $0) }) - } - - @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { - let isSome = _swift_js_get_optional_float_presence() + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int64) -> Self { if isSome == 0 { return Self(optional: nil) - } else { - let rawValue = _swift_js_get_optional_float_value() - return Self(optional: Wrapped(rawValue: Float(rawValue))) } + return Self(optional: Wrapped(rawValue: Wrapped.RawValue.bridgeJSLiftParameter(wrappedValue))) } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - let optionalRawValue: Float? = asOptional?.rawValue - optionalRawValue.bridgeJSLowerReturn() + Wrapped.bridgeJSStackPushAsOptional(asOptional) } } extension _BridgedAsOptional -where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Double { - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> ( - isSome: Int32, value: Float64 - ) { - switch asOptional { - case .none: - return (isSome: 0, value: 0.0) - case .some(let wrapped): - return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) - } - } - - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float64) -> Self { - let optionalRawValue = Optional.bridgeJSLiftParameter(isSome, wrappedValue) - return Self(optional: optionalRawValue.flatMap { Wrapped(rawValue: $0) }) - } - +where + Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, + Wrapped.RawValue: _BridgedSwiftOptionalScalarSideChannelBridge +{ @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Self { - let isSome = _swift_js_get_optional_double_presence() - if isSome == 0 { - return Self(optional: nil) - } else { - let rawValue = _swift_js_get_optional_double_value() - return Self(optional: Wrapped(rawValue: Double(rawValue))) - } - } - - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - let optionalRawValue: Double? = asOptional?.rawValue - optionalRawValue.bridgeJSLowerReturn() + let optionalRawValue = Optional.bridgeJSLiftReturnFromSideChannel() + return Self(optional: optionalRawValue.flatMap { Wrapped(rawValue: $0) }) } } diff --git a/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json index 9403e3b0c..f57f91936 100644 --- a/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json @@ -138,8 +138,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -164,8 +167,11 @@ "GlobalUtils" ], "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -476,8 +482,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, diff --git a/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift b/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift index 6795c79ec..90c4b138e 100644 --- a/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/ArraySupportTests.swift @@ -190,6 +190,8 @@ final class ArraySupportTests: XCTestCase { @JS static func roundTripCaseEnumArray(_ v: [Direction]) -> [Direction] { v } @JS static func roundTripStringRawValueEnumArray(_ v: [Theme]) -> [Theme] { v } @JS static func roundTripIntRawValueEnumArray(_ v: [HttpStatus]) -> [HttpStatus] { v } + @JS static func roundTripInt64RawValueEnumArray(_ v: [FileSize]) -> [FileSize] { v } + @JS static func roundTripUInt64RawValueEnumArray(_ v: [SessionId]) -> [SessionId] { v } @JS static func roundTripStructArray(_ v: [DataPoint]) -> [DataPoint] { v } @JS static func roundTripSwiftClassArray(_ v: [Greeter]) -> [Greeter] { v } @JS static func roundTripNamespacedSwiftClassArray(_ v: [Utils.Converter]) -> [Utils.Converter] { v } @@ -202,6 +204,8 @@ final class ArraySupportTests: XCTestCase { @JS static func roundTripOptionalCaseEnumArray(_ v: [Direction?]) -> [Direction?] { v } @JS static func roundTripOptionalStringRawValueEnumArray(_ v: [Theme?]) -> [Theme?] { v } @JS static func roundTripOptionalIntRawValueEnumArray(_ v: [HttpStatus?]) -> [HttpStatus?] { v } + @JS static func roundTripOptionalInt64RawValueEnumArray(_ v: [FileSize?]) -> [FileSize?] { v } + @JS static func roundTripOptionalUInt64RawValueEnumArray(_ v: [SessionId?]) -> [SessionId?] { v } @JS static func roundTripOptionalStructArray(_ v: [DataPoint?]) -> [DataPoint?] { v } @JS static func roundTripOptionalSwiftClassArray(_ v: [Greeter?]) -> [Greeter?] { v } @JS static func roundTripOptionalJSClassArray(_ v: [ArrayElementObject?]) -> [ArrayElementObject?] { v } diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index d2fe49db2..595f6c051 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -10,12 +10,6 @@ func runJsWorks() -> Void return } -@JS func roundTripInt(v: Int) -> Int { - return v -} -@JS func roundTripUInt(v: UInt) -> UInt { - return v -} @JS func roundTripFloat(v: Float) -> Float { return v } @@ -225,6 +219,19 @@ struct TestError: Error { case unknown = -1 } +@JS enum FileSize: Int64 { + case tiny = 1024 + case small = 10240 + case medium = 102400 + case large = 1048576 +} + +@JS enum SessionId: UInt64 { + case none = 0 + case active = 9876543210 + case expired = 1234567890 +} + @JS enum Precision: Float { case rough = 0.1 case normal = 0.01 @@ -281,6 +288,22 @@ struct TestError: Error { return .ok } +@JS func setFileSize(_ size: FileSize) -> FileSize { + return size +} + +@JS func getFileSize() -> FileSize { + return .small +} + +@JS func setSessionId(_ session: SessionId) -> SessionId { + return session +} + +@JS func getSessionId() -> SessionId { + return .active +} + @JS func processTheme(_ theme: Theme) -> HttpStatus { switch theme { case .light: return .ok diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index e9c0e7653..e01761a8e 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -2685,6 +2685,28 @@ public func _bjs_ArraySupportExports_static_roundTripIntRawValueEnumArray() -> V #endif } +@_expose(wasm, "bjs_ArraySupportExports_static_roundTripInt64RawValueEnumArray") +@_cdecl("bjs_ArraySupportExports_static_roundTripInt64RawValueEnumArray") +public func _bjs_ArraySupportExports_static_roundTripInt64RawValueEnumArray() -> Void { + #if arch(wasm32) + let ret = ArraySupportExports.roundTripInt64RawValueEnumArray(_: [FileSize].bridgeJSStackPop()) + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ArraySupportExports_static_roundTripUInt64RawValueEnumArray") +@_cdecl("bjs_ArraySupportExports_static_roundTripUInt64RawValueEnumArray") +public func _bjs_ArraySupportExports_static_roundTripUInt64RawValueEnumArray() -> Void { + #if arch(wasm32) + let ret = ArraySupportExports.roundTripUInt64RawValueEnumArray(_: [SessionId].bridgeJSStackPop()) + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_ArraySupportExports_static_roundTripStructArray") @_cdecl("bjs_ArraySupportExports_static_roundTripStructArray") public func _bjs_ArraySupportExports_static_roundTripStructArray() -> Void { @@ -2808,6 +2830,28 @@ public func _bjs_ArraySupportExports_static_roundTripOptionalIntRawValueEnumArra #endif } +@_expose(wasm, "bjs_ArraySupportExports_static_roundTripOptionalInt64RawValueEnumArray") +@_cdecl("bjs_ArraySupportExports_static_roundTripOptionalInt64RawValueEnumArray") +public func _bjs_ArraySupportExports_static_roundTripOptionalInt64RawValueEnumArray() -> Void { + #if arch(wasm32) + let ret = ArraySupportExports.roundTripOptionalInt64RawValueEnumArray(_: [Optional].bridgeJSStackPop()) + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ArraySupportExports_static_roundTripOptionalUInt64RawValueEnumArray") +@_cdecl("bjs_ArraySupportExports_static_roundTripOptionalUInt64RawValueEnumArray") +public func _bjs_ArraySupportExports_static_roundTripOptionalUInt64RawValueEnumArray() -> Void { + #if arch(wasm32) + let ret = ArraySupportExports.roundTripOptionalUInt64RawValueEnumArray(_: [Optional].bridgeJSStackPop()) + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_ArraySupportExports_static_roundTripOptionalStructArray") @_cdecl("bjs_ArraySupportExports_static_roundTripOptionalStructArray") public func _bjs_ArraySupportExports_static_roundTripOptionalStructArray() -> Void { @@ -3223,6 +3267,12 @@ extension Theme: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { extension HttpStatus: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { } +extension FileSize: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension SessionId: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + extension Precision: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { } @@ -3935,6 +3985,116 @@ public func _bjs_StaticPropertyNamespace_NestedProperties_static_nestedDouble_se #endif } +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt") +public func _bjs_IntegerTypesSupportExports_static_roundTripInt(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripInt(_: Int.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripUInt") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripUInt") +public func _bjs_IntegerTypesSupportExports_static_roundTripUInt(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripUInt(_: UInt.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt8") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt8") +public func _bjs_IntegerTypesSupportExports_static_roundTripInt8(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripInt8(_: Int8.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripUInt8") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripUInt8") +public func _bjs_IntegerTypesSupportExports_static_roundTripUInt8(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripUInt8(_: UInt8.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt16") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt16") +public func _bjs_IntegerTypesSupportExports_static_roundTripInt16(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripInt16(_: Int16.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripUInt16") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripUInt16") +public func _bjs_IntegerTypesSupportExports_static_roundTripUInt16(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripUInt16(_: UInt16.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt32") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt32") +public func _bjs_IntegerTypesSupportExports_static_roundTripInt32(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripInt32(_: Int32.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripUInt32") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripUInt32") +public func _bjs_IntegerTypesSupportExports_static_roundTripUInt32(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripUInt32(_: UInt32.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt64") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt64") +public func _bjs_IntegerTypesSupportExports_static_roundTripInt64(_ v: Int64) -> Int64 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripInt64(_: Int64.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripUInt64") +@_cdecl("bjs_IntegerTypesSupportExports_static_roundTripUInt64") +public func _bjs_IntegerTypesSupportExports_static_roundTripUInt64(_ v: Int64) -> Int64 { + #if arch(wasm32) + let ret = IntegerTypesSupportExports.roundTripUInt64(_: UInt64.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_OptionalSupportExports_static_roundTripOptionalString") @_cdecl("bjs_OptionalSupportExports_static_roundTripOptionalString") public func _bjs_OptionalSupportExports_static_roundTripOptionalString(_ vIsSome: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { @@ -4034,6 +4194,28 @@ public func _bjs_OptionalSupportExports_static_roundTripOptionalIntRawValueEnum( #endif } +@_expose(wasm, "bjs_OptionalSupportExports_static_roundTripOptionalInt64RawValueEnum") +@_cdecl("bjs_OptionalSupportExports_static_roundTripOptionalInt64RawValueEnum") +public func _bjs_OptionalSupportExports_static_roundTripOptionalInt64RawValueEnum(_ vIsSome: Int32, _ vValue: Int64) -> Void { + #if arch(wasm32) + let ret = OptionalSupportExports.roundTripOptionalInt64RawValueEnum(_: Optional.bridgeJSLiftParameter(vIsSome, vValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_OptionalSupportExports_static_roundTripOptionalUInt64RawValueEnum") +@_cdecl("bjs_OptionalSupportExports_static_roundTripOptionalUInt64RawValueEnum") +public func _bjs_OptionalSupportExports_static_roundTripOptionalUInt64RawValueEnum(_ vIsSome: Int32, _ vValue: Int64) -> Void { + #if arch(wasm32) + let ret = OptionalSupportExports.roundTripOptionalUInt64RawValueEnum(_: Optional.bridgeJSLiftParameter(vIsSome, vValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_OptionalSupportExports_static_roundTripOptionalTSEnum") @_cdecl("bjs_OptionalSupportExports_static_roundTripOptionalTSEnum") public func _bjs_OptionalSupportExports_static_roundTripOptionalTSEnum(_ vIsSome: Int32, _ vValue: Int32) -> Void { @@ -5468,28 +5650,6 @@ public func _bjs_roundTripVoid() -> Void { #endif } -@_expose(wasm, "bjs_roundTripInt") -@_cdecl("bjs_roundTripInt") -public func _bjs_roundTripInt(_ v: Int32) -> Int32 { - #if arch(wasm32) - let ret = roundTripInt(v: Int.bridgeJSLiftParameter(v)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_roundTripUInt") -@_cdecl("bjs_roundTripUInt") -public func _bjs_roundTripUInt(_ v: Int32) -> Int32 { - #if arch(wasm32) - let ret = roundTripUInt(v: UInt.bridgeJSLiftParameter(v)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_roundTripFloat") @_cdecl("bjs_roundTripFloat") public func _bjs_roundTripFloat(_ v: Float32) -> Float32 { @@ -6136,6 +6296,50 @@ public func _bjs_getHttpStatus() -> Int32 { #endif } +@_expose(wasm, "bjs_setFileSize") +@_cdecl("bjs_setFileSize") +public func _bjs_setFileSize(_ size: Int64) -> Int64 { + #if arch(wasm32) + let ret = setFileSize(_: FileSize.bridgeJSLiftParameter(size)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getFileSize") +@_cdecl("bjs_getFileSize") +public func _bjs_getFileSize() -> Int64 { + #if arch(wasm32) + let ret = getFileSize() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_setSessionId") +@_cdecl("bjs_setSessionId") +public func _bjs_setSessionId(_ session: Int64) -> Int64 { + #if arch(wasm32) + let ret = setSessionId(_: SessionId.bridgeJSLiftParameter(session)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getSessionId") +@_cdecl("bjs_getSessionId") +public func _bjs_getSessionId() -> Int64 { + #if arch(wasm32) + let ret = getSessionId() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_processTheme") @_cdecl("bjs_processTheme") public func _bjs_processTheme(_ themeBytes: Int32, _ themeLength: Int32) -> Int32 { @@ -11501,6 +11705,235 @@ func _$jsTranslatePoint(_ point: Point, _ dx: Int, _ dy: Int) throws(JSException return Point.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripInt_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripInt_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripUInt_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripUInt_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripInt8_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt8_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt8_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt8_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripInt8_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripUInt8_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt8_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt8_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt8_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripUInt8_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripInt16_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt16_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt16_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt16_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripInt16_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripUInt16_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt16_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt16_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt16_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripUInt16_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripInt32_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt32_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt32_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt32_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripInt32_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripUInt32_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt32_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt32_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt32_static(_ v: Int32) -> Int32 { + return bjs_IntegerTypesSupportImports_jsRoundTripUInt32_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripInt64_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt64_static_extern(_ v: Int64) -> Int64 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt64_static_extern(_ v: Int64) -> Int64 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt64_static(_ v: Int64) -> Int64 { + return bjs_IntegerTypesSupportImports_jsRoundTripInt64_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripUInt64_static") +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt64_static_extern(_ v: Int64) -> Int64 +#else +fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt64_static_extern(_ v: Int64) -> Int64 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripUInt64_static(_ v: Int64) -> Int64 { + return bjs_IntegerTypesSupportImports_jsRoundTripUInt64_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_runJsIntegerTypesSupportTests_static") +fileprivate func bjs_IntegerTypesSupportImports_runJsIntegerTypesSupportTests_static_extern() -> Void +#else +fileprivate func bjs_IntegerTypesSupportImports_runJsIntegerTypesSupportTests_static_extern() -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IntegerTypesSupportImports_runJsIntegerTypesSupportTests_static() -> Void { + return bjs_IntegerTypesSupportImports_runJsIntegerTypesSupportTests_static_extern() +} + +func _$IntegerTypesSupportImports_jsRoundTripInt(_ v: Int) throws(JSException) -> Int { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripInt_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripUInt(_ v: UInt) throws(JSException) -> UInt { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripUInt_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripInt8(_ v: Int8) throws(JSException) -> Int8 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripInt8_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int8.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripUInt8(_ v: UInt8) throws(JSException) -> UInt8 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripUInt8_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt8.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripInt16(_ v: Int16) throws(JSException) -> Int16 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripInt16_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int16.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripUInt16(_ v: UInt16) throws(JSException) -> UInt16 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripUInt16_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt16.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripInt32(_ v: Int32) throws(JSException) -> Int32 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripInt32_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int32.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripUInt32(_ v: UInt32) throws(JSException) -> UInt32 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripUInt32_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt32.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripInt64(_ v: Int64) throws(JSException) -> Int64 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripInt64_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return Int64.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_jsRoundTripUInt64(_ v: UInt64) throws(JSException) -> UInt64 { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_IntegerTypesSupportImports_jsRoundTripUInt64_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return UInt64.bridgeJSLiftReturn(ret) +} + +func _$IntegerTypesSupportImports_runJsIntegerTypesSupportTests() throws(JSException) -> Void { + bjs_IntegerTypesSupportImports_runJsIntegerTypesSupportTests_static() + if let error = _swift_js_take_exception() { + throw error + } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSClassWithArrayMembers_init") fileprivate func bjs_JSClassWithArrayMembers_init_extern() -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 8a3656b65..cd8111566 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -16,8 +16,11 @@ "label" : "_", "name" : "base", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -31,14 +34,20 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -160,8 +169,11 @@ "label" : "_", "name" : "base", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -175,14 +187,20 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -330,8 +348,11 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -421,8 +442,11 @@ "isStatic" : false, "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -747,15 +771,21 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -772,8 +802,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -781,15 +814,21 @@ "label" : "b", "name" : "b", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -862,8 +901,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -888,8 +930,11 @@ "Utils" ], "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1066,8 +1111,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1083,8 +1131,11 @@ "isStatic" : false, "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1104,8 +1155,11 @@ "label" : "intValue", "name" : "intValue", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1191,8 +1245,11 @@ "isStatic" : false, "name" : "intValue", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1241,8 +1298,11 @@ "isStatic" : false, "name" : "readonlyInt", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1321,8 +1381,11 @@ "isStatic" : false, "name" : "computedReadonly", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1341,8 +1404,11 @@ "isStatic" : false, "name" : "observedProperty", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1364,8 +1430,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1373,15 +1442,21 @@ "label" : "b", "name" : "b", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -1403,8 +1478,11 @@ "label" : "a", "name" : "a", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1412,15 +1490,21 @@ "label" : "b", "name" : "b", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -1478,8 +1562,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1568,8 +1655,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1605,8 +1695,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1665,8 +1758,11 @@ "label" : "_", "name" : "amount", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -1757,8 +1853,11 @@ ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -1793,8 +1892,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1884,8 +1986,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -1907,8 +2012,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -2191,8 +2299,11 @@ "label" : "by", "name" : "amount", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -2215,8 +2326,11 @@ ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -2442,8 +2556,11 @@ "isStatic" : false, "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -2479,8 +2596,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -2808,8 +2928,11 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, { @@ -2946,8 +3069,11 @@ { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -3210,8 +3336,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -3221,8 +3350,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -3367,8 +3499,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -3915,8 +4050,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -4057,8 +4195,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -4068,8 +4209,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -4641,6 +4785,92 @@ } } }, + { + "abiName" : "bjs_ArraySupportExports_static_roundTripInt64RawValueEnumArray", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripInt64RawValueEnumArray", + "namespace" : [ + "ArraySupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "array" : { + "_0" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "ArraySupportExports" + } + } + }, + { + "abiName" : "bjs_ArraySupportExports_static_roundTripUInt64RawValueEnumArray", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripUInt64RawValueEnumArray", + "namespace" : [ + "ArraySupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "array" : { + "_0" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "ArraySupportExports" + } + } + }, { "abiName" : "bjs_ArraySupportExports_static_roundTripStructArray", "effects" : { @@ -4866,8 +5096,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -4882,8 +5115,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -5157,13 +5393,13 @@ } }, { - "abiName" : "bjs_ArraySupportExports_static_roundTripOptionalStructArray", + "abiName" : "bjs_ArraySupportExports_static_roundTripOptionalInt64RawValueEnumArray", "effects" : { "isAsync" : false, "isStatic" : true, "isThrows" : false }, - "name" : "roundTripOptionalStructArray", + "name" : "roundTripOptionalInt64RawValueEnumArray", "namespace" : [ "ArraySupportExports" ], @@ -5176,8 +5412,9 @@ "_0" : { "nullable" : { "_0" : { - "swiftStruct" : { - "_0" : "DataPoint" + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" } }, "_1" : "null" @@ -5192,8 +5429,9 @@ "_0" : { "nullable" : { "_0" : { - "swiftStruct" : { - "_0" : "DataPoint" + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" } }, "_1" : "null" @@ -5208,13 +5446,13 @@ } }, { - "abiName" : "bjs_ArraySupportExports_static_roundTripOptionalSwiftClassArray", + "abiName" : "bjs_ArraySupportExports_static_roundTripOptionalUInt64RawValueEnumArray", "effects" : { "isAsync" : false, "isStatic" : true, "isThrows" : false }, - "name" : "roundTripOptionalSwiftClassArray", + "name" : "roundTripOptionalUInt64RawValueEnumArray", "namespace" : [ "ArraySupportExports" ], @@ -5227,7 +5465,111 @@ "_0" : { "nullable" : { "_0" : { - "swiftHeapObject" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + }, + "_1" : "null" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + }, + "_1" : "null" + } + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "ArraySupportExports" + } + } + }, + { + "abiName" : "bjs_ArraySupportExports_static_roundTripOptionalStructArray", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripOptionalStructArray", + "namespace" : [ + "ArraySupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "array" : { + "_0" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "_1" : "null" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "_1" : "null" + } + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "ArraySupportExports" + } + } + }, + { + "abiName" : "bjs_ArraySupportExports_static_roundTripOptionalSwiftClassArray", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripOptionalSwiftClassArray", + "namespace" : [ + "ArraySupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "array" : { + "_0" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { "_0" : "Greeter" } }, @@ -5329,8 +5671,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5344,8 +5689,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5670,8 +6018,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5694,8 +6045,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5724,8 +6078,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5780,8 +6137,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5814,8 +6174,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5849,8 +6212,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -5971,15 +6337,21 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -6109,8 +6481,11 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -6377,8 +6752,11 @@ "label" : "count", "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -6514,8 +6892,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -6523,8 +6904,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -6558,8 +6942,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -6570,8 +6957,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -6628,8 +7018,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -6822,6 +7215,85 @@ { "associatedValues" : [ + ], + "name" : "tiny", + "rawValue" : "1024" + }, + { + "associatedValues" : [ + + ], + "name" : "small", + "rawValue" : "10240" + }, + { + "associatedValues" : [ + + ], + "name" : "medium", + "rawValue" : "102400" + }, + { + "associatedValues" : [ + + ], + "name" : "large", + "rawValue" : "1048576" + } + ], + "emitStyle" : "const", + "name" : "FileSize", + "rawType" : "Int64", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "FileSize", + "tsFullPath" : "FileSize" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "none", + "rawValue" : "0" + }, + { + "associatedValues" : [ + + ], + "name" : "active", + "rawValue" : "9876543210" + }, + { + "associatedValues" : [ + + ], + "name" : "expired", + "rawValue" : "1234567890" + } + ], + "emitStyle" : "const", + "name" : "SessionId", + "rawType" : "UInt64", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "SessionId", + "tsFullPath" : "SessionId" + }, + { + "cases" : [ + { + "associatedValues" : [ + ], "name" : "rough", "rawValue" : "0.1" @@ -7306,8 +7778,11 @@ "associatedValues" : [ { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -7393,8 +7868,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -7438,8 +7916,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -7497,15 +7978,21 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -7605,8 +8092,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -7624,8 +8114,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -7694,8 +8187,11 @@ }, { "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -7773,8 +8269,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -7924,15 +8423,21 @@ "label" : "_", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -8043,15 +8548,21 @@ "label" : "rootId", "name" : "rootId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -8078,15 +8589,21 @@ "label" : "graphId", "name" : "graphId", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "staticContext" : { @@ -8148,8 +8665,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -8178,8 +8698,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -8193,8 +8716,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -8294,8 +8820,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -8338,8 +8867,412 @@ } } ], - "swiftCallName" : "StaticPropertyNamespace.NestedProperties", - "tsFullPath" : "StaticPropertyNamespace.NestedProperties" + "swiftCallName" : "StaticPropertyNamespace.NestedProperties", + "tsFullPath" : "StaticPropertyNamespace.NestedProperties" + }, + { + "cases" : [ + + ], + "emitStyle" : "const", + "name" : "IntegerTypesSupportExports", + "staticMethods" : [ + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripInt", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripInt", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripUInt", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripUInt", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "word" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripInt8", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripInt8", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripUInt8", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripUInt8", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripInt16", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripInt16", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripUInt16", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripUInt16", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripInt32", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripInt32", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripUInt32", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripUInt32", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripInt64", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripInt64", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + }, + { + "abiName" : "bjs_IntegerTypesSupportExports_static_roundTripUInt64", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripUInt64", + "namespace" : [ + "IntegerTypesSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "IntegerTypesSupportExports" + } + } + } + ], + "staticProperties" : [ + + ], + "swiftCallName" : "IntegerTypesSupportExports", + "tsFullPath" : "IntegerTypesSupportExports" }, { "cases" : [ @@ -8409,8 +9342,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -8421,8 +9357,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -8739,6 +9678,96 @@ } } }, + { + "abiName" : "bjs_OptionalSupportExports_static_roundTripOptionalInt64RawValueEnum", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripOptionalInt64RawValueEnum", + "namespace" : [ + "OptionalSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + }, + "_1" : "null" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "OptionalSupportExports" + } + } + }, + { + "abiName" : "bjs_OptionalSupportExports_static_roundTripOptionalUInt64RawValueEnum", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripOptionalUInt64RawValueEnum", + "namespace" : [ + "OptionalSupportExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + }, + "_1" : "null" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "OptionalSupportExports" + } + } + }, { "abiName" : "bjs_OptionalSupportExports_static_roundTripOptionalTSEnum", "effects" : { @@ -8933,8 +9962,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -8949,8 +9981,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -9664,8 +10699,11 @@ "_0" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -9737,8 +10775,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -9778,8 +10819,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -9833,56 +10877,6 @@ } } }, - { - "abiName" : "bjs_roundTripInt", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "roundTripInt", - "parameters" : [ - { - "label" : "v", - "name" : "v", - "type" : { - "int" : { - - } - } - } - ], - "returnType" : { - "int" : { - - } - } - }, - { - "abiName" : "bjs_roundTripUInt", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "roundTripUInt", - "parameters" : [ - { - "label" : "v", - "name" : "v", - "type" : { - "uint" : { - - } - } - } - ], - "returnType" : { - "uint" : { - - } - } - }, { "abiName" : "bjs_roundTripFloat", "effects" : { @@ -10197,8 +11191,11 @@ "type" : { "dictionary" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -10208,8 +11205,11 @@ "returnType" : { "dictionary" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -10423,8 +11423,11 @@ ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -10560,15 +11563,21 @@ "label" : "v", "name" : "v", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -10795,8 +11804,11 @@ "label" : "x", "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -10804,15 +11816,21 @@ "label" : "y", "name" : "y", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -10907,128 +11925,218 @@ "isStatic" : false, "isThrows" : false }, - "name" : "getDirection", + "name" : "getDirection", + "parameters" : [ + + ], + "returnType" : { + "caseEnum" : { + "_0" : "Direction" + } + } + }, + { + "abiName" : "bjs_processDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processDirection", + "parameters" : [ + { + "label" : "_", + "name" : "input", + "type" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + ], + "returnType" : { + "caseEnum" : { + "_0" : "Status" + } + } + }, + { + "abiName" : "bjs_setTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setTheme", + "parameters" : [ + { + "label" : "_", + "name" : "theme", + "type" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + }, + { + "abiName" : "bjs_getTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getTheme", + "parameters" : [ + + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + }, + { + "abiName" : "bjs_setHttpStatus", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setHttpStatus", "parameters" : [ - + { + "label" : "_", + "name" : "status", + "type" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + } ], "returnType" : { - "caseEnum" : { - "_0" : "Direction" + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" } } }, { - "abiName" : "bjs_processDirection", + "abiName" : "bjs_getHttpStatus", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "processDirection", + "name" : "getHttpStatus", "parameters" : [ - { - "label" : "_", - "name" : "input", - "type" : { - "caseEnum" : { - "_0" : "Direction" - } - } - } + ], "returnType" : { - "caseEnum" : { - "_0" : "Status" + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" } } }, { - "abiName" : "bjs_setTheme", + "abiName" : "bjs_setFileSize", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "setTheme", + "name" : "setFileSize", "parameters" : [ { "label" : "_", - "name" : "theme", + "name" : "size", "type" : { "rawValueEnum" : { - "_0" : "Theme", - "_1" : "String" + "_0" : "FileSize", + "_1" : "Int64" } } } ], "returnType" : { "rawValueEnum" : { - "_0" : "Theme", - "_1" : "String" + "_0" : "FileSize", + "_1" : "Int64" } } }, { - "abiName" : "bjs_getTheme", + "abiName" : "bjs_getFileSize", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "getTheme", + "name" : "getFileSize", "parameters" : [ ], "returnType" : { "rawValueEnum" : { - "_0" : "Theme", - "_1" : "String" + "_0" : "FileSize", + "_1" : "Int64" } } }, { - "abiName" : "bjs_setHttpStatus", + "abiName" : "bjs_setSessionId", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "setHttpStatus", + "name" : "setSessionId", "parameters" : [ { "label" : "_", - "name" : "status", + "name" : "session", "type" : { "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" + "_0" : "SessionId", + "_1" : "UInt64" } } } ], "returnType" : { "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" + "_0" : "SessionId", + "_1" : "UInt64" } } }, { - "abiName" : "bjs_getHttpStatus", + "abiName" : "bjs_getSessionId", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "getHttpStatus", + "name" : "getSessionId", "parameters" : [ ], "returnType" : { "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" + "_0" : "SessionId", + "_1" : "UInt64" } } }, @@ -11185,8 +12293,11 @@ "label" : "value", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -11491,8 +12602,11 @@ "label" : "_", "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -11667,8 +12781,11 @@ "label" : "_", "name" : "code", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -11744,8 +12861,11 @@ "label" : "_", "name" : "code", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -11839,8 +12959,11 @@ "label" : "_", "name" : "count1", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -11848,8 +12971,11 @@ "label" : "_", "name" : "count2", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -11969,8 +13095,11 @@ "label" : "_", "name" : "code", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -12003,8 +13132,11 @@ "label" : "_", "name" : "code", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -12071,8 +13203,11 @@ "label" : "_", "name" : "code", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -12196,8 +13331,11 @@ "label" : "intValue", "name" : "intValue", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -12420,8 +13558,11 @@ "label" : "base", "name" : "base", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -12435,14 +13576,20 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -12960,8 +14107,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -12969,8 +14119,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -13029,8 +14182,11 @@ "isReadonly" : false, "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -13051,8 +14207,11 @@ "label" : "by", "name" : "amount", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -13075,8 +14234,11 @@ ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -13301,8 +14463,11 @@ "isReadonly" : false, "name" : "count", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -13335,8 +14500,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -13439,8 +14607,11 @@ "isStatic" : false, "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -13449,8 +14620,11 @@ "isStatic" : false, "name" : "y", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -13637,8 +14811,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -13703,8 +14880,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -13742,8 +14922,11 @@ "label" : "x", "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -13751,8 +14934,11 @@ "label" : "y", "name" : "y", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -13769,8 +14955,11 @@ "isStatic" : false, "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -13779,8 +14968,11 @@ "isStatic" : false, "name" : "y", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -13820,8 +15012,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -13852,8 +15047,11 @@ "isStatic" : false, "name" : "age", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -13971,8 +15169,11 @@ "isStatic" : false, "name" : "id", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14005,8 +15206,11 @@ "isStatic" : false, "name" : "id", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14064,8 +15268,11 @@ "isStatic" : false, "name" : "id", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14445,8 +15652,11 @@ "isStatic" : false, "name" : "x", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14489,8 +15699,11 @@ "isStatic" : false, "name" : "quantity", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -14537,8 +15750,11 @@ "isStatic" : false, "name" : "id", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14591,8 +15807,11 @@ "isStatic" : false, "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14621,8 +15840,11 @@ } }, "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14744,8 +15966,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -14753,8 +15978,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14802,8 +16030,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -14894,8 +16125,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -14903,8 +16137,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -14916,8 +16153,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -14927,8 +16167,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -15100,8 +16343,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -15116,8 +16362,11 @@ "_0" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -15445,8 +16694,11 @@ { "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15461,14 +16713,20 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15478,8 +16736,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15621,8 +16882,11 @@ { "name" : "base", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -15636,14 +16900,20 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15729,8 +16999,11 @@ { "name" : "value", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15745,8 +17018,11 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], @@ -15762,8 +17038,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15781,19 +17060,28 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15803,8 +17091,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15822,24 +17113,36 @@ "moduleName" : "BridgeJSRuntimeTests", "parameters" : [ { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15849,8 +17152,11 @@ } ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -15972,8 +17278,11 @@ ], "returnType" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, @@ -16049,8 +17358,11 @@ "type" : { "dictionary" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -16060,8 +17372,11 @@ "returnType" : { "dictionary" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -16820,16 +18135,22 @@ { "name" : "dx", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } }, { "name" : "dy", "type" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -16848,6 +18169,278 @@ { "functions" : [ + ], + "types" : [ + { + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "IntegerTypesSupportImports", + "setters" : [ + + ], + "staticMethods" : [ + { + "name" : "jsRoundTripInt", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "name" : "jsRoundTripUInt", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "word" + } + } + } + }, + { + "name" : "jsRoundTripInt8", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w8" + } + } + } + }, + { + "name" : "jsRoundTripUInt8", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w8" + } + } + } + }, + { + "name" : "jsRoundTripInt16", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w16" + } + } + } + }, + { + "name" : "jsRoundTripUInt16", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w16" + } + } + } + }, + { + "name" : "jsRoundTripInt32", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w32" + } + } + } + }, + { + "name" : "jsRoundTripUInt32", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w32" + } + } + } + }, + { + "name" : "jsRoundTripInt64", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "w64" + } + } + } + }, + { + "name" : "jsRoundTripUInt64", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : false, + "width" : "w64" + } + } + } + }, + { + "name" : "runJsIntegerTypesSupportTests", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ] + } + ] + }, + { + "functions" : [ + ], "types" : [ { @@ -16858,8 +18451,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -16885,8 +18481,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -16914,8 +18513,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -16925,8 +18527,11 @@ "returnType" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -16989,8 +18594,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -17034,8 +18642,11 @@ "type" : { "array" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } } } @@ -17221,8 +18832,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -17233,8 +18847,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "null" @@ -17249,8 +18866,11 @@ "type" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "undefined" @@ -17261,8 +18881,11 @@ "returnType" : { "nullable" : { "_0" : { - "int" : { - + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } } }, "_1" : "undefined" diff --git a/Tests/BridgeJSRuntimeTests/IntegerTypesSupportTests.swift b/Tests/BridgeJSRuntimeTests/IntegerTypesSupportTests.swift new file mode 100644 index 000000000..c4ed65d0c --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/IntegerTypesSupportTests.swift @@ -0,0 +1,73 @@ +import JavaScriptKit +import XCTest + +@JSClass struct IntegerTypesSupportImports { + @JSFunction static func jsRoundTripInt(_ v: Int) throws(JSException) -> Int + @JSFunction static func jsRoundTripUInt(_ v: UInt) throws(JSException) -> UInt + @JSFunction static func jsRoundTripInt8(_ v: Int8) throws(JSException) -> Int8 + @JSFunction static func jsRoundTripUInt8(_ v: UInt8) throws(JSException) -> UInt8 + @JSFunction static func jsRoundTripInt16(_ v: Int16) throws(JSException) -> Int16 + @JSFunction static func jsRoundTripUInt16(_ v: UInt16) throws(JSException) -> UInt16 + @JSFunction static func jsRoundTripInt32(_ v: Int32) throws(JSException) -> Int32 + @JSFunction static func jsRoundTripUInt32(_ v: UInt32) throws(JSException) -> UInt32 + @JSFunction static func jsRoundTripInt64(_ v: Int64) throws(JSException) -> Int64 + @JSFunction static func jsRoundTripUInt64(_ v: UInt64) throws(JSException) -> UInt64 + + @JSFunction static func runJsIntegerTypesSupportTests() throws(JSException) -> Void +} + +final class IntegerTypesSupportTests: XCTestCase { + func testRunJsIntegerTypesSupportTests() throws { + try IntegerTypesSupportImports.runJsIntegerTypesSupportTests() + } + + private func roundTripTest(_ fn: (T) throws -> T, _ input: [T]) throws { + for v in input { + let result = try fn(v) + XCTAssertEqual(result, v) + } + } + func testRoundTripInt() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripInt, [0, 1, -1, Int.min, Int.max]) + } + func testRoundTripUInt() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripUInt, [0, 1, UInt.max]) + } + func testRoundTripInt8() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripInt8, [0, 1, -1, Int8.min, Int8.max]) + } + func testRoundTripUInt8() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripUInt8, [0, 1, UInt8.max]) + } + func testRoundTripInt16() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripInt16, [0, 1, -1, Int16.min, Int16.max]) + } + func testRoundTripUInt16() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripUInt16, [0, 1, UInt16.max]) + } + func testRoundTripInt32() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripInt32, [0, 1, -1, Int32.min, Int32.max]) + } + func testRoundTripUInt32() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripUInt32, [0, 1, UInt32.max]) + } + func testRoundTripInt64() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripInt64, [0, 1, -1, Int64.min, Int64.max]) + } + func testRoundTripUInt64() throws { + try roundTripTest(IntegerTypesSupportImports.jsRoundTripUInt64, [0, 1, UInt64.max]) + } +} + +@JS enum IntegerTypesSupportExports { + @JS static func roundTripInt(_ v: Int) -> Int { v } + @JS static func roundTripUInt(_ v: UInt) -> UInt { v } + @JS static func roundTripInt8(_ v: Int8) -> Int8 { v } + @JS static func roundTripUInt8(_ v: UInt8) -> UInt8 { v } + @JS static func roundTripInt16(_ v: Int16) -> Int16 { v } + @JS static func roundTripUInt16(_ v: UInt16) -> UInt16 { v } + @JS static func roundTripInt32(_ v: Int32) -> Int32 { v } + @JS static func roundTripUInt32(_ v: UInt32) -> UInt32 { v } + @JS static func roundTripInt64(_ v: Int64) -> Int64 { v } + @JS static func roundTripUInt64(_ v: UInt64) -> UInt64 { v } +} diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/ArraySupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/ArraySupportTests.mjs index b877e9cf2..29ce274ce 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/ArraySupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/ArraySupportTests.mjs @@ -75,7 +75,7 @@ export function getImports(importsContext) { */ export function runJsArraySupportTests(rootExports) { const exports = rootExports.ArraySupportExports; - const { Direction, Status, Theme, HttpStatus, Greeter, Utils } = rootExports; + const { Direction, Status, Theme, HttpStatus, FileSize, SessionId, Greeter, Utils } = rootExports; // Primitive arrays assert.deepEqual(exports.roundTripIntArray([1, 2, 3, -10, 2147483647]), [1, 2, 3, -10, 2147483647]); @@ -112,6 +112,8 @@ export function runJsArraySupportTests(rootExports) { assert.deepEqual(exports.roundTripCaseEnumArray([Direction.North, Direction.South]), [Direction.North, Direction.South]); assert.deepEqual(exports.roundTripIntRawValueEnumArray([HttpStatus.Ok, HttpStatus.NotFound]), [HttpStatus.Ok, HttpStatus.NotFound]); assert.deepEqual(exports.roundTripStringRawValueEnumArray([Theme.Light, Theme.Dark]), [Theme.Light, Theme.Dark]); + assert.deepEqual(exports.roundTripInt64RawValueEnumArray([FileSize.Tiny, FileSize.Large]), [FileSize.Tiny, FileSize.Large]); + assert.deepEqual(exports.roundTripUInt64RawValueEnumArray([SessionId.None, SessionId.Active]), [SessionId.None, SessionId.Active]); // Struct arrays const points = [ @@ -172,6 +174,8 @@ export function runJsArraySupportTests(rootExports) { assert.equal(optPoints[1], null); assert.deepEqual(exports.roundTripOptionalCaseEnumArray([Direction.North, null]), [Direction.North, null]); assert.deepEqual(exports.roundTripOptionalIntRawValueEnumArray([HttpStatus.Ok, null]), [HttpStatus.Ok, null]); + assert.deepEqual(exports.roundTripOptionalInt64RawValueEnumArray([FileSize.Small, null]), [FileSize.Small, null]); + assert.deepEqual(exports.roundTripOptionalUInt64RawValueEnumArray([SessionId.Expired, null]), [SessionId.Expired, null]); assert.deepEqual(exports.roundTripOptionalJSClassArray([]), []); const optJsClassResult = exports.roundTripOptionalJSClassArray([foo1, null, foo2]); assert.equal(optJsClassResult.length, 3); @@ -205,4 +209,4 @@ export function runJsArraySupportTests(rootExports) { assert.deepEqual(exports.multiOptionalArraySecond(null, ["y"]), ["y"]); assert.deepEqual(exports.multiOptionalArrayFirst([5], null), [5]); assert.equal(exports.multiOptionalArraySecond([5], null), null); -} \ No newline at end of file +} diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs new file mode 100644 index 000000000..c66e1adcd --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs @@ -0,0 +1,175 @@ +// @ts-check + +import assert from 'node:assert'; + +/** + * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["IntegerTypesSupportImports"]} + */ +export function getImports(importsContext) { + return { + jsRoundTripInt: (v) => { + return v; + }, + jsRoundTripUInt: (v) => { + return v; + }, + jsRoundTripInt8: (v) => { + return v; + }, + jsRoundTripUInt8: (v) => { + return v; + }, + jsRoundTripInt16: (v) => { + return v; + }, + jsRoundTripUInt16: (v) => { + return v; + }, + jsRoundTripInt32: (v) => { + return v; + }, + jsRoundTripUInt32: (v) => { + return v; + }, + jsRoundTripInt64: (v) => { + return v; + }, + jsRoundTripUInt64: (v) => { + return v; + }, + runJsIntegerTypesSupportTests: () => { + const exports = importsContext.getExports(); + if (!exports) { throw new Error("No exports!?"); } + runJsIntegerTypesSupportTests(exports); + }, + } +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} rootExports + */ +export function runJsIntegerTypesSupportTests(rootExports) { + const exports = rootExports.IntegerTypesSupportExports; + const int8Min = -(1 << 7); + const int8Max = (1 << 7) - 1; + const uint8Max = (1 << 8) - 1; + const int16Min = -(1 << 15); + const int16Max = (1 << 15) - 1; + const uint16Max = (1 << 16) - 1; + const int32Min = -(2 ** 31); + const int32Max = (2 ** 31) - 1; + const uint32Max = (2 ** 32) - 1; + const int64Min = -(1n << 63n); + const int64Max = (1n << 63n) - 1n; + const uint64Max = (1n << 64n) - 1n; + + for (const v of [0, 1, -1, int32Min, int32Max]) { + assert.equal(exports.roundTripInt(v), v); + } + for (const v of [0, 1, uint32Max]) { + assert.equal(exports.roundTripUInt(v), v); + } + for (const [v, expected] of [ + [int32Max + 1, int32Min], + [int32Min - 1, int32Max], + ]) { + assert.equal(exports.roundTripInt(v), expected); + } + for (const [v, expected] of [ + [-1, uint32Max], + [uint32Max + 1, 0], + ]) { + assert.equal(exports.roundTripUInt(v), expected); + } + for (const v of [0, 1, -1, int8Min, int8Max]) { + assert.equal(exports.roundTripInt8(v), v); + } + for (const v of [0, 1, uint8Max]) { + assert.equal(exports.roundTripUInt8(v), v); + } + for (const v of [0, 1, -1, int16Min, int16Max]) { + assert.equal(exports.roundTripInt16(v), v); + } + for (const v of [0, 1, uint16Max]) { + assert.equal(exports.roundTripUInt16(v), v); + } + for (const v of [0, 1, -1, int32Min, int32Max]) { + assert.equal(exports.roundTripInt32(v), v); + } + for (const v of [0, 1, uint32Max]) { + assert.equal(exports.roundTripUInt32(v), v); + } + for (const [v, expected] of [ + [int8Max + 1, -128], + [int8Min - 1, 127], + ]) { + assert.equal(exports.roundTripInt8(v), expected); + } + for (const [v, expected] of [ + [-1, 255], + [uint8Max + 1, 0], + ]) { + assert.equal(exports.roundTripUInt8(v), expected); + } + for (const [v, expected] of [ + [int16Max + 1, -32768], + [int16Min - 1, 32767], + ]) { + assert.equal(exports.roundTripInt16(v), expected); + } + for (const [v, expected] of [ + [-1, 65535], + [uint16Max + 1, 0], + ]) { + assert.equal(exports.roundTripUInt16(v), expected); + } + for (const [v, expected] of [ + [int32Max + 1, int32Min], + [int32Min - 1, int32Max], + ]) { + assert.equal(exports.roundTripInt32(v), expected); + } + for (const [v, expected] of [ + [-1, uint32Max], + [uint32Max + 1, 0], + ]) { + assert.equal(exports.roundTripUInt32(v), expected); + } + for (const v of [ + 0n, 1n, -1n, + BigInt(Number.MIN_SAFE_INTEGER), + BigInt(Number.MAX_SAFE_INTEGER), + int64Min, + int64Max, + ]) { + assert.equal(exports.roundTripInt64(v), v); + } + for (const v of [ + 0n, 1n, + BigInt(Number.MAX_SAFE_INTEGER), + uint64Max, + ]) { + assert.equal(exports.roundTripUInt64(v), v); + } + for (const v of [ + int64Max + 1n, + int64Min - 1n, + uint64Max, + uint64Max + 1n, + -(1n << 64n), + (1n << 127n) - 1n, + ]) { + assert.equal(exports.roundTripInt64(v), BigInt.asIntN(64, v)); + } + for (const v of [ + -1n, + -2n, + int64Min, + int64Max, + uint64Max + 1n, + -(1n << 64n), + (1n << 127n) - 1n, + ]) { + assert.equal(exports.roundTripUInt64(v), BigInt.asUintN(64, v)); + } +} \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs index f9fa397f6..6576876da 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs @@ -5,6 +5,8 @@ import { StatusValues, ThemeValues, HttpStatusValues, + FileSizeValues, + SessionIdValues, TSDirection, TSTheme, APIResultValues, @@ -58,7 +60,7 @@ export function getImports(importsContext) { */ export function runJsOptionalSupportTests(rootExports) { const exports = rootExports.OptionalSupportExports; - const { Status, Theme, HttpStatus, Networking, ComplexResult, APIResult, Greeter, OptionalPropertyHolder, TypedPayloadResult, Direction } = rootExports; + const { Status, Theme, HttpStatus, FileSize, SessionId, Networking, ComplexResult, APIResult, Greeter, OptionalPropertyHolder, TypedPayloadResult, Direction } = rootExports; assert.equal(exports.roundTripOptionalString(null), null); assert.equal(exports.roundTripOptionalInt(null), null); assert.equal(exports.roundTripOptionalBool(null), null); @@ -76,6 +78,8 @@ export function runJsOptionalSupportTests(rootExports) { assert.equal(exports.roundTripOptionalCaseEnum(Status.Success), StatusValues.Success); assert.equal(exports.roundTripOptionalStringRawValueEnum(Theme.Light), ThemeValues.Light); assert.equal(exports.roundTripOptionalIntRawValueEnum(HttpStatus.Ok), HttpStatusValues.Ok); + assert.equal(exports.roundTripOptionalInt64RawValueEnum(FileSize.Tiny), FileSizeValues.Tiny); + assert.equal(exports.roundTripOptionalUInt64RawValueEnum(SessionId.Active), SessionIdValues.Active); assert.equal(exports.roundTripOptionalTSEnum(TSDirection.North), TSDirection.North); assert.equal(exports.roundTripOptionalTSStringEnum(TSTheme.Light), TSTheme.Light); assert.equal(exports.roundTripOptionalNamespacedEnum(Networking.API.Method.Get), Networking.API.Method.Get); diff --git a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift index 7f9708f57..3b06901db 100644 --- a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift @@ -96,6 +96,8 @@ final class OptionalSupportTests: XCTestCase { @JS static func roundTripOptionalCaseEnum(_ v: Status?) -> Status? { v } @JS static func roundTripOptionalStringRawValueEnum(_ v: Theme?) -> Theme? { v } @JS static func roundTripOptionalIntRawValueEnum(_ v: HttpStatus?) -> HttpStatus? { v } + @JS static func roundTripOptionalInt64RawValueEnum(_ v: FileSize?) -> FileSize? { v } + @JS static func roundTripOptionalUInt64RawValueEnum(_ v: SessionId?) -> SessionId? { v } @JS static func roundTripOptionalTSEnum(_ v: TSDirection?) -> TSDirection? { v } @JS static func roundTripOptionalTSStringEnum(_ v: TSTheme?) -> TSTheme? { v } @JS static func roundTripOptionalNamespacedEnum(_ v: Networking.API.Method?) -> Networking.API.Method? { v } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index ca2da4324..265781bff 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -1,7 +1,7 @@ // @ts-check import { - DirectionValues, StatusValues, ThemeValues, HttpStatusValues, TSDirection, TSTheme, APIResultValues, ComplexResultValues, APIOptionalResultValues, StaticCalculatorValues, StaticPropertyEnumValues, PrecisionValues, TypedPayloadResultValues, AllTypesResultValues, OptionalAllTypesResultValues + DirectionValues, StatusValues, ThemeValues, HttpStatusValues, FileSizeValues, SessionIdValues, TSDirection, TSTheme, APIResultValues, ComplexResultValues, APIOptionalResultValues, StaticCalculatorValues, StaticPropertyEnumValues, PrecisionValues, TypedPayloadResultValues, AllTypesResultValues, OptionalAllTypesResultValues } from '../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.js'; import { ImportedFoo } from './BridgeJSRuntimeTests/JavaScript/Types.mjs'; import { runJsOptionalSupportTests } from './BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs'; @@ -12,6 +12,7 @@ import { getImports as getArraySupportImports, ArrayElementObject } from './Brid import { getImports as getDictionarySupportImports } from './BridgeJSRuntimeTests/JavaScript/DictionarySupportTests.mjs'; import { getImports as getDefaultArgumentImports } from './BridgeJSRuntimeTests/JavaScript/DefaultArgumentTests.mjs'; import { getImports as getJSClassSupportImports, JSClassWithArrayMembers } from './BridgeJSRuntimeTests/JavaScript/JSClassSupportTests.mjs'; +import { getImports as getIntegerTypesSupportImports } from './BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs'; /** @type {import('../.build/plugins/PackageToJS/outputs/PackageTests/test.d.ts').SetupOptionsFn} */ export async function setupOptions(options, context) { @@ -144,6 +145,7 @@ export async function setupOptions(options, context) { DictionarySupportImports: getDictionarySupportImports(importsContext), DefaultArgumentImports: getDefaultArgumentImports(importsContext), JSClassSupportImports: getJSClassSupportImports(importsContext), + IntegerTypesSupportImports: getIntegerTypesSupportImports(importsContext), }; }, addToCoreImports(importObject, importsContext) { @@ -182,12 +184,6 @@ import assert from "node:assert"; /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { exports.roundTripVoid(); - for (const v of [0, 1, -1, 2147483647, -2147483648]) { - assert.equal(exports.roundTripInt(v), v); - } - for (const v of [0, 1, 2147483647, 4294967295]) { - assert.equal(exports.roundTripUInt(v), v); - } for (const v of [ 0.0, 1.0, -1.0, NaN, @@ -534,6 +530,10 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(exports.HttpStatus.NotFound, 404); assert.equal(HttpStatusValues.ServerError, 500); assert.equal(HttpStatusValues.Unknown, -1); + assert.equal(exports.FileSize.Tiny, 1024n); + assert.equal(FileSizeValues.Large, 1048576n); + assert.equal(exports.SessionId.None, 0n); + assert.equal(SessionIdValues.Active, 9876543210n); assert.equal(exports.Precision.Rough, 0.1); assert.equal(exports.Precision.Normal, 0.01); @@ -547,6 +547,10 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(exports.getTheme(), ThemeValues.Light); assert.equal(exports.setHttpStatus(exports.HttpStatus.Ok), HttpStatusValues.Ok); assert.equal(exports.getHttpStatus(), exports.HttpStatus.Ok); + assert.equal(exports.setFileSize(exports.FileSize.Medium), FileSizeValues.Medium); + assert.equal(exports.getFileSize(), FileSizeValues.Small); + assert.equal(exports.setSessionId(exports.SessionId.Expired), SessionIdValues.Expired); + assert.equal(exports.getSessionId(), SessionIdValues.Active); assert.equal(exports.processTheme(exports.Theme.Light), exports.HttpStatus.Ok); assert.equal(exports.processTheme(exports.Theme.Dark), HttpStatusValues.NotFound); From abf1c88b7cbb455bcab2158b6ace30a5c7936d8c Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 16 Mar 2026 21:56:48 +0000 Subject: [PATCH 16/68] Revert "BridgeJS: Correctly emit @JS methods in extensions" (#703) Revert of https://github.com/swiftwasm/JavaScriptKit/pull/694. Required to unblock CI on https://github.com/swiftwasm/JavaScriptKit/pull/702. --- .../BridgeJSCore/SwiftToSkeleton.swift | 72 +----- .../BridgeJSCodegenTests.swift | 17 -- .../Multifile/CrossFileExtension.swift | 5 - .../Multifile/CrossFileExtensionClass.swift | 4 - .../Inputs/MacroSwift/StaticFunctions.swift | 16 -- .../Inputs/MacroSwift/SwiftClass.swift | 14 - .../Inputs/MacroSwift/SwiftStruct.swift | 23 -- .../CrossFileExtension.json | 82 ------ .../CrossFileExtension.swift | 60 ----- .../StaticFunctions.Global.json | 97 ------- .../StaticFunctions.Global.swift | 44 ---- .../BridgeJSCodegenTests/StaticFunctions.json | 97 ------- .../StaticFunctions.swift | 44 ---- .../BridgeJSCodegenTests/SwiftClass.json | 64 ----- .../BridgeJSCodegenTests/SwiftClass.swift | 44 ---- .../BridgeJSCodegenTests/SwiftStruct.json | 106 -------- .../BridgeJSCodegenTests/SwiftStruct.swift | 92 ------- .../StaticFunctions.Global.d.ts | 4 - .../StaticFunctions.Global.js | 18 -- .../BridgeJSLinkTests/StaticFunctions.d.ts | 4 - .../BridgeJSLinkTests/StaticFunctions.js | 18 -- .../BridgeJSLinkTests/SwiftClass.d.ts | 4 - .../BridgeJSLinkTests/SwiftClass.js | 22 -- .../BridgeJSLinkTests/SwiftStruct.d.ts | 8 - .../BridgeJSLinkTests/SwiftStruct.js | 42 --- .../Exporting-Swift/Exporting-Swift-Class.md | 48 ---- .../Exporting-Swift/Exporting-Swift-Enum.md | 1 - .../Exporting-Swift/Exporting-Swift-Struct.md | 1 - .../BridgeJSRuntimeTests/ExportAPITests.swift | 22 -- .../Generated/BridgeJS.swift | 169 ------------ .../Generated/JavaScript/BridgeJS.json | 242 ------------------ Tests/BridgeJSRuntimeTests/StructAPIs.swift | 28 -- Tests/prelude.mjs | 24 -- 33 files changed, 1 insertion(+), 1535 deletions(-) delete mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift delete mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift delete mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json delete mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 482b1fff5..81ad32813 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -43,14 +43,12 @@ public final class SwiftToSkeleton { var perSourceErrors: [(inputFilePath: String, errors: [DiagnosticError])] = [] var importedFiles: [ImportedFileSkeleton] = [] var exported = ExportedSkeleton(functions: [], classes: [], enums: [], exposeToGlobal: exposeToGlobal) - var exportCollectors: [ExportSwiftAPICollector] = [] for (sourceFile, inputFilePath) in sourceFiles { progress.print("Processing \(inputFilePath)") let exportCollector = ExportSwiftAPICollector(parent: self) exportCollector.walk(sourceFile) - exportCollectors.append(exportCollector) let typeNameCollector = ImportSwiftMacrosJSImportTypeNameCollector(viewMode: .sourceAccurate) typeNameCollector.walk(sourceFile) @@ -76,15 +74,7 @@ public final class SwiftToSkeleton { if !importedFile.isEmpty { importedFiles.append(importedFile) } - } - - // Resolve extensions against all collectors. This needs to happen at this point so we can resolve both same file and cross file extensions. - for source in exportCollectors { - source.resolveDeferredExtensions(against: exportCollectors) - } - - for collector in exportCollectors { - collector.finalize(&exported) + exportCollector.finalize(&exported) } if !perSourceErrors.isEmpty { @@ -496,8 +486,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { var exportedStructNames: [String] = [] var exportedStructByName: [String: ExportedStruct] = [:] var errors: [DiagnosticError] = [] - /// Extensions collected during the walk, to be resolved after all files have been walked - var deferredExtensions: [ExtensionDeclSyntax] = [] func finalize(_ result: inout ExportedSkeleton) { result.functions.append(contentsOf: exportedFunctions) @@ -1400,64 +1388,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } - override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { - // Defer until all type declarations in the module have been collected. - deferredExtensions.append(node) - return .skipChildren - } - - func resolveDeferredExtensions(against collectors: [ExportSwiftAPICollector]) { - for ext in deferredExtensions { - var resolved = false - for collector in collectors { - if collector.resolveExtension(ext) { - resolved = true - break - } - } - if !resolved { - diagnose( - node: ext.extendedType, - message: "Unsupported type '\(ext.extendedType.trimmedDescription)'.", - hint: "You can only extend `@JS` annotated types defined in the same module" - ) - } - } - } - - /// Walks extension members under the matching type’s state, returning whether the type was found. - /// - /// Note: The lookup scans dictionaries keyed by `makeKey(name:namespace:)`, matching only by - /// plain name. If two types share a name but differ by namespace, `.first(where:)` picks - /// whichever comes first. This is acceptable today since namespace collisions are unlikely, - /// but may need refinement if namespace-qualified extension resolution is added. - func resolveExtension(_ ext: ExtensionDeclSyntax) -> Bool { - let name = ext.extendedType.trimmedDescription - let state: State - if let entry = exportedClassByName.first(where: { $0.value.name == name }) { - state = .classBody(name: name, key: entry.key) - } else if let entry = exportedStructByName.first(where: { $0.value.name == name }) { - state = .structBody(name: name, key: entry.key) - } else if let entry = exportedEnumByName.first(where: { $0.value.name == name }) { - state = .enumBody(name: name, key: entry.key) - } else if exportedProtocolByName.values.contains(where: { $0.name == name }) { - diagnose( - node: ext.extendedType, - message: "Protocol extensions are not supported by BridgeJS.", - hint: "You cannot extend `@JS` protocol '\(name)' with additional members" - ) - return true - } else { - return false - } - stateStack.push(state: state) - for member in ext.memberBlock.members { - walk(member) - } - stateStack.pop() - return true - } - override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index dd0ce5d03..9754fbced 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -167,23 +167,6 @@ import Testing try snapshotCodegen(skeleton: skeleton, name: "CrossFileFunctionTypes.ReverseOrder") } - @Test - func codegenCrossFileExtension() throws { - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) - let classURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtensionClass.swift") - swiftAPI.addSourceFile( - Parser.parse(source: try String(contentsOf: classURL, encoding: .utf8)), - inputFilePath: "CrossFileExtensionClass.swift" - ) - let extensionURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtension.swift") - swiftAPI.addSourceFile( - Parser.parse(source: try String(contentsOf: extensionURL, encoding: .utf8)), - inputFilePath: "CrossFileExtension.swift" - ) - let skeleton = try swiftAPI.finalize() - try snapshotCodegen(skeleton: skeleton, name: "CrossFileExtension") - } - @Test func codegenSkipsEmptySkeletons() throws { let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift deleted file mode 100644 index ce9e8e2b0..000000000 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift +++ /dev/null @@ -1,5 +0,0 @@ -extension Greeter { - @JS func greetFormally() -> String { - return "Good day, " + self.name + "." - } -} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift deleted file mode 100644 index 48625d42a..000000000 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift +++ /dev/null @@ -1,4 +0,0 @@ -@JS class Greeter { - @JS init(name: String) {} - @JS func greet() -> String { return "" } -} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift index 4f6296d2e..1d42cf415 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift @@ -38,19 +38,3 @@ enum APIResult { } } } - -extension MathUtils { - @JS static func divide(a: Int, b: Int) -> Int { - return a / b - } - - @JS static var pi: Double { 3.14159 } -} - -extension Calculator { - @JS static func cube(value: Int) -> Int { - return value * value * value - } - - @JS static var version: String { "1.0" } -} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift index 2fb050eeb..d7b5a5b8e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift @@ -12,20 +12,6 @@ } } -extension Greeter { - @JS func greetEnthusiastically() -> String { - return "Hey, " + self.name + "!!!" - } - - @JS var nameCount: Int { name.count } - - @JS static func greetAnonymously() -> String { - return "Hello." - } - - @JS static var defaultGreeting: String { "Hello, world!" } -} - @JS func takeGreeter(greeter: Greeter) { print(greeter.greet()) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift index 63bb0ff8d..0d84f4736 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift @@ -60,26 +60,3 @@ } @JS func roundtripContainer(_ container: Container) -> Container - -@JS struct Vector2D { - var dx: Double - var dy: Double -} - -extension Vector2D { - @JS func magnitude() -> Double { - return (dx * dx + dy * dy).squareRoot() - } - - @JS func scaled(by factor: Double) -> Vector2D { - return Vector2D(dx: dx * factor, dy: dy * factor) - } -} - -extension DataPoint { - @JS static func origin() -> DataPoint { - return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) - } - - @JS static var dimensions: Int { 2 } -} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json deleted file mode 100644 index f77d39ad9..000000000 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "exported" : { - "classes" : [ - { - "constructor" : { - "abiName" : "bjs_Greeter_init", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "parameters" : [ - { - "label" : "name", - "name" : "name", - "type" : { - "string" : { - - } - } - } - ] - }, - "methods" : [ - { - "abiName" : "bjs_Greeter_greet", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "greet", - "parameters" : [ - - ], - "returnType" : { - "string" : { - - } - } - }, - { - "abiName" : "bjs_Greeter_greetFormally", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "greetFormally", - "parameters" : [ - - ], - "returnType" : { - "string" : { - - } - } - } - ], - "name" : "Greeter", - "properties" : [ - - ], - "swiftCallName" : "Greeter" - } - ], - "enums" : [ - - ], - "exposeToGlobal" : false, - "functions" : [ - - ], - "protocols" : [ - - ], - "structs" : [ - - ] - }, - "moduleName" : "TestModule" -} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift deleted file mode 100644 index ab73df508..000000000 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift +++ /dev/null @@ -1,60 +0,0 @@ -@_expose(wasm, "bjs_Greeter_init") -@_cdecl("bjs_Greeter_init") -public func _bjs_Greeter_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { - #if arch(wasm32) - let ret = Greeter(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Greeter_greet") -@_cdecl("bjs_Greeter_greet") -public func _bjs_Greeter_greet(_ _self: UnsafeMutableRawPointer) -> Void { - #if arch(wasm32) - let ret = Greeter.bridgeJSLiftParameter(_self).greet() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Greeter_greetFormally") -@_cdecl("bjs_Greeter_greetFormally") -public func _bjs_Greeter_greetFormally(_ _self: UnsafeMutableRawPointer) -> Void { - #if arch(wasm32) - let ret = Greeter.bridgeJSLiftParameter(_self).greetFormally() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Greeter_deinit") -@_cdecl("bjs_Greeter_deinit") -public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { - #if arch(wasm32) - Unmanaged.fromOpaque(pointer).release() - #else - fatalError("Only available on WebAssembly") - #endif -} - -extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { - var jsValue: JSValue { - return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) - } -} - -#if arch(wasm32) -@_extern(wasm, module: "TestModule", name: "bjs_Greeter_wrap") -fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 -#else -fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { - fatalError("Only available on WebAssembly") -} -#endif -@inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { - return _bjs_Greeter_wrap_extern(pointer) -} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json index 7e332fe3a..c241595a3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -152,64 +152,11 @@ } } } - }, - { - "abiName" : "bjs_MathUtils_static_divide", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "divide", - "parameters" : [ - { - "label" : "a", - "name" : "a", - "type" : { - "int" : { - - } - } - }, - { - "label" : "b", - "name" : "b", - "type" : { - "int" : { - - } - } - } - ], - "returnType" : { - "int" : { - - } - }, - "staticContext" : { - "className" : { - "_0" : "MathUtils" - } - } } ], "name" : "MathUtils", "properties" : [ - { - "isReadonly" : true, - "isStatic" : true, - "name" : "pi", - "staticContext" : { - "className" : { - "_0" : "MathUtils" - } - }, - "type" : { - "double" : { - } - } - } ], "swiftCallName" : "MathUtils" } @@ -268,54 +215,10 @@ "_0" : "Calculator" } } - }, - { - "abiName" : "bjs_Calculator_static_cube", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "cube", - "parameters" : [ - { - "label" : "value", - "name" : "value", - "type" : { - "int" : { - - } - } - } - ], - "returnType" : { - "int" : { - - } - }, - "staticContext" : { - "enumName" : { - "_0" : "Calculator" - } - } } ], "staticProperties" : [ - { - "isReadonly" : true, - "isStatic" : true, - "name" : "version", - "staticContext" : { - "enumName" : { - "_0" : "Calculator" - } - }, - "type" : { - "string" : { - } - } - } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index d329c7a96..60d7fa83c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -44,28 +44,6 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } -@_expose(wasm, "bjs_Calculator_static_cube") -@_cdecl("bjs_Calculator_static_cube") -public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { - #if arch(wasm32) - let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Calculator_static_version_get") -@_cdecl("bjs_Calculator_static_version_get") -public func _bjs_Calculator_static_version_get() -> Void { - #if arch(wasm32) - let ret = Calculator.version - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -156,28 +134,6 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } -@_expose(wasm, "bjs_MathUtils_static_divide") -@_cdecl("bjs_MathUtils_static_divide") -public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { - #if arch(wasm32) - let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_MathUtils_static_pi_get") -@_cdecl("bjs_MathUtils_static_pi_get") -public func _bjs_MathUtils_static_pi_get() -> Float64 { - #if arch(wasm32) - let ret = MathUtils.pi - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index 041afc2f9..7c5df25b7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -152,64 +152,11 @@ } } } - }, - { - "abiName" : "bjs_MathUtils_static_divide", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "divide", - "parameters" : [ - { - "label" : "a", - "name" : "a", - "type" : { - "int" : { - - } - } - }, - { - "label" : "b", - "name" : "b", - "type" : { - "int" : { - - } - } - } - ], - "returnType" : { - "int" : { - - } - }, - "staticContext" : { - "className" : { - "_0" : "MathUtils" - } - } } ], "name" : "MathUtils", "properties" : [ - { - "isReadonly" : true, - "isStatic" : true, - "name" : "pi", - "staticContext" : { - "className" : { - "_0" : "MathUtils" - } - }, - "type" : { - "double" : { - } - } - } ], "swiftCallName" : "MathUtils" } @@ -268,54 +215,10 @@ "_0" : "Calculator" } } - }, - { - "abiName" : "bjs_Calculator_static_cube", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "cube", - "parameters" : [ - { - "label" : "value", - "name" : "value", - "type" : { - "int" : { - - } - } - } - ], - "returnType" : { - "int" : { - - } - }, - "staticContext" : { - "enumName" : { - "_0" : "Calculator" - } - } } ], "staticProperties" : [ - { - "isReadonly" : true, - "isStatic" : true, - "name" : "version", - "staticContext" : { - "enumName" : { - "_0" : "Calculator" - } - }, - "type" : { - "string" : { - } - } - } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index d329c7a96..60d7fa83c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -44,28 +44,6 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } -@_expose(wasm, "bjs_Calculator_static_cube") -@_cdecl("bjs_Calculator_static_cube") -public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { - #if arch(wasm32) - let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Calculator_static_version_get") -@_cdecl("bjs_Calculator_static_version_get") -public func _bjs_Calculator_static_version_get() -> Void { - #if arch(wasm32) - let ret = Calculator.version - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -156,28 +134,6 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } -@_expose(wasm, "bjs_MathUtils_static_divide") -@_cdecl("bjs_MathUtils_static_divide") -public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { - #if arch(wasm32) - let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_MathUtils_static_pi_get") -@_cdecl("bjs_MathUtils_static_pi_get") -public func _bjs_MathUtils_static_pi_get() -> Float64 { - #if arch(wasm32) - let ret = MathUtils.pi - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index cf5156d8d..7cebdd5e6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -63,45 +63,6 @@ } } - }, - { - "abiName" : "bjs_Greeter_greetEnthusiastically", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "greetEnthusiastically", - "parameters" : [ - - ], - "returnType" : { - "string" : { - - } - } - }, - { - "abiName" : "bjs_Greeter_static_greetAnonymously", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "greetAnonymously", - "parameters" : [ - - ], - "returnType" : { - "string" : { - - } - }, - "staticContext" : { - "className" : { - "_0" : "Greeter" - } - } } ], "name" : "Greeter", @@ -113,31 +74,6 @@ "type" : { "string" : { - } - } - }, - { - "isReadonly" : true, - "isStatic" : false, - "name" : "nameCount", - "type" : { - "int" : { - - } - } - }, - { - "isReadonly" : true, - "isStatic" : true, - "name" : "defaultGreeting", - "staticContext" : { - "className" : { - "_0" : "Greeter" - } - }, - "type" : { - "string" : { - } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index abf33ec5e..aab0eb308 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -40,28 +40,6 @@ public func _bjs_Greeter_changeName(_ _self: UnsafeMutableRawPointer, _ nameByte #endif } -@_expose(wasm, "bjs_Greeter_greetEnthusiastically") -@_cdecl("bjs_Greeter_greetEnthusiastically") -public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { - #if arch(wasm32) - let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Greeter_static_greetAnonymously") -@_cdecl("bjs_Greeter_static_greetAnonymously") -public func _bjs_Greeter_static_greetAnonymously() -> Void { - #if arch(wasm32) - let ret = Greeter.greetAnonymously() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -83,28 +61,6 @@ public func _bjs_Greeter_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes #endif } -@_expose(wasm, "bjs_Greeter_nameCount_get") -@_cdecl("bjs_Greeter_nameCount_get") -public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { - #if arch(wasm32) - let ret = Greeter.bridgeJSLiftParameter(_self).nameCount - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") -@_cdecl("bjs_Greeter_static_defaultGreeting_get") -public func _bjs_Greeter_static_defaultGreeting_get() -> Void { - #if arch(wasm32) - let ret = Greeter.defaultGreeting - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 4c36dc15c..eeb567d4a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -214,28 +214,7 @@ ] }, "methods" : [ - { - "abiName" : "bjs_DataPoint_static_origin", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "origin", - "parameters" : [ - ], - "returnType" : { - "swiftStruct" : { - "_0" : "DataPoint" - } - }, - "staticContext" : { - "structName" : { - "_0" : "DataPoint" - } - } - } ], "name" : "DataPoint", "properties" : [ @@ -301,21 +280,6 @@ "_1" : "null" } } - }, - { - "isReadonly" : true, - "isStatic" : true, - "name" : "dimensions", - "staticContext" : { - "structName" : { - "_0" : "DataPoint" - } - }, - "type" : { - "int" : { - - } - } } ], "swiftCallName" : "DataPoint" @@ -636,76 +600,6 @@ } ], "swiftCallName" : "Container" - }, - { - "methods" : [ - { - "abiName" : "bjs_Vector2D_magnitude", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "magnitude", - "parameters" : [ - - ], - "returnType" : { - "double" : { - - } - } - }, - { - "abiName" : "bjs_Vector2D_scaled", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "scaled", - "parameters" : [ - { - "label" : "by", - "name" : "factor", - "type" : { - "double" : { - - } - } - } - ], - "returnType" : { - "swiftStruct" : { - "_0" : "Vector2D" - } - } - } - ], - "name" : "Vector2D", - "properties" : [ - { - "isReadonly" : true, - "isStatic" : false, - "name" : "dx", - "type" : { - "double" : { - - } - } - }, - { - "isReadonly" : true, - "isStatic" : false, - "name" : "dy", - "type" : { - "double" : { - - } - } - } - ], - "swiftCallName" : "Vector2D" } ] }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 9f671c711..236937db9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -66,28 +66,6 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } -@_expose(wasm, "bjs_DataPoint_static_dimensions_get") -@_cdecl("bjs_DataPoint_static_dimensions_get") -public func _bjs_DataPoint_static_dimensions_get() -> Int32 { - #if arch(wasm32) - let ret = DataPoint.dimensions - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_DataPoint_static_origin") -@_cdecl("bjs_DataPoint_static_origin") -public func _bjs_DataPoint_static_origin() -> Void { - #if arch(wasm32) - let ret = DataPoint.origin() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Address { let zipCode = Optional.bridgeJSStackPop() @@ -455,76 +433,6 @@ fileprivate func _bjs_struct_lift_Container_extern() -> Int32 { return _bjs_struct_lift_Container_extern() } -extension Vector2D: _BridgedSwiftStruct { - @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Vector2D { - let dy = Double.bridgeJSStackPop() - let dx = Double.bridgeJSStackPop() - return Vector2D(dx: dx, dy: dy) - } - - @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { - self.dx.bridgeJSStackPush() - self.dy.bridgeJSStackPush() - } - - init(unsafelyCopying jsObject: JSObject) { - _bjs_struct_lower_Vector2D(jsObject.bridgeJSLowerParameter()) - self = Self.bridgeJSStackPop() - } - - func toJSObject() -> JSObject { - let __bjs_self = self - __bjs_self.bridgeJSStackPush() - return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Vector2D())) - } -} - -#if arch(wasm32) -@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Vector2D") -fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void -#else -fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void { - fatalError("Only available on WebAssembly") -} -#endif -@inline(never) fileprivate func _bjs_struct_lower_Vector2D(_ objectId: Int32) -> Void { - return _bjs_struct_lower_Vector2D_extern(objectId) -} - -#if arch(wasm32) -@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Vector2D") -fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 -#else -fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 { - fatalError("Only available on WebAssembly") -} -#endif -@inline(never) fileprivate func _bjs_struct_lift_Vector2D() -> Int32 { - return _bjs_struct_lift_Vector2D_extern() -} - -@_expose(wasm, "bjs_Vector2D_magnitude") -@_cdecl("bjs_Vector2D_magnitude") -public func _bjs_Vector2D_magnitude() -> Float64 { - #if arch(wasm32) - let ret = Vector2D.bridgeJSLiftParameter().magnitude() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Vector2D_scaled") -@_cdecl("bjs_Vector2D_scaled") -public func _bjs_Vector2D_scaled(_ factor: Float64) -> Void { - #if arch(wasm32) - let ret = Vector2D.bridgeJSLiftParameter().scaled(by: Double.bridgeJSLiftParameter(factor)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_roundtrip") @_cdecl("bjs_roundtrip") public func _bjs_roundtrip() -> Void { 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 5916e1648..a2f1c7d6d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts @@ -22,8 +22,6 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; - cube(value: number): number; - readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -55,8 +53,6 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; - divide(a: number, b: number): number; - readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 42e25545e..073784583 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -304,14 +304,6 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } - static divide(a, b) { - const ret = instance.exports.bjs_MathUtils_static_divide(a, b); - return ret; - } - static get pi() { - const ret = instance.exports.bjs_MathUtils_static_pi_get(); - return ret; - } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -329,16 +321,6 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; - }, - cube: function(value) { - const ret = instance.exports.bjs_Calculator_static_cube(value); - return ret; - }, - get version() { - instance.exports.bjs_Calculator_static_version_get(); - const ret = tmpRetString; - tmpRetString = undefined; - return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts index c9cb26910..e938ddb9a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts @@ -22,8 +22,6 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; - cube(value: number): number; - readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -45,8 +43,6 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; - divide(a: number, b: number): number; - readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 4cf9615fb..173bd6c27 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -304,14 +304,6 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } - static divide(a, b) { - const ret = instance.exports.bjs_MathUtils_static_divide(a, b); - return ret; - } - static get pi() { - const ret = instance.exports.bjs_MathUtils_static_pi_get(); - return ret; - } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -323,16 +315,6 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; - }, - cube: function(value) { - const ret = instance.exports.bjs_Calculator_static_cube(value); - return ret; - }, - get version() { - instance.exports.bjs_Calculator_static_version_get(); - const ret = tmpRetString; - tmpRetString = undefined; - return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 6d590950c..05fc97fee 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -14,9 +14,7 @@ export interface SwiftHeapObject { export interface Greeter extends SwiftHeapObject { greet(): string; changeName(name: string): void; - greetEnthusiastically(): string; name: string; - readonly nameCount: number; } export interface PublicGreeter extends SwiftHeapObject { } @@ -25,8 +23,6 @@ export interface PackageGreeter extends SwiftHeapObject { export type Exports = { Greeter: { new(name: string): Greeter; - greetAnonymously(): string; - readonly defaultGreeting: string; } PublicGreeter: { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index cf9faa707..4dd231e0e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -289,18 +289,6 @@ export async function createInstantiator(options, swift) { const nameId = swift.memory.retain(nameBytes); instance.exports.bjs_Greeter_changeName(this.pointer, nameId, nameBytes.length); } - greetEnthusiastically() { - instance.exports.bjs_Greeter_greetEnthusiastically(this.pointer); - const ret = tmpRetString; - tmpRetString = undefined; - return ret; - } - static greetAnonymously() { - instance.exports.bjs_Greeter_static_greetAnonymously(); - const ret = tmpRetString; - tmpRetString = undefined; - return ret; - } get name() { instance.exports.bjs_Greeter_name_get(this.pointer); const ret = tmpRetString; @@ -312,16 +300,6 @@ export async function createInstantiator(options, swift) { const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } - get nameCount() { - const ret = instance.exports.bjs_Greeter_nameCount_get(this.pointer); - return ret; - } - static get defaultGreeting() { - instance.exports.bjs_Greeter_static_defaultGreeting_get(); - const ret = tmpRetString; - tmpRetString = undefined; - return ret; - } } class PublicGreeter extends SwiftHeapObject { static __construct(ptr) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts index bf4ebc71f..4a61a26e3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -43,12 +43,6 @@ export interface Container { object: any; optionalObject: any | null; } -export interface Vector2D { - dx: number; - dy: number; - magnitude(): number; - scaled(factor: number): Vector2D; -} export type PrecisionObject = typeof PrecisionValues; /// Represents a Swift heap object like a class instance or an actor instance. @@ -71,8 +65,6 @@ export type Exports = { Precision: PrecisionObject DataPoint: { init(x: number, y: number, label: string, optCount: number | null, optFlag: boolean | null): DataPoint; - readonly dimensions: number; - origin(): DataPoint; } ConfigStruct: { readonly maxRetries: number; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index a60615686..4334bec62 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -220,29 +220,6 @@ export async function createInstantiator(options, swift) { return { object: value, optionalObject: optValue }; } }); - const __bjs_createVector2DHelpers = () => ({ - lower: (value) => { - f64Stack.push(value.dx); - f64Stack.push(value.dy); - }, - lift: () => { - const f64 = f64Stack.pop(); - const f641 = f64Stack.pop(); - const instance1 = { dx: f641, dy: f64 }; - instance1.magnitude = function() { - structHelpers.Vector2D.lower(this); - const ret = instance.exports.bjs_Vector2D_magnitude(); - return ret; - }.bind(instance1); - instance1.scaled = function(factor) { - structHelpers.Vector2D.lower(this); - const ret = instance.exports.bjs_Vector2D_scaled(factor); - const structValue = structHelpers.Vector2D.lift(); - return structValue; - }.bind(instance1); - return instance1; - } - }); return { /** @@ -360,13 +337,6 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Container.lift(); return swift.memory.retain(value); } - bjs["swift_js_struct_lower_Vector2D"] = function(objectId) { - structHelpers.Vector2D.lower(swift.memory.getObject(objectId)); - } - bjs["swift_js_struct_lift_Vector2D"] = function() { - const value = structHelpers.Vector2D.lift(); - return swift.memory.retain(value); - } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -558,9 +528,6 @@ export async function createInstantiator(options, swift) { const ContainerHelpers = __bjs_createContainerHelpers(); structHelpers.Container = ContainerHelpers; - const Vector2DHelpers = __bjs_createVector2DHelpers(); - structHelpers.Vector2D = Vector2DHelpers; - const exports = { Greeter, roundtrip: function bjs_roundtrip(session) { @@ -586,15 +553,6 @@ export async function createInstantiator(options, swift) { const structValue = structHelpers.DataPoint.lift(); return structValue; }, - get dimensions() { - const ret = instance.exports.bjs_DataPoint_static_dimensions_get(); - return ret; - }, - origin: function() { - instance.exports.bjs_DataPoint_static_origin(); - const structValue = structHelpers.DataPoint.lift(); - return structValue; - }, }, ConfigStruct: { get maxRetries() { diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md index a16c81286..9cd4a2224 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md @@ -77,53 +77,6 @@ export type Exports = { } ``` -## Adding Members via Extensions - -You can add exported methods, computed properties, and static members to a `@JS` class using extensions. The extension block itself does not need `@JS` - only the individual members do: - -```swift -@JS class Greeter { - @JS var name: String - - @JS init(name: String) { - self.name = name - } - - @JS func greet() -> String { - return "Hello, " + self.name + "!" - } -} - -extension Greeter { - @JS func greetEnthusiastically() -> String { - return "Hey, " + self.name + "!!!" - } - - @JS var nameCount: Int { name.count } - - @JS static func greetAnonymously() -> String { - return "Hello." - } - - @JS static var defaultGreeting: String { "Hello, world!" } -} -``` - -This also works across files within the same module: - -```swift -// GreeterExtension.swift -extension Greeter { - @JS func greetFormally() -> String { - return "Good day, " + self.name + "." - } -} -``` - -All `@JS`-annotated members in extensions are merged into the same generated TypeScript interface as the original class declaration. - -> Note: Extensions must target `@JS`-annotated types from the same module. - ## How It Works Classes use **reference semantics** when crossing the Swift/JavaScript boundary: @@ -150,6 +103,5 @@ This differs from structs, which use copy semantics and transfer data by value. | Static / class properties: `static var`, `class let` | ✅ (See )| | Methods: `func` | ✅ (See ) | | Static/class methods: `static func`, `class func` | ✅ (See ) | -| Extension methods/properties | ✅ | | Subscripts: `subscript()` | ❌ | | Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md index 68996b27b..2220d457c 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md @@ -514,5 +514,4 @@ This differs from classes, which use reference semantics and share state across | Associated values: `JSObject` | ✅ | | Associated values: Arrays | ✅ | | Associated values: Optionals of all supported types | ✅ | -| Extension static functions/properties | ✅ | | Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md index c4a9524d9..32bb79ed3 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md @@ -165,7 +165,6 @@ This differs from classes, which use reference semantics and share state across | Instance methods | ✅ | | Static methods | ✅ | | Static properties | ✅ | -| Extension methods/properties | ✅ | | Property observers (`willSet`, `didSet`) | ❌ | | Generics | ❌ | | Conformances | ❌ | diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 171d0dd3a..595f6c051 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -144,20 +144,6 @@ struct TestError: Error { } } -extension Greeter { - @JS func greetEnthusiastically() -> String { - return "Hey, \(name)!!!" - } - - @JS var nameCount: Int { name.count } - - @JS static func greetAnonymously() -> String { - return "Hello." - } - - @JS static var defaultGreeting: String { "Hello, world!" } -} - @JS func takeGreeter(g: Greeter, name: String) { g.changeName(name: name) } @@ -271,14 +257,6 @@ extension Greeter { case auto = "auto" } -extension StaticCalculator { - @JS static func doubleValue(_ value: Int) -> Int { - return value * 2 - } - - @JS static var version: String { "1.0" } -} - @JS func setDirection(_ direction: Direction) -> Direction { return direction } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index b54106be9..e01761a8e 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -3726,28 +3726,6 @@ public func _bjs_StaticCalculator_static_roundtrip(_ value: Int32) -> Int32 { #endif } -@_expose(wasm, "bjs_StaticCalculator_static_doubleValue") -@_cdecl("bjs_StaticCalculator_static_doubleValue") -public func _bjs_StaticCalculator_static_doubleValue(_ value: Int32) -> Int32 { - #if arch(wasm32) - let ret = StaticCalculator.doubleValue(_: Int.bridgeJSLiftParameter(value)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_StaticCalculator_static_version_get") -@_cdecl("bjs_StaticCalculator_static_version_get") -public func _bjs_StaticCalculator_static_version_get() -> Void { - #if arch(wasm32) - let ret = StaticCalculator.version - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_StaticUtils_Nested_static_roundtrip") @_cdecl("bjs_StaticUtils_Nested_static_roundtrip") public func _bjs_StaticUtils_Nested_static_roundtrip(_ valueBytes: Int32, _ valueLength: Int32) -> Void { @@ -4695,28 +4673,6 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } -@_expose(wasm, "bjs_DataPoint_static_dimensions_get") -@_cdecl("bjs_DataPoint_static_dimensions_get") -public func _bjs_DataPoint_static_dimensions_get() -> Int32 { - #if arch(wasm32) - let ret = DataPoint.dimensions - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_DataPoint_static_origin") -@_cdecl("bjs_DataPoint_static_origin") -public func _bjs_DataPoint_static_origin() -> Void { - #if arch(wasm32) - let ret = DataPoint.origin() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - extension PublicPoint: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PublicPoint { let y = Int.bridgeJSStackPop() @@ -5518,87 +5474,6 @@ public func _bjs_ConfigStruct_static_computedSetting_get() -> Void { #endif } -extension Vector2D: _BridgedSwiftStruct { - @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Vector2D { - let dy = Double.bridgeJSStackPop() - let dx = Double.bridgeJSStackPop() - return Vector2D(dx: dx, dy: dy) - } - - @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { - self.dx.bridgeJSStackPush() - self.dy.bridgeJSStackPush() - } - - init(unsafelyCopying jsObject: JSObject) { - _bjs_struct_lower_Vector2D(jsObject.bridgeJSLowerParameter()) - self = Self.bridgeJSStackPop() - } - - func toJSObject() -> JSObject { - let __bjs_self = self - __bjs_self.bridgeJSStackPush() - return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Vector2D())) - } -} - -#if arch(wasm32) -@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Vector2D") -fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void -#else -fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void { - fatalError("Only available on WebAssembly") -} -#endif -@inline(never) fileprivate func _bjs_struct_lower_Vector2D(_ objectId: Int32) -> Void { - return _bjs_struct_lower_Vector2D_extern(objectId) -} - -#if arch(wasm32) -@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Vector2D") -fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 -#else -fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 { - fatalError("Only available on WebAssembly") -} -#endif -@inline(never) fileprivate func _bjs_struct_lift_Vector2D() -> Int32 { - return _bjs_struct_lift_Vector2D_extern() -} - -@_expose(wasm, "bjs_Vector2D_init") -@_cdecl("bjs_Vector2D_init") -public func _bjs_Vector2D_init(_ dx: Float64, _ dy: Float64) -> Void { - #if arch(wasm32) - let ret = Vector2D(dx: Double.bridgeJSLiftParameter(dx), dy: Double.bridgeJSLiftParameter(dy)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Vector2D_magnitude") -@_cdecl("bjs_Vector2D_magnitude") -public func _bjs_Vector2D_magnitude() -> Float64 { - #if arch(wasm32) - let ret = Vector2D.bridgeJSLiftParameter().magnitude() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Vector2D_scaled") -@_cdecl("bjs_Vector2D_scaled") -public func _bjs_Vector2D_scaled(_ factor: Float64) -> Void { - #if arch(wasm32) - let ret = Vector2D.bridgeJSLiftParameter().scaled(by: Double.bridgeJSLiftParameter(factor)) - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - extension JSObjectContainer: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> JSObjectContainer { let optionalObject = Optional.bridgeJSStackPop() @@ -7527,28 +7402,6 @@ public func _bjs_Greeter_makeCustomGreeter(_ _self: UnsafeMutableRawPointer) -> #endif } -@_expose(wasm, "bjs_Greeter_greetEnthusiastically") -@_cdecl("bjs_Greeter_greetEnthusiastically") -public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { - #if arch(wasm32) - let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Greeter_static_greetAnonymously") -@_cdecl("bjs_Greeter_static_greetAnonymously") -public func _bjs_Greeter_static_greetAnonymously() -> Void { - #if arch(wasm32) - let ret = Greeter.greetAnonymously() - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -7581,28 +7434,6 @@ public func _bjs_Greeter_prefix_get(_ _self: UnsafeMutableRawPointer) -> Void { #endif } -@_expose(wasm, "bjs_Greeter_nameCount_get") -@_cdecl("bjs_Greeter_nameCount_get") -public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { - #if arch(wasm32) - let ret = Greeter.bridgeJSLiftParameter(_self).nameCount - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - -@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") -@_cdecl("bjs_Greeter_static_defaultGreeting_get") -public func _bjs_Greeter_static_defaultGreeting_get() -> Void { - #if arch(wasm32) - let ret = Greeter.defaultGreeting - return ret.bridgeJSLowerReturn() - #else - fatalError("Only available on WebAssembly") - #endif -} - @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 484620191..cd8111566 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -729,45 +729,6 @@ "useJSTypedClosure" : false } } - }, - { - "abiName" : "bjs_Greeter_greetEnthusiastically", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "greetEnthusiastically", - "parameters" : [ - - ], - "returnType" : { - "string" : { - - } - } - }, - { - "abiName" : "bjs_Greeter_static_greetAnonymously", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "greetAnonymously", - "parameters" : [ - - ], - "returnType" : { - "string" : { - - } - }, - "staticContext" : { - "className" : { - "_0" : "Greeter" - } - } } ], "name" : "Greeter", @@ -789,31 +750,6 @@ "type" : { "string" : { - } - } - }, - { - "isReadonly" : true, - "isStatic" : false, - "name" : "nameCount", - "type" : { - "int" : { - - } - } - }, - { - "isReadonly" : true, - "isStatic" : true, - "name" : "defaultGreeting", - "staticContext" : { - "className" : { - "_0" : "Greeter" - } - }, - "type" : { - "string" : { - } } } @@ -8509,54 +8445,10 @@ "_0" : "StaticCalculator" } } - }, - { - "abiName" : "bjs_StaticCalculator_static_doubleValue", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "doubleValue", - "parameters" : [ - { - "label" : "_", - "name" : "value", - "type" : { - "int" : { - - } - } - } - ], - "returnType" : { - "int" : { - - } - }, - "staticContext" : { - "enumName" : { - "_0" : "StaticCalculator" - } - } } ], "staticProperties" : [ - { - "isReadonly" : true, - "isStatic" : true, - "name" : "version", - "staticContext" : { - "enumName" : { - "_0" : "StaticCalculator" - } - }, - "type" : { - "string" : { - } - } - } ], "swiftCallName" : "StaticCalculator", "tsFullPath" : "StaticCalculator" @@ -14947,28 +14839,7 @@ ] }, "methods" : [ - { - "abiName" : "bjs_DataPoint_static_origin", - "effects" : { - "isAsync" : false, - "isStatic" : true, - "isThrows" : false - }, - "name" : "origin", - "parameters" : [ - ], - "returnType" : { - "swiftStruct" : { - "_0" : "DataPoint" - } - }, - "staticContext" : { - "structName" : { - "_0" : "DataPoint" - } - } - } ], "name" : "DataPoint", "properties" : [ @@ -15034,21 +14905,6 @@ "_1" : "null" } } - }, - { - "isReadonly" : true, - "isStatic" : true, - "name" : "dimensions", - "staticContext" : { - "structName" : { - "_0" : "DataPoint" - } - }, - "type" : { - "int" : { - - } - } } ], "swiftCallName" : "DataPoint" @@ -16025,104 +15881,6 @@ ], "swiftCallName" : "ConfigStruct" }, - { - "constructor" : { - "abiName" : "bjs_Vector2D_init", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "parameters" : [ - { - "label" : "dx", - "name" : "dx", - "type" : { - "double" : { - - } - } - }, - { - "label" : "dy", - "name" : "dy", - "type" : { - "double" : { - - } - } - } - ] - }, - "methods" : [ - { - "abiName" : "bjs_Vector2D_magnitude", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "magnitude", - "parameters" : [ - - ], - "returnType" : { - "double" : { - - } - } - }, - { - "abiName" : "bjs_Vector2D_scaled", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "scaled", - "parameters" : [ - { - "label" : "by", - "name" : "factor", - "type" : { - "double" : { - - } - } - } - ], - "returnType" : { - "swiftStruct" : { - "_0" : "Vector2D" - } - } - } - ], - "name" : "Vector2D", - "properties" : [ - { - "isReadonly" : true, - "isStatic" : false, - "name" : "dx", - "type" : { - "double" : { - - } - } - }, - { - "isReadonly" : true, - "isStatic" : false, - "name" : "dy", - "type" : { - "double" : { - - } - } - } - ], - "swiftCallName" : "Vector2D" - }, { "methods" : [ diff --git a/Tests/BridgeJSRuntimeTests/StructAPIs.swift b/Tests/BridgeJSRuntimeTests/StructAPIs.swift index daa7ad1e2..0a05a517d 100644 --- a/Tests/BridgeJSRuntimeTests/StructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/StructAPIs.swift @@ -174,34 +174,6 @@ import JavaScriptKit } } -extension DataPoint { - @JS static func origin() -> DataPoint { - return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) - } - - @JS static var dimensions: Int { 2 } -} - -@JS struct Vector2D { - var dx: Double - var dy: Double - - @JS init(dx: Double, dy: Double) { - self.dx = dx - self.dy = dy - } -} - -extension Vector2D { - @JS func magnitude() -> Double { - return (dx * dx + dy * dy).squareRoot() - } - - @JS func scaled(by factor: Double) -> Vector2D { - return Vector2D(dx: dx * factor, dy: dy * factor) - } -} - @JS func roundTripDataPoint(_ data: DataPoint) -> DataPoint { return data } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 8eb9a0270..265781bff 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -265,12 +265,6 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(g.name, "Bob"); assert.equal(g.greet(), "Hello, Bob!"); - // Test class extension members - assert.equal(g.greetEnthusiastically(), "Hey, Bob!!!"); - assert.equal(g.nameCount, 3); - assert.equal(exports.Greeter.greetAnonymously(), "Hello."); - assert.equal(exports.Greeter.defaultGreeting, "Hello, world!"); - const g2 = exports.roundTripSwiftHeapObject(g) assert.equal(g2.greet(), "Hello, Bob!"); assert.equal(g2.name, "Bob"); @@ -771,10 +765,6 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(StaticCalculatorValues.Basic, 1); assert.equal(StaticCalculatorValues.Scientific, exports.StaticCalculator.Scientific); assert.equal(StaticCalculatorValues.Basic, exports.StaticCalculator.Basic); - - // Test enum extension static members - assert.equal(exports.StaticCalculator.doubleValue(21), 42); - assert.equal(exports.StaticCalculator.version, "1.0"); assert.equal(exports.StaticUtils.Nested.roundtrip("hello world"), "hello world"); assert.equal(exports.StaticUtils.Nested.roundtrip("test"), "test"); @@ -793,20 +783,6 @@ function testStructSupport(exports) { const data2 = { x: 0.0, y: 0.0, label: "", optCount: null, optFlag: null }; assert.deepEqual(exports.roundTripDataPoint(data2), data2); - // Test struct extension static members - const origin = exports.DataPoint.origin(); - assert.equal(origin.x, 0.0); - assert.equal(origin.y, 0.0); - assert.equal(origin.label, "origin"); - assert.equal(exports.DataPoint.dimensions, 2); - - // Test struct extension instance methods - const vec = exports.Vector2D.init(3.0, 4.0); - assert.equal(vec.magnitude(), 5.0); - const scaled = vec.scaled(2.0); - assert.equal(scaled.dx, 6.0); - assert.equal(scaled.dy, 8.0); - const publicPoint = { x: 9, y: -3 }; assert.deepEqual(exports.roundTripPublicPoint(publicPoint), publicPoint); From d6630c81cece8a263b1666f85c14ab5a8dd2ef99 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 23 Mar 2026 19:05:48 +0000 Subject: [PATCH 17/68] Fix Embedded, bump 6.3 Swift toolchain in `test.yml` (#702) * Bump Swift toolchain snapshots in `test.yml` Bumping to `2026-03-05` for 6.3 and `2026-03-09` for `main`. * Fix concurrency `@_spi` * Downgrade `main` snapshot to old version * Fix 6.3 build error * EmbeddedApp/main.swift: Fix capitalization in print statement * Add `Examples/EmbeddedConcurrency` * EmbeddedConcurrency: don't use `-c release` for SwiftSyntax Remove the '-c release' option from the build command. * Fix warnings with untyped throws, fix npm install error # Conflicts: # Examples/EmbeddedConcurrency/build.sh * Fix formatting * Bump `build-examples` snapshots to 2026-03-14 * Use 2026-03-09 for `main` development snapshots * Add Swift version check before building examples * Exercise `await` on `JSPromise/value` * Address PR feedback * Move `EmbeddedConcurrencyApp` to fixtures * Temporarily disable `main` snapshots * Removing crashing test from the PR --- .github/workflows/test.yml | 8 +++-- .../Embedded/Sources/EmbeddedApp/main.swift | 2 +- Sources/JavaScriptEventLoop/JSSending.swift | 35 +++++++++++++++++++ .../JavaScriptEventLoop+ExecutorFactory.swift | 30 +++++++++++++--- .../JavaScriptEventLoop.swift | 7 ++-- .../BasicObjects/JSTypedArray.swift | 6 ++-- 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69f63a27c..419c772a0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: target: "wasm32-unknown-wasip1" - os: ubuntu-24.04 toolchain: - download-url: https://download.swift.org/swift-6.3-branch/ubuntu2404/swift-6.3-DEVELOPMENT-SNAPSHOT-2025-12-05-a/swift-6.3-DEVELOPMENT-SNAPSHOT-2025-12-05-a-ubuntu24.04.tar.gz + download-url: https://download.swift.org/swift-6.3-branch/ubuntu2404/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-03-05-a/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-03-05-a-ubuntu24.04.tar.gz wasi-backend: Node target: "wasm32-unknown-wasip1" - os: ubuntu-22.04 @@ -167,14 +167,16 @@ jobs: - uses: actions/checkout@v6 - uses: ./.github/actions/install-swift with: - download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-02-02-a/swift-DEVELOPMENT-SNAPSHOT-2026-02-02-a-ubuntu22.04.tar.gz + download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-03-09-a/swift-DEVELOPMENT-SNAPSHOT-2026-03-09-a-ubuntu22.04.tar.gz - uses: swiftwasm/setup-swiftwasm@v2 id: setup-wasm32-unknown-wasip1 with: { target: wasm32-unknown-wasip1 } - uses: swiftwasm/setup-swiftwasm@v2 id: setup-wasm32-unknown-wasip1-threads with: { target: wasm32-unknown-wasip1-threads } - - run: ./Utilities/build-examples.sh + - run: | + swift --version + ./Utilities/build-examples.sh env: SWIFT_SDK_ID_wasm32_unknown_wasip1_threads: ${{ steps.setup-wasm32-unknown-wasip1-threads.outputs.swift-sdk-id }} SWIFT_SDK_ID_wasm32_unknown_wasip1: ${{ steps.setup-wasm32-unknown-wasip1.outputs.swift-sdk-id }} diff --git a/Examples/Embedded/Sources/EmbeddedApp/main.swift b/Examples/Embedded/Sources/EmbeddedApp/main.swift index f6bf5b6ac..5e7f01a3c 100644 --- a/Examples/Embedded/Sources/EmbeddedApp/main.swift +++ b/Examples/Embedded/Sources/EmbeddedApp/main.swift @@ -3,7 +3,7 @@ import JavaScriptKit let alert = JSObject.global.alert.object! let document = JSObject.global.document -print("Hello from WASM, document title: \(document.title.string ?? "")") +print("Hello from Wasm, document title: \(document.title.string ?? "")") var count = 0 diff --git a/Sources/JavaScriptEventLoop/JSSending.swift b/Sources/JavaScriptEventLoop/JSSending.swift index 7a3750c15..fb2fb1ddf 100644 --- a/Sources/JavaScriptEventLoop/JSSending.swift +++ b/Sources/JavaScriptEventLoop/JSSending.swift @@ -226,6 +226,32 @@ extension JSSending { /// - Parameter isolation: The actor isolation context for this call, used in Swift concurrency. /// - Returns: The received object of type `T`. /// - Throws: `JSSendingError` if the sending operation fails, or `JSException` if a JavaScript error occurs. + #if compiler(>=6.4) + @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) + public func receive( + isolation: isolated (any Actor)? = #isolation, + file: StaticString = #file, + line: UInt = #line + ) async throws(JSException) -> T { + #if _runtime(_multithreaded) + let idInDestination = try await withCheckedThrowingContinuation { continuation in + let context = _JSSendingContext(continuation: continuation) + let idInSource = self.storage.idInSource + let transferring = self.storage.transferring ? [idInSource] : [] + swjs_request_sending_object( + idInSource, + transferring, + Int32(transferring.count), + self.storage.sourceTid, + Unmanaged.passRetained(context).toOpaque() + ) + } + return storage.construct(JSObject(id: idInDestination)) + #else + return storage.construct(storage.sourceObject) + #endif + } + #else @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) public func receive( isolation: isolated (any Actor)? = #isolation, @@ -250,6 +276,7 @@ extension JSSending { return storage.construct(storage.sourceObject) #endif } + #endif // 6.0 and below can't compile the following without a compiler crash. #if compiler(>=6.1) @@ -341,11 +368,19 @@ extension JSSending { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) private final class _JSSendingContext: Sendable { + #if compiler(>=6.4) + let continuation: CheckedContinuation + + init(continuation: CheckedContinuation) { + self.continuation = continuation + } + #else let continuation: CheckedContinuation init(continuation: CheckedContinuation) { self.continuation = continuation } + #endif } /// Error type representing failures during JavaScript object sending operations. diff --git a/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift b/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift index 7de4cb74a..a9b6091e8 100644 --- a/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift +++ b/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift @@ -5,10 +5,10 @@ // See: https://forums.swift.org/t/pitch-2-custom-main-and-global-executors/78437 #if compiler(>=6.3) -@_spi(ExperimentalCustomExecutors) import _Concurrency +@_spi(ExperimentalCustomExecutors) @_spi(ExperimentalScheduling) import _Concurrency #else import _Concurrency -#endif +#endif // #if compiler(>=6.3) import _CJavaScriptKit #if compiler(>=6.3) @@ -40,6 +40,22 @@ extension JavaScriptEventLoop: SchedulingExecutor { tolerance: C.Duration?, clock: C ) { + #if hasFeature(Embedded) + #if compiler(>=6.4) + // In Embedded Swift, ContinuousClock and SuspendingClock are unavailable. + // Hand-off the scheduling work to the Clock implementation for custom clocks. + clock.enqueue( + job, + on: self, + at: clock.now.advanced(by: delay), + tolerance: tolerance + ) + #else + fatalError( + "Delayed enqueue requires Swift 6.4+ in Embedded mode" + ) + #endif // #if compiler(>=6.4) (Embedded) + #else // #if hasFeature(Embedded) let duration: Duration // Handle clocks we know if let _ = clock as? ContinuousClock { @@ -47,7 +63,9 @@ extension JavaScriptEventLoop: SchedulingExecutor { } else if let _ = clock as? SuspendingClock { duration = delay as! SuspendingClock.Duration } else { - // Hand-off the scheduling work to Clock implementation for unknown clocks + #if compiler(>=6.4) + // Hand-off the scheduling work to Clock implementation for unknown clocks. + // Clock.enqueue is only available in the development branch (6.4+). clock.enqueue( job, on: self, @@ -55,12 +73,16 @@ extension JavaScriptEventLoop: SchedulingExecutor { tolerance: tolerance ) return + #else + fatalError("Unsupported clock type; only ContinuousClock and SuspendingClock are supported") + #endif // #if compiler(>=6.4) (non-Embedded) } let milliseconds = Self.delayInMilliseconds(from: duration) self.enqueue( UnownedJob(job), withDelay: milliseconds ) + #endif // #if hasFeature(Embedded) } private static func delayInMilliseconds(from swiftDuration: Duration) -> Double { @@ -111,4 +133,4 @@ extension JavaScriptEventLoop: ExecutorFactory { } } -#endif // compiler(>=6.3) +#endif // #if compiler(>=6.3) diff --git a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift index aebc90d65..aec1441a5 100644 --- a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift +++ b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift @@ -123,13 +123,16 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { private static func installGlobalExecutorIsolated() { guard !didInstallGlobalExecutor else { return } didInstallGlobalExecutor = true - #if compiler(>=6.3) + #if compiler(>=6.3) && !hasFeature(Embedded) if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999, *) { // For Swift 6.3 and above, we can use the new `ExecutorFactory` API _Concurrency._createExecutors(factory: JavaScriptEventLoop.self) } #else - // For Swift 6.1 and below, we need to install the global executor by hook API + // For Swift 6.1 and below, or Embedded Swift, we need to install + // the global executor by hook API. The ExecutorFactory mechanism + // does not work in Embedded Swift because ExecutorImpl.swift is + // excluded from the embedded Concurrency library. installByLegacyHook() #endif } diff --git a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift index dceecf5bf..0ad7b235a 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift @@ -98,7 +98,7 @@ public final class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiter /// used as the return value for the `withUnsafeBytes(_:)` method. The /// argument is valid only for the duration of the closure's execution. /// - Returns: The return value, if any, of the `body` closure parameter. - public func withUnsafeBytes(_ body: (UnsafeBufferPointer) throws -> R) rethrows -> R { + public func withUnsafeBytes(_ body: (UnsafeBufferPointer) throws(E) -> R) throws(E) -> R { let buffer = UnsafeMutableBufferPointer.allocate(capacity: length) defer { buffer.deallocate() } copyMemory(to: buffer) @@ -121,7 +121,9 @@ public final class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiter /// argument is valid only for the duration of the closure's execution. /// - Returns: The return value, if any, of the `body`async closure parameter. @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) - public func withUnsafeBytesAsync(_ body: (UnsafeBufferPointer) async throws -> R) async rethrows -> R { + public func withUnsafeBytesAsync( + _ body: (UnsafeBufferPointer) async throws(E) -> R + ) async throws(E) -> R { let buffer = UnsafeMutableBufferPointer.allocate(capacity: length) defer { buffer.deallocate() } copyMemory(to: buffer) From c36a7422659cfcf017d6f673b03cf70e134c9d59 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Mon, 23 Mar 2026 20:32:53 +0000 Subject: [PATCH 18/68] Gate `ExperimentalCustomExecutors` usage behind Swift 6.4 compiler check (#705) Gate `ExperimentalCustomExecutors` usage behind Swift 6.4 for non-Wasm targets Seems like it's dropped in Swift 6.3 rc shipped along with Xcode 26.4 RC in the last minute --- .../JavaScriptEventLoop+ExecutorFactory.swift | 8 ++++---- Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift b/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift index a9b6091e8..0d2010016 100644 --- a/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift +++ b/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift @@ -4,14 +4,14 @@ // See: https://github.com/swiftlang/swift/pull/80266 // See: https://forums.swift.org/t/pitch-2-custom-main-and-global-executors/78437 -#if compiler(>=6.3) +#if compiler(>=6.4) || (swift(>=6.3) && arch(wasm32)) @_spi(ExperimentalCustomExecutors) @_spi(ExperimentalScheduling) import _Concurrency #else import _Concurrency -#endif // #if compiler(>=6.3) +#endif // #if compiler(>=6.4) || (swift(>=6.3) && arch(wasm32)) import _CJavaScriptKit -#if compiler(>=6.3) +#if compiler(>=6.4) || (swift(>=6.3) && arch(wasm32)) // MARK: - MainExecutor Implementation // MainExecutor is used by the main actor to execute tasks on the main thread @@ -133,4 +133,4 @@ extension JavaScriptEventLoop: ExecutorFactory { } } -#endif // #if compiler(>=6.3) +#endif // #if compiler(>=6.4) || (swift(>=6.3) && arch(wasm32)) diff --git a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift index aec1441a5..5fc267ddc 100644 --- a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift +++ b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift @@ -1,5 +1,5 @@ import JavaScriptKit -#if compiler(>=6.3) +#if compiler(>=6.4) || (swift(>=6.3) && arch(wasm32)) @_spi(ExperimentalCustomExecutors) import _Concurrency #else import _Concurrency @@ -123,9 +123,9 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { private static func installGlobalExecutorIsolated() { guard !didInstallGlobalExecutor else { return } didInstallGlobalExecutor = true - #if compiler(>=6.3) && !hasFeature(Embedded) + #if (compiler(>=6.4) || (swift(>=6.3) && arch(wasm32))) && !hasFeature(Embedded) if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999, *) { - // For Swift 6.3 and above, we can use the new `ExecutorFactory` API + // For Swift 6.4 and above, we can use the new `ExecutorFactory` API _Concurrency._createExecutors(factory: JavaScriptEventLoop.self) } #else From 7be7d4e9d821e7d7147a85bd89755cbc3aea7970 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 24 Mar 2026 08:44:14 +0100 Subject: [PATCH 19/68] BridgeJS: Re-land extension method support (reverted in #703) (#706) * BridgeJS: Correctly emit @JS methods in extensions * BridgeJS: Improve test coverage for @JS methods and properties in extensions * Fix formatting * Update test code to avoid accidentally introduced failure * Fix CI: update snapshots, formatting, runtime test, add docs and review feedback * BridgeJS: Regenerate snapshots and runtime bindings against current main --------- Co-authored-by: William Taylor Co-authored-by: Max Desiatov --- .../BridgeJSCore/SwiftToSkeleton.swift | 72 ++++- .../BridgeJSCodegenTests.swift | 17 ++ .../Multifile/CrossFileExtension.swift | 5 + .../Multifile/CrossFileExtensionClass.swift | 4 + .../Inputs/MacroSwift/StaticFunctions.swift | 16 ++ .../Inputs/MacroSwift/SwiftClass.swift | 14 + .../Inputs/MacroSwift/SwiftStruct.swift | 23 ++ .../CrossFileExtension.json | 82 ++++++ .../CrossFileExtension.swift | 63 +++++ .../StaticFunctions.Global.json | 112 ++++++++ .../StaticFunctions.Global.swift | 44 +++ .../BridgeJSCodegenTests/StaticFunctions.json | 112 ++++++++ .../StaticFunctions.swift | 44 +++ .../BridgeJSCodegenTests/SwiftClass.json | 67 +++++ .../BridgeJSCodegenTests/SwiftClass.swift | 44 +++ .../BridgeJSCodegenTests/SwiftStruct.json | 109 ++++++++ .../BridgeJSCodegenTests/SwiftStruct.swift | 92 +++++++ .../StaticFunctions.Global.d.ts | 4 + .../StaticFunctions.Global.js | 18 ++ .../BridgeJSLinkTests/StaticFunctions.d.ts | 4 + .../BridgeJSLinkTests/StaticFunctions.js | 18 ++ .../BridgeJSLinkTests/SwiftClass.d.ts | 4 + .../BridgeJSLinkTests/SwiftClass.js | 22 ++ .../BridgeJSLinkTests/SwiftStruct.d.ts | 8 + .../BridgeJSLinkTests/SwiftStruct.js | 42 +++ .../Exporting-Swift/Exporting-Swift-Class.md | 48 ++++ .../Exporting-Swift/Exporting-Swift-Enum.md | 1 + .../Exporting-Swift/Exporting-Swift-Struct.md | 1 + .../BridgeJSRuntimeTests/ExportAPITests.swift | 22 ++ .../Generated/BridgeJS.swift | 169 ++++++++++++ .../Generated/JavaScript/BridgeJS.json | 254 ++++++++++++++++++ Tests/BridgeJSRuntimeTests/StructAPIs.swift | 28 ++ Tests/prelude.mjs | 24 ++ 33 files changed, 1586 insertions(+), 1 deletion(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 81ad32813..482b1fff5 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -43,12 +43,14 @@ public final class SwiftToSkeleton { var perSourceErrors: [(inputFilePath: String, errors: [DiagnosticError])] = [] var importedFiles: [ImportedFileSkeleton] = [] var exported = ExportedSkeleton(functions: [], classes: [], enums: [], exposeToGlobal: exposeToGlobal) + var exportCollectors: [ExportSwiftAPICollector] = [] for (sourceFile, inputFilePath) in sourceFiles { progress.print("Processing \(inputFilePath)") let exportCollector = ExportSwiftAPICollector(parent: self) exportCollector.walk(sourceFile) + exportCollectors.append(exportCollector) let typeNameCollector = ImportSwiftMacrosJSImportTypeNameCollector(viewMode: .sourceAccurate) typeNameCollector.walk(sourceFile) @@ -74,7 +76,15 @@ public final class SwiftToSkeleton { if !importedFile.isEmpty { importedFiles.append(importedFile) } - exportCollector.finalize(&exported) + } + + // Resolve extensions against all collectors. This needs to happen at this point so we can resolve both same file and cross file extensions. + for source in exportCollectors { + source.resolveDeferredExtensions(against: exportCollectors) + } + + for collector in exportCollectors { + collector.finalize(&exported) } if !perSourceErrors.isEmpty { @@ -486,6 +496,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { var exportedStructNames: [String] = [] var exportedStructByName: [String: ExportedStruct] = [:] var errors: [DiagnosticError] = [] + /// Extensions collected during the walk, to be resolved after all files have been walked + var deferredExtensions: [ExtensionDeclSyntax] = [] func finalize(_ result: inout ExportedSkeleton) { result.functions.append(contentsOf: exportedFunctions) @@ -1388,6 +1400,64 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } + override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + // Defer until all type declarations in the module have been collected. + deferredExtensions.append(node) + return .skipChildren + } + + func resolveDeferredExtensions(against collectors: [ExportSwiftAPICollector]) { + for ext in deferredExtensions { + var resolved = false + for collector in collectors { + if collector.resolveExtension(ext) { + resolved = true + break + } + } + if !resolved { + diagnose( + node: ext.extendedType, + message: "Unsupported type '\(ext.extendedType.trimmedDescription)'.", + hint: "You can only extend `@JS` annotated types defined in the same module" + ) + } + } + } + + /// Walks extension members under the matching type’s state, returning whether the type was found. + /// + /// Note: The lookup scans dictionaries keyed by `makeKey(name:namespace:)`, matching only by + /// plain name. If two types share a name but differ by namespace, `.first(where:)` picks + /// whichever comes first. This is acceptable today since namespace collisions are unlikely, + /// but may need refinement if namespace-qualified extension resolution is added. + func resolveExtension(_ ext: ExtensionDeclSyntax) -> Bool { + let name = ext.extendedType.trimmedDescription + let state: State + if let entry = exportedClassByName.first(where: { $0.value.name == name }) { + state = .classBody(name: name, key: entry.key) + } else if let entry = exportedStructByName.first(where: { $0.value.name == name }) { + state = .structBody(name: name, key: entry.key) + } else if let entry = exportedEnumByName.first(where: { $0.value.name == name }) { + state = .enumBody(name: name, key: entry.key) + } else if exportedProtocolByName.values.contains(where: { $0.name == name }) { + diagnose( + node: ext.extendedType, + message: "Protocol extensions are not supported by BridgeJS.", + hint: "You cannot extend `@JS` protocol '\(name)' with additional members" + ) + return true + } else { + return false + } + stateStack.push(state: state) + for member in ext.memberBlock.members { + walk(member) + } + stateStack.pop() + return true + } + override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index 9754fbced..dd0ce5d03 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -167,6 +167,23 @@ import Testing try snapshotCodegen(skeleton: skeleton, name: "CrossFileFunctionTypes.ReverseOrder") } + @Test + func codegenCrossFileExtension() throws { + let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let classURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtensionClass.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: classURL, encoding: .utf8)), + inputFilePath: "CrossFileExtensionClass.swift" + ) + let extensionURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtension.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: extensionURL, encoding: .utf8)), + inputFilePath: "CrossFileExtension.swift" + ) + let skeleton = try swiftAPI.finalize() + try snapshotCodegen(skeleton: skeleton, name: "CrossFileExtension") + } + @Test func codegenSkipsEmptySkeletons() throws { let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift new file mode 100644 index 000000000..ce9e8e2b0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift @@ -0,0 +1,5 @@ +extension Greeter { + @JS func greetFormally() -> String { + return "Good day, " + self.name + "." + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift new file mode 100644 index 000000000..48625d42a --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift @@ -0,0 +1,4 @@ +@JS class Greeter { + @JS init(name: String) {} + @JS func greet() -> String { return "" } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift index 1d42cf415..4f6296d2e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift @@ -38,3 +38,19 @@ enum APIResult { } } } + +extension MathUtils { + @JS static func divide(a: Int, b: Int) -> Int { + return a / b + } + + @JS static var pi: Double { 3.14159 } +} + +extension Calculator { + @JS static func cube(value: Int) -> Int { + return value * value * value + } + + @JS static var version: String { "1.0" } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift index d7b5a5b8e..2fb050eeb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift @@ -12,6 +12,20 @@ } } +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, " + self.name + "!!!" + } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } +} + @JS func takeGreeter(greeter: Greeter) { print(greeter.greet()) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift index 0d84f4736..63bb0ff8d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift @@ -60,3 +60,26 @@ } @JS func roundtripContainer(_ container: Container) -> Container + +@JS struct Vector2D { + var dx: Double + var dy: Double +} + +extension Vector2D { + @JS func magnitude() -> Double { + return (dx * dx + dy * dy).squareRoot() + } + + @JS func scaled(by factor: Double) -> Vector2D { + return Vector2D(dx: dx * factor, dy: dy * factor) + } +} + +extension DataPoint { + @JS static func origin() -> DataPoint { + return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) + } + + @JS static var dimensions: Int { 2 } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json new file mode 100644 index 000000000..f77d39ad9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json @@ -0,0 +1,82 @@ +{ + "exported" : { + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Greeter_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Greeter_greet", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greet", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_greetFormally", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetFormally", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Greeter", + "properties" : [ + + ], + "swiftCallName" : "Greeter" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift new file mode 100644 index 000000000..521e8b595 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift @@ -0,0 +1,63 @@ +@_expose(wasm, "bjs_Greeter_init") +@_cdecl("bjs_Greeter_init") +public func _bjs_Greeter_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_greet") +@_cdecl("bjs_Greeter_greet") +public func _bjs_Greeter_greet(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greet() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_greetFormally") +@_cdecl("bjs_Greeter_greetFormally") +public func _bjs_Greeter_greetFormally(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetFormally() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_deinit") +@_cdecl("bjs_Greeter_deinit") +public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Greeter_wrap") +fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Greeter_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json index c241595a3..e20af8a3b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -152,11 +152,73 @@ } } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "pi", + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + }, + "type" : { + "double" : { + } + } + } ], "swiftCallName" : "MathUtils" } @@ -215,10 +277,60 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index 60d7fa83c..d329c7a96 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -44,6 +44,28 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Calculator_static_version_get") +@_cdecl("bjs_Calculator_static_version_get") +public func _bjs_Calculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = Calculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +156,28 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_MathUtils_static_pi_get") +@_cdecl("bjs_MathUtils_static_pi_get") +public func _bjs_MathUtils_static_pi_get() -> Float64 { + #if arch(wasm32) + let ret = MathUtils.pi + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index 7c5df25b7..ded6f7602 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -152,11 +152,73 @@ } } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "pi", + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + }, + "type" : { + "double" : { + } + } + } ], "swiftCallName" : "MathUtils" } @@ -215,10 +277,60 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index 60d7fa83c..d329c7a96 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -44,6 +44,28 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Calculator_static_version_get") +@_cdecl("bjs_Calculator_static_version_get") +public func _bjs_Calculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = Calculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +156,28 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_MathUtils_static_pi_get") +@_cdecl("bjs_MathUtils_static_pi_get") +public func _bjs_MathUtils_static_pi_get() -> Float64 { + #if arch(wasm32) + let ret = MathUtils.pi + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index 7cebdd5e6..6ab78c82c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -63,6 +63,45 @@ } } + }, + { + "abiName" : "bjs_Greeter_greetEnthusiastically", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetEnthusiastically", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_static_greetAnonymously", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "greetAnonymously", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + } } ], "name" : "Greeter", @@ -74,6 +113,34 @@ "type" : { "string" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "nameCount", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + }, + "type" : { + "string" : { + } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index aab0eb308..abf33ec5e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -40,6 +40,28 @@ public func _bjs_Greeter_changeName(_ _self: UnsafeMutableRawPointer, _ nameByte #endif } +@_expose(wasm, "bjs_Greeter_greetEnthusiastically") +@_cdecl("bjs_Greeter_greetEnthusiastically") +public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_greetAnonymously") +@_cdecl("bjs_Greeter_static_greetAnonymously") +public func _bjs_Greeter_static_greetAnonymously() -> Void { + #if arch(wasm32) + let ret = Greeter.greetAnonymously() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -61,6 +83,28 @@ public func _bjs_Greeter_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes #endif } +@_expose(wasm, "bjs_Greeter_nameCount_get") +@_cdecl("bjs_Greeter_nameCount_get") +public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).nameCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") +@_cdecl("bjs_Greeter_static_defaultGreeting_get") +public func _bjs_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index eeb567d4a..4c1ef582b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -214,7 +214,28 @@ ] }, "methods" : [ + { + "abiName" : "bjs_DataPoint_static_origin", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "origin", + "parameters" : [ + ], + "returnType" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + } + } ], "name" : "DataPoint", "properties" : [ @@ -280,6 +301,24 @@ "_1" : "null" } } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "dimensions", + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + }, + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } } ], "swiftCallName" : "DataPoint" @@ -600,6 +639,76 @@ } ], "swiftCallName" : "Container" + }, + { + "methods" : [ + { + "abiName" : "bjs_Vector2D_magnitude", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "magnitude", + "parameters" : [ + + ], + "returnType" : { + "double" : { + + } + } + }, + { + "abiName" : "bjs_Vector2D_scaled", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "scaled", + "parameters" : [ + { + "label" : "by", + "name" : "factor", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Vector2D" + } + } + } + ], + "name" : "Vector2D", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dx", + "type" : { + "double" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dy", + "type" : { + "double" : { + + } + } + } + ], + "swiftCallName" : "Vector2D" } ] }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 236937db9..9f671c711 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -66,6 +66,28 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_static_dimensions_get") +@_cdecl("bjs_DataPoint_static_dimensions_get") +public func _bjs_DataPoint_static_dimensions_get() -> Int32 { + #if arch(wasm32) + let ret = DataPoint.dimensions + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_static_origin") +@_cdecl("bjs_DataPoint_static_origin") +public func _bjs_DataPoint_static_origin() -> Void { + #if arch(wasm32) + let ret = DataPoint.origin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Address { let zipCode = Optional.bridgeJSStackPop() @@ -433,6 +455,76 @@ fileprivate func _bjs_struct_lift_Container_extern() -> Int32 { return _bjs_struct_lift_Container_extern() } +extension Vector2D: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Vector2D { + let dy = Double.bridgeJSStackPop() + let dx = Double.bridgeJSStackPop() + return Vector2D(dx: dx, dy: dy) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.dx.bridgeJSStackPush() + self.dy.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Vector2D(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Vector2D())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Vector2D") +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Vector2D(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Vector2D_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Vector2D") +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Vector2D() -> Int32 { + return _bjs_struct_lift_Vector2D_extern() +} + +@_expose(wasm, "bjs_Vector2D_magnitude") +@_cdecl("bjs_Vector2D_magnitude") +public func _bjs_Vector2D_magnitude() -> Float64 { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().magnitude() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Vector2D_scaled") +@_cdecl("bjs_Vector2D_scaled") +public func _bjs_Vector2D_scaled(_ factor: Float64) -> Void { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().scaled(by: Double.bridgeJSLiftParameter(factor)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundtrip") @_cdecl("bjs_roundtrip") public func _bjs_roundtrip() -> Void { 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 a2f1c7d6d..5916e1648 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts @@ -22,6 +22,8 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; + cube(value: number): number; + readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -53,6 +55,8 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; + divide(a: number, b: number): number; + readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 073784583..42e25545e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -304,6 +304,14 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } + static divide(a, b) { + const ret = instance.exports.bjs_MathUtils_static_divide(a, b); + return ret; + } + static get pi() { + const ret = instance.exports.bjs_MathUtils_static_pi_get(); + return ret; + } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -321,6 +329,16 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; + }, + cube: function(value) { + const ret = instance.exports.bjs_Calculator_static_cube(value); + return ret; + }, + get version() { + instance.exports.bjs_Calculator_static_version_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts index e938ddb9a..c9cb26910 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts @@ -22,6 +22,8 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; + cube(value: number): number; + readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -43,6 +45,8 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; + divide(a: number, b: number): number; + readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 173bd6c27..4cf9615fb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -304,6 +304,14 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } + static divide(a, b) { + const ret = instance.exports.bjs_MathUtils_static_divide(a, b); + return ret; + } + static get pi() { + const ret = instance.exports.bjs_MathUtils_static_pi_get(); + return ret; + } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -315,6 +323,16 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; + }, + cube: function(value) { + const ret = instance.exports.bjs_Calculator_static_cube(value); + return ret; + }, + get version() { + instance.exports.bjs_Calculator_static_version_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 05fc97fee..6d590950c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -14,7 +14,9 @@ export interface SwiftHeapObject { export interface Greeter extends SwiftHeapObject { greet(): string; changeName(name: string): void; + greetEnthusiastically(): string; name: string; + readonly nameCount: number; } export interface PublicGreeter extends SwiftHeapObject { } @@ -23,6 +25,8 @@ export interface PackageGreeter extends SwiftHeapObject { export type Exports = { Greeter: { new(name: string): Greeter; + greetAnonymously(): string; + readonly defaultGreeting: string; } PublicGreeter: { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 4dd231e0e..cf9faa707 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -289,6 +289,18 @@ export async function createInstantiator(options, swift) { const nameId = swift.memory.retain(nameBytes); instance.exports.bjs_Greeter_changeName(this.pointer, nameId, nameBytes.length); } + greetEnthusiastically() { + instance.exports.bjs_Greeter_greetEnthusiastically(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + static greetAnonymously() { + instance.exports.bjs_Greeter_static_greetAnonymously(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } get name() { instance.exports.bjs_Greeter_name_get(this.pointer); const ret = tmpRetString; @@ -300,6 +312,16 @@ export async function createInstantiator(options, swift) { const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } + get nameCount() { + const ret = instance.exports.bjs_Greeter_nameCount_get(this.pointer); + return ret; + } + static get defaultGreeting() { + instance.exports.bjs_Greeter_static_defaultGreeting_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } } class PublicGreeter extends SwiftHeapObject { static __construct(ptr) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts index 4a61a26e3..bf4ebc71f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -43,6 +43,12 @@ export interface Container { object: any; optionalObject: any | null; } +export interface Vector2D { + dx: number; + dy: number; + magnitude(): number; + scaled(factor: number): Vector2D; +} export type PrecisionObject = typeof PrecisionValues; /// Represents a Swift heap object like a class instance or an actor instance. @@ -65,6 +71,8 @@ export type Exports = { Precision: PrecisionObject DataPoint: { init(x: number, y: number, label: string, optCount: number | null, optFlag: boolean | null): DataPoint; + readonly dimensions: number; + origin(): DataPoint; } ConfigStruct: { readonly maxRetries: number; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index 4334bec62..a60615686 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -220,6 +220,29 @@ export async function createInstantiator(options, swift) { return { object: value, optionalObject: optValue }; } }); + const __bjs_createVector2DHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.dx); + f64Stack.push(value.dy); + }, + lift: () => { + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + const instance1 = { dx: f641, dy: f64 }; + instance1.magnitude = function() { + structHelpers.Vector2D.lower(this); + const ret = instance.exports.bjs_Vector2D_magnitude(); + return ret; + }.bind(instance1); + instance1.scaled = function(factor) { + structHelpers.Vector2D.lower(this); + const ret = instance.exports.bjs_Vector2D_scaled(factor); + const structValue = structHelpers.Vector2D.lift(); + return structValue; + }.bind(instance1); + return instance1; + } + }); return { /** @@ -337,6 +360,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Container.lift(); return swift.memory.retain(value); } + bjs["swift_js_struct_lower_Vector2D"] = function(objectId) { + structHelpers.Vector2D.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Vector2D"] = function() { + const value = structHelpers.Vector2D.lift(); + return swift.memory.retain(value); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -528,6 +558,9 @@ export async function createInstantiator(options, swift) { const ContainerHelpers = __bjs_createContainerHelpers(); structHelpers.Container = ContainerHelpers; + const Vector2DHelpers = __bjs_createVector2DHelpers(); + structHelpers.Vector2D = Vector2DHelpers; + const exports = { Greeter, roundtrip: function bjs_roundtrip(session) { @@ -553,6 +586,15 @@ export async function createInstantiator(options, swift) { const structValue = structHelpers.DataPoint.lift(); return structValue; }, + get dimensions() { + const ret = instance.exports.bjs_DataPoint_static_dimensions_get(); + return ret; + }, + origin: function() { + instance.exports.bjs_DataPoint_static_origin(); + const structValue = structHelpers.DataPoint.lift(); + return structValue; + }, }, ConfigStruct: { get maxRetries() { diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md index 9cd4a2224..a16c81286 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md @@ -77,6 +77,53 @@ export type Exports = { } ``` +## Adding Members via Extensions + +You can add exported methods, computed properties, and static members to a `@JS` class using extensions. The extension block itself does not need `@JS` - only the individual members do: + +```swift +@JS class Greeter { + @JS var name: String + + @JS init(name: String) { + self.name = name + } + + @JS func greet() -> String { + return "Hello, " + self.name + "!" + } +} + +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, " + self.name + "!!!" + } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } +} +``` + +This also works across files within the same module: + +```swift +// GreeterExtension.swift +extension Greeter { + @JS func greetFormally() -> String { + return "Good day, " + self.name + "." + } +} +``` + +All `@JS`-annotated members in extensions are merged into the same generated TypeScript interface as the original class declaration. + +> Note: Extensions must target `@JS`-annotated types from the same module. + ## How It Works Classes use **reference semantics** when crossing the Swift/JavaScript boundary: @@ -103,5 +150,6 @@ This differs from structs, which use copy semantics and transfer data by value. | Static / class properties: `static var`, `class let` | ✅ (See )| | Methods: `func` | ✅ (See ) | | Static/class methods: `static func`, `class func` | ✅ (See ) | +| Extension methods/properties | ✅ | | Subscripts: `subscript()` | ❌ | | Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md index 2220d457c..68996b27b 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Enum.md @@ -514,4 +514,5 @@ This differs from classes, which use reference semantics and share state across | Associated values: `JSObject` | ✅ | | Associated values: Arrays | ✅ | | Associated values: Optionals of all supported types | ✅ | +| Extension static functions/properties | ✅ | | Generics | ❌ | diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md index 32bb79ed3..c4a9524d9 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Struct.md @@ -165,6 +165,7 @@ This differs from classes, which use reference semantics and share state across | Instance methods | ✅ | | Static methods | ✅ | | Static properties | ✅ | +| Extension methods/properties | ✅ | | Property observers (`willSet`, `didSet`) | ❌ | | Generics | ❌ | | Conformances | ❌ | diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 595f6c051..171d0dd3a 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -144,6 +144,20 @@ struct TestError: Error { } } +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, \(name)!!!" + } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } +} + @JS func takeGreeter(g: Greeter, name: String) { g.changeName(name: name) } @@ -257,6 +271,14 @@ struct TestError: Error { case auto = "auto" } +extension StaticCalculator { + @JS static func doubleValue(_ value: Int) -> Int { + return value * 2 + } + + @JS static var version: String { "1.0" } +} + @JS func setDirection(_ direction: Direction) -> Direction { return direction } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index e01761a8e..b54106be9 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -3726,6 +3726,28 @@ public func _bjs_StaticCalculator_static_roundtrip(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_StaticCalculator_static_doubleValue") +@_cdecl("bjs_StaticCalculator_static_doubleValue") +public func _bjs_StaticCalculator_static_doubleValue(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = StaticCalculator.doubleValue(_: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_StaticCalculator_static_version_get") +@_cdecl("bjs_StaticCalculator_static_version_get") +public func _bjs_StaticCalculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = StaticCalculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_StaticUtils_Nested_static_roundtrip") @_cdecl("bjs_StaticUtils_Nested_static_roundtrip") public func _bjs_StaticUtils_Nested_static_roundtrip(_ valueBytes: Int32, _ valueLength: Int32) -> Void { @@ -4673,6 +4695,28 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_static_dimensions_get") +@_cdecl("bjs_DataPoint_static_dimensions_get") +public func _bjs_DataPoint_static_dimensions_get() -> Int32 { + #if arch(wasm32) + let ret = DataPoint.dimensions + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_static_origin") +@_cdecl("bjs_DataPoint_static_origin") +public func _bjs_DataPoint_static_origin() -> Void { + #if arch(wasm32) + let ret = DataPoint.origin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension PublicPoint: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PublicPoint { let y = Int.bridgeJSStackPop() @@ -5474,6 +5518,87 @@ public func _bjs_ConfigStruct_static_computedSetting_get() -> Void { #endif } +extension Vector2D: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Vector2D { + let dy = Double.bridgeJSStackPop() + let dx = Double.bridgeJSStackPop() + return Vector2D(dx: dx, dy: dy) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.dx.bridgeJSStackPush() + self.dy.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Vector2D(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Vector2D())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Vector2D") +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Vector2D_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Vector2D(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Vector2D_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Vector2D") +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Vector2D_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Vector2D() -> Int32 { + return _bjs_struct_lift_Vector2D_extern() +} + +@_expose(wasm, "bjs_Vector2D_init") +@_cdecl("bjs_Vector2D_init") +public func _bjs_Vector2D_init(_ dx: Float64, _ dy: Float64) -> Void { + #if arch(wasm32) + let ret = Vector2D(dx: Double.bridgeJSLiftParameter(dx), dy: Double.bridgeJSLiftParameter(dy)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Vector2D_magnitude") +@_cdecl("bjs_Vector2D_magnitude") +public func _bjs_Vector2D_magnitude() -> Float64 { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().magnitude() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Vector2D_scaled") +@_cdecl("bjs_Vector2D_scaled") +public func _bjs_Vector2D_scaled(_ factor: Float64) -> Void { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().scaled(by: Double.bridgeJSLiftParameter(factor)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension JSObjectContainer: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> JSObjectContainer { let optionalObject = Optional.bridgeJSStackPop() @@ -7402,6 +7527,28 @@ public func _bjs_Greeter_makeCustomGreeter(_ _self: UnsafeMutableRawPointer) -> #endif } +@_expose(wasm, "bjs_Greeter_greetEnthusiastically") +@_cdecl("bjs_Greeter_greetEnthusiastically") +public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_greetAnonymously") +@_cdecl("bjs_Greeter_static_greetAnonymously") +public func _bjs_Greeter_static_greetAnonymously() -> Void { + #if arch(wasm32) + let ret = Greeter.greetAnonymously() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -7434,6 +7581,28 @@ public func _bjs_Greeter_prefix_get(_ _self: UnsafeMutableRawPointer) -> Void { #endif } +@_expose(wasm, "bjs_Greeter_nameCount_get") +@_cdecl("bjs_Greeter_nameCount_get") +public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).nameCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") +@_cdecl("bjs_Greeter_static_defaultGreeting_get") +public func _bjs_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index cd8111566..842bcff24 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -729,6 +729,45 @@ "useJSTypedClosure" : false } } + }, + { + "abiName" : "bjs_Greeter_greetEnthusiastically", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetEnthusiastically", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_static_greetAnonymously", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "greetAnonymously", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + } } ], "name" : "Greeter", @@ -750,6 +789,34 @@ "type" : { "string" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "nameCount", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + }, + "type" : { + "string" : { + } } } @@ -8445,10 +8512,60 @@ "_0" : "StaticCalculator" } } + }, + { + "abiName" : "bjs_StaticCalculator_static_doubleValue", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "doubleValue", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "staticContext" : { + "enumName" : { + "_0" : "StaticCalculator" + } + } } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "StaticCalculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "StaticCalculator", "tsFullPath" : "StaticCalculator" @@ -14839,7 +14956,28 @@ ] }, "methods" : [ + { + "abiName" : "bjs_DataPoint_static_origin", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "origin", + "parameters" : [ + ], + "returnType" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + } + } ], "name" : "DataPoint", "properties" : [ @@ -14905,6 +15043,24 @@ "_1" : "null" } } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "dimensions", + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + }, + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } } ], "swiftCallName" : "DataPoint" @@ -15881,6 +16037,104 @@ ], "swiftCallName" : "ConfigStruct" }, + { + "constructor" : { + "abiName" : "bjs_Vector2D_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "dx", + "name" : "dx", + "type" : { + "double" : { + + } + } + }, + { + "label" : "dy", + "name" : "dy", + "type" : { + "double" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Vector2D_magnitude", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "magnitude", + "parameters" : [ + + ], + "returnType" : { + "double" : { + + } + } + }, + { + "abiName" : "bjs_Vector2D_scaled", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "scaled", + "parameters" : [ + { + "label" : "by", + "name" : "factor", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Vector2D" + } + } + } + ], + "name" : "Vector2D", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dx", + "type" : { + "double" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dy", + "type" : { + "double" : { + + } + } + } + ], + "swiftCallName" : "Vector2D" + }, { "methods" : [ diff --git a/Tests/BridgeJSRuntimeTests/StructAPIs.swift b/Tests/BridgeJSRuntimeTests/StructAPIs.swift index 0a05a517d..daa7ad1e2 100644 --- a/Tests/BridgeJSRuntimeTests/StructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/StructAPIs.swift @@ -174,6 +174,34 @@ import JavaScriptKit } } +extension DataPoint { + @JS static func origin() -> DataPoint { + return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) + } + + @JS static var dimensions: Int { 2 } +} + +@JS struct Vector2D { + var dx: Double + var dy: Double + + @JS init(dx: Double, dy: Double) { + self.dx = dx + self.dy = dy + } +} + +extension Vector2D { + @JS func magnitude() -> Double { + return (dx * dx + dy * dy).squareRoot() + } + + @JS func scaled(by factor: Double) -> Vector2D { + return Vector2D(dx: dx * factor, dy: dy * factor) + } +} + @JS func roundTripDataPoint(_ data: DataPoint) -> DataPoint { return data } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 265781bff..8eb9a0270 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -265,6 +265,12 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(g.name, "Bob"); assert.equal(g.greet(), "Hello, Bob!"); + // Test class extension members + assert.equal(g.greetEnthusiastically(), "Hey, Bob!!!"); + assert.equal(g.nameCount, 3); + assert.equal(exports.Greeter.greetAnonymously(), "Hello."); + assert.equal(exports.Greeter.defaultGreeting, "Hello, world!"); + const g2 = exports.roundTripSwiftHeapObject(g) assert.equal(g2.greet(), "Hello, Bob!"); assert.equal(g2.name, "Bob"); @@ -765,6 +771,10 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(StaticCalculatorValues.Basic, 1); assert.equal(StaticCalculatorValues.Scientific, exports.StaticCalculator.Scientific); assert.equal(StaticCalculatorValues.Basic, exports.StaticCalculator.Basic); + + // Test enum extension static members + assert.equal(exports.StaticCalculator.doubleValue(21), 42); + assert.equal(exports.StaticCalculator.version, "1.0"); assert.equal(exports.StaticUtils.Nested.roundtrip("hello world"), "hello world"); assert.equal(exports.StaticUtils.Nested.roundtrip("test"), "test"); @@ -783,6 +793,20 @@ function testStructSupport(exports) { const data2 = { x: 0.0, y: 0.0, label: "", optCount: null, optFlag: null }; assert.deepEqual(exports.roundTripDataPoint(data2), data2); + // Test struct extension static members + const origin = exports.DataPoint.origin(); + assert.equal(origin.x, 0.0); + assert.equal(origin.y, 0.0); + assert.equal(origin.label, "origin"); + assert.equal(exports.DataPoint.dimensions, 2); + + // Test struct extension instance methods + const vec = exports.Vector2D.init(3.0, 4.0); + assert.equal(vec.magnitude(), 5.0); + const scaled = vec.scaled(2.0); + assert.equal(scaled.dx, 6.0); + assert.equal(scaled.dy, 8.0); + const publicPoint = { x: 9, y: -3 }; assert.deepEqual(exports.roundTripPublicPoint(publicPoint), publicPoint); From 7e242b01453f23f16df2e83b48558dc088f54ec9 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 27 Mar 2026 09:09:32 +0000 Subject: [PATCH 20/68] BridgeJS: support imports of JS `Promise` as `async` Swift (#707) * BridgeJS: support imports of `Promise` JS as `async` Swift * E2e testing of bridging Promise returns * fix formatting * `JSTypedClosure`-based approach * Clean up `BridgeJSLink` * Fix missing `import _Concurrency` * Fix formatting * Use `JSTypedClosure` without wrapping the result value * Make closure parameters as `sending` * Check more stack ABI types * Add support for `async` in `@JSFunction` * Use namespaced import * Fix missing `fetchWeatherData` * Bring back `fetchWeatherData` * Regenerate `fetchWeatherData` bridging code * BridgeJS: Centralize closure sig collection in BridgeSkeletonWalker * BridgeJS: Stop spreading isAsync handling outside of CallJSEmission * BridgeJS: Remove error-prone default effects in thunk generation * BridgeJSLink: Centralize async handling in ImportedThunkBuilder * BridgeJS: Remove reundant returnType from `call` family of methods in ImportedThunkBuilder --------- Co-authored-by: Yuta Saito --- .../Generated/JavaScript/BridgeJS.json | 15 + .../Generated/JavaScript/BridgeJS.json | 10 + .../Sources/BridgeJSCore/ClosureCodegen.swift | 11 +- .../Sources/BridgeJSCore/ExportSwift.swift | 3 + .../Sources/BridgeJSCore/ImportTS.swift | 132 +- .../BridgeJSCore/SwiftToSkeleton.swift | 12 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 292 ++-- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 72 +- .../TS2Swift/JavaScript/src/processor.js | 33 +- .../test/__snapshots__/ts2swift.test.js.snap | 14 +- .../Inputs/MacroSwift/AsyncImport.swift | 6 + .../Inputs/MacroSwift/AsyncStaticImport.swift | 4 + .../BridgeJSCodegenTests/ArrayTypes.json | 35 + .../BridgeJSCodegenTests/AsyncImport.json | 151 ++ .../BridgeJSCodegenTests/AsyncImport.swift | 569 ++++++++ .../AsyncStaticImport.json | 67 + .../AsyncStaticImport.swift | 227 +++ .../CrossFileSkipsEmptySkeletons.json | 5 + .../BridgeJSCodegenTests/DictionaryTypes.json | 5 + .../BridgeJSCodegenTests/EnumRawType.json | 10 + .../FixedWidthIntegers.json | 40 + .../BridgeJSCodegenTests/GlobalGetter.json | 5 + .../GlobalThisImports.json | 15 + .../BridgeJSCodegenTests/ImportArray.json | 10 + .../InvalidPropertyNames.json | 25 + .../BridgeJSCodegenTests/JSClass.json | 25 + .../JSClassStaticFunctions.json | 30 + .../BridgeJSCodegenTests/JSValue.json | 10 + .../BridgeJSCodegenTests/Optionals.json | 40 + .../PrimitiveParameters.json | 5 + .../BridgeJSCodegenTests/PrimitiveReturn.json | 10 + .../ProtocolInClosure.json | 15 +- .../BridgeJSCodegenTests/StringParameter.json | 10 + .../BridgeJSCodegenTests/StringReturn.json | 5 + .../BridgeJSCodegenTests/SwiftClass.json | 10 + .../BridgeJSCodegenTests/SwiftClosure.json | 129 +- .../SwiftClosureImports.json | 16 +- .../SwiftStructImports.json | 5 + .../VoidParameterVoidReturn.json | 5 + .../BridgeJSLinkTests/AsyncImport.d.ts | 23 + .../BridgeJSLinkTests/AsyncImport.js | 507 +++++++ .../BridgeJSLinkTests/AsyncStaticImport.d.ts | 23 + .../BridgeJSLinkTests/AsyncStaticImport.js | 402 ++++++ .../JavaScriptKit/BridgeJSIntrinsics.swift | 89 ++ .../AsyncImportTests.swift | 85 ++ .../BridgeJSRuntimeTests/ExportAPITests.swift | 2 +- .../Generated/BridgeJS.Macros.swift | 13 +- .../Generated/BridgeJS.swift | 1087 +++++++++++++- .../Generated/JavaScript/BridgeJS.json | 1254 ++++++++++++++--- .../JavaScript/AsyncImportTests.mjs | 46 + Tests/BridgeJSRuntimeTests/bridge-js.d.ts | 7 + Tests/prelude.mjs | 16 +- 52 files changed, 5227 insertions(+), 410 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncStaticImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js create mode 100644 Tests/BridgeJSRuntimeTests/AsyncImportTests.swift create mode 100644 Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs diff --git a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json index 95c4ac18e..b2c33ac01 100644 --- a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json +++ b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json @@ -2839,6 +2839,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "benchmarkHelperNoop", "parameters" : [ @@ -2850,6 +2855,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "benchmarkHelperNoopWithNumber", "parameters" : [ { @@ -2868,6 +2878,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "benchmarkRunner", "parameters" : [ { diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json index 60eb694ff..1a21916ee 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json @@ -242,6 +242,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "createTS2Swift", "parameters" : [ @@ -260,6 +265,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "convert", "parameters" : [ { diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index 142050f56..f3ed97ba3 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -12,7 +12,10 @@ public struct ClosureCodegen { public init() {} private func swiftClosureType(for signature: ClosureSignature) -> String { - let closureParams = signature.parameters.map { "\($0.closureSwiftType)" }.joined(separator: ", ") + let sendingPrefix = signature.sendingParameters ? "sending " : "" + let closureParams = signature.parameters.map { "\(sendingPrefix)\($0.closureSwiftType)" }.joined( + separator: ", " + ) let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "") let swiftReturnType = signature.returnType.closureSwiftType return "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)" @@ -29,6 +32,7 @@ public struct ClosureCodegen { let builder = try ImportTS.CallJSEmission( moduleName: "bjs", abiName: externName, + effects: Effects(isAsync: signature.isAsync, isThrows: signature.isThrows), returnType: signature.returnType, context: .exportSwift ) @@ -185,11 +189,10 @@ public struct ClosureCodegen { } public func renderSupport(for skeleton: BridgeJSSkeleton) throws -> String? { - let collector = ClosureSignatureCollectorVisitor() - var walker = BridgeTypeWalker(visitor: collector) + let collector = ClosureSignatureCollectorVisitor(moduleName: skeleton.moduleName) + var walker = BridgeSkeletonWalker(visitor: collector) walker.walk(skeleton) let closureSignatures = walker.visitor.signatures - guard !closureSignatures.isEmpty else { return nil } var decls: [DeclSyntax] = [] diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 5b6c7d1ff..ca7bdc3c2 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -1228,6 +1228,7 @@ struct ProtocolCodegen { let builder = try ImportTS.CallJSEmission( moduleName: moduleName, abiName: "_extern_\(method.name)", + effects: method.effects, returnType: method.returnType, context: .exportSwift ) @@ -1327,6 +1328,7 @@ struct ProtocolCodegen { let getterBuilder = try ImportTS.CallJSEmission( moduleName: moduleName, abiName: getterAbiName, + effects: Effects(isAsync: false, isThrows: false), returnType: property.type, context: .exportSwift ) @@ -1360,6 +1362,7 @@ struct ProtocolCodegen { let setterBuilder = try ImportTS.CallJSEmission( moduleName: moduleName, abiName: setterAbiName, + effects: Effects(isAsync: false, isThrows: false), returnType: .void, context: .exportSwift ) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 1d1fe3aa9..536c7eeab 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -66,9 +66,11 @@ public struct ImportTS { _ getter: ImportedGetterSkeleton, topLevelDecls: inout [DeclSyntax] ) throws -> [DeclSyntax] { + let effects = Effects(isAsync: false, isThrows: true) let builder = try CallJSEmission( moduleName: moduleName, abiName: getter.abiName(context: nil), + effects: effects, returnType: getter.type ) try builder.call() @@ -78,7 +80,8 @@ public struct ImportTS { builder.renderThunkDecl( name: "_$\(getter.name)_get", parameters: [], - returnType: getter.type + returnType: getter.type, + effects: effects ) .with(\.leadingTrivia, Self.renderDocumentation(documentation: getter.documentation)) ] @@ -94,13 +97,14 @@ public struct ImportTS { let abiName: String let moduleName: String + let effects: Effects let returnType: BridgeType let context: BridgeContext var body = CodeFragmentPrinter() var abiParameterForwardings: [String] = [] var abiParameterSignatures: [(name: String, type: WasmCoreType)] = [] - var abiReturnType: WasmCoreType? + let abiReturnType: WasmCoreType? // Track destructured variable names for multiple lowered parameters var destructuredVarNames: [String] = [] // Stack-lowered parameters should be evaluated in reverse order to match LIFO stacks @@ -111,15 +115,29 @@ public struct ImportTS { private var borrowedArguments: [BorrowedArgument] = [] private let needsReturnVariable: Bool - init(moduleName: String, abiName: String, returnType: BridgeType, context: BridgeContext = .importTS) throws { + init( + moduleName: String, + abiName: String, + effects: Effects, + returnType: BridgeType, + context: BridgeContext = .importTS + ) throws { self.moduleName = moduleName self.abiName = abiName + self.effects = effects self.returnType = returnType self.context = context let liftingInfo = try returnType.liftingReturnInfo(context: context) - needsReturnVariable = - !(returnType == .void || returnType.usesSideChannelForOptionalReturn() - || liftingInfo.valueToLift == nil) + if effects.isAsync || returnType == .void || returnType.usesSideChannelForOptionalReturn() { + abiReturnType = nil + } else { + abiReturnType = liftingInfo.valueToLift + } + needsReturnVariable = abiReturnType != nil + + if effects.isAsync { + prependClosureCallbackParams() + } } func lowerParameter(param: Parameter) throws { @@ -212,6 +230,15 @@ public struct ImportTS { } } + /// Prepends `resolveRef: Int32, rejectRef: Int32` parameters to the ABI parameter list. + /// + /// Used for async imports where the JS side receives closure-backed + /// resolve/reject callbacks as object references. + private func prependClosureCallbackParams() { + abiParameterSignatures.insert(contentsOf: [("resolveRef", .i32), ("rejectRef", .i32)], at: 0) + abiParameterForwardings.insert(contentsOf: ["resolveRef", "rejectRef"], at: 0) + } + func call() throws { for stmt in stackLoweringStmts { body.write(stmt.description) @@ -243,26 +270,32 @@ public struct ImportTS { } } - // Add exception check for ImportTS context - if context == .importTS { + // Add exception check for ImportTS context (skipped for async, where + // errors are funneled through the JS-side reject path) + if !effects.isAsync && context == .importTS { body.write("if let error = _swift_js_take_exception() { throw error }") } } func liftReturnValue() throws { + if effects.isAsync { + liftAsyncReturnValue() + } else { + try liftSyncReturnValue() + } + } + + private func liftSyncReturnValue() throws { let liftingInfo = try returnType.liftingReturnInfo(context: context) if returnType == .void { - abiReturnType = nil return } if returnType.usesSideChannelForOptionalReturn() { // Side channel returns: extern function returns Void, value is retrieved via side channel - abiReturnType = nil body.write("return \(returnType.swiftType).bridgeJSLiftReturnFromSideChannel()") } else { - abiReturnType = liftingInfo.valueToLift let liftExpr: String switch returnType { case .closure(let signature, _): @@ -278,12 +311,38 @@ public struct ImportTS { } } - func assignThis(returnType: BridgeType) { - guard case .jsObject = returnType else { - preconditionFailure("assignThis can only be called with a jsObject return type") + private func liftAsyncReturnValue() { + // For async imports, the extern function takes leading `resolveRef: Int32, rejectRef: Int32` + // and returns void. The JS side calls the resolve/reject closures when the Promise settles. + // The resolve closure is typed to match the return type, so the ABI conversion is handled + // by the existing closure codegen infrastructure — no manual JSValue-to-type switch needed. + + // Wrap the existing body (parameter lowering + extern call) in _bjs_awaitPromise + let innerBody = body + body = CodeFragmentPrinter() + + let rejectFactory = "makeRejectClosure: { JSTypedClosure<(sending JSValue) -> Void>($0) }" + if returnType == .void { + let resolveFactory = "makeResolveClosure: { JSTypedClosure<() -> Void>($0) }" + body.write( + "try await _bjs_awaitPromise(\(resolveFactory), \(rejectFactory)) { resolveRef, rejectRef in" + ) + } else { + let resolveSwiftType = returnType.closureSwiftType + let resolveFactory = + "makeResolveClosure: { JSTypedClosure<(sending \(resolveSwiftType)) -> Void>($0) }" + body.write( + "let resolved = try await _bjs_awaitPromise(\(resolveFactory), \(rejectFactory)) { resolveRef, rejectRef in" + ) + } + body.indent { + body.write(lines: innerBody.lines) + } + body.write("}") + + if returnType != .void { + body.write("return resolved") } - abiReturnType = .i32 - body.write("self.jsObject = JSObject(id: UInt32(bitPattern: ret))") } func renderImportDecl() -> DeclSyntax { @@ -299,9 +358,13 @@ public struct ImportTS { return "\(raw: printer.lines.joined(separator: "\n"))" } - func renderThunkDecl(name: String, parameters: [Parameter], returnType: BridgeType) -> DeclSyntax { + func renderThunkDecl( + name: String, + parameters: [Parameter], + returnType: BridgeType, + effects: Effects + ) -> DeclSyntax { let printer = CodeFragmentPrinter() - let effects = Effects(isAsync: false, isThrows: true) let signature = SwiftSignatureBuilder.buildFunctionSignature( parameters: parameters, returnType: returnType, @@ -362,6 +425,7 @@ public struct ImportTS { let builder = try CallJSEmission( moduleName: moduleName, abiName: function.abiName(context: nil), + effects: function.effects, returnType: function.returnType ) for param in function.parameters { @@ -374,7 +438,8 @@ public struct ImportTS { builder.renderThunkDecl( name: Self.thunkName(function: function), parameters: function.parameters, - returnType: function.returnType + returnType: function.returnType, + effects: function.effects ) .with(\.leadingTrivia, Self.renderDocumentation(documentation: function.documentation)) ] @@ -388,6 +453,7 @@ public struct ImportTS { let builder = try CallJSEmission( moduleName: moduleName, abiName: method.abiName(context: type), + effects: method.effects, returnType: method.returnType ) try builder.lowerParameter(param: selfParameter) @@ -401,14 +467,20 @@ public struct ImportTS { builder.renderThunkDecl( name: Self.thunkName(type: type, method: method), parameters: [selfParameter] + method.parameters, - returnType: method.returnType + returnType: method.returnType, + effects: method.effects ) ] } func renderStaticMethod(method: ImportedFunctionSkeleton) throws -> [DeclSyntax] { let abiName = method.abiName(context: type, operation: "static") - let builder = try CallJSEmission(moduleName: moduleName, abiName: abiName, returnType: method.returnType) + let builder = try CallJSEmission( + moduleName: moduleName, + abiName: abiName, + effects: method.effects, + returnType: method.returnType + ) for param in method.parameters { try builder.lowerParameter(param: param) } @@ -419,15 +491,18 @@ public struct ImportTS { builder.renderThunkDecl( name: Self.thunkName(type: type, method: method), parameters: method.parameters, - returnType: method.returnType + returnType: method.returnType, + effects: method.effects ) ] } func renderConstructorDecl(constructor: ImportedConstructorSkeleton) throws -> [DeclSyntax] { + let effects = Effects(isAsync: false, isThrows: true) let builder = try CallJSEmission( moduleName: moduleName, abiName: constructor.abiName(context: type), + effects: effects, returnType: .jsObject(nil) ) for param in constructor.parameters { @@ -440,15 +515,18 @@ public struct ImportTS { builder.renderThunkDecl( name: Self.thunkName(type: type), parameters: constructor.parameters, - returnType: .jsObject(nil) + returnType: .jsObject(nil), + effects: effects ) ] } func renderGetterDecl(getter: ImportedGetterSkeleton) throws -> DeclSyntax { + let effects = Effects(isAsync: false, isThrows: true) let builder = try CallJSEmission( moduleName: moduleName, abiName: getter.abiName(context: type), + effects: effects, returnType: getter.type ) try builder.lowerParameter(param: selfParameter) @@ -459,15 +537,18 @@ public struct ImportTS { builder.renderThunkDecl( name: Self.thunkName(type: type, propertyName: getter.name, operation: "get"), parameters: [selfParameter], - returnType: getter.type + returnType: getter.type, + effects: effects ) ) } func renderSetterDecl(setter: ImportedSetterSkeleton) throws -> DeclSyntax { + let effects = Effects(isAsync: false, isThrows: true) let builder = try CallJSEmission( moduleName: moduleName, abiName: setter.abiName(context: type), + effects: effects, returnType: .void ) let newValue = Parameter(label: nil, name: "newValue", type: setter.type) @@ -487,7 +568,8 @@ public struct ImportTS { return builder.renderThunkDecl( name: Self.thunkName(type: type, propertyName: propertyNameForThunk, operation: "set"), parameters: [selfParameter, newValue], - returnType: .void + returnType: .void, + effects: effects ) } if let constructor = type.constructor { diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 482b1fff5..7b7c6ca30 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -2137,7 +2137,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { let valueType: BridgeType } - /// Validates effects (throws required, async not supported) + /// Validates effects (throws required, async only supported for @JSFunction) private func validateEffects( _ effects: FunctionEffectSpecifiersSyntax?, node: some SyntaxProtocol, @@ -2153,7 +2153,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { ) return nil } - if effects.isAsync { + if effects.isAsync && attributeName != "JSFunction" { errors.append( DiagnosticError( node: node, @@ -2490,7 +2490,12 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { _ jsFunction: AttributeSyntax, _ node: FunctionDeclSyntax, ) -> ImportedFunctionSkeleton? { - guard validateEffects(node.signature.effectSpecifiers, node: node, attributeName: "JSFunction") != nil + guard + let effects = validateEffects( + node.signature.effectSpecifiers, + node: node, + attributeName: "JSFunction" + ) else { return nil } @@ -2516,6 +2521,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { from: from, parameters: parameters, returnType: returnType, + effects: effects, documentation: nil ) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index f69a4b266..63b628eb3 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -636,11 +636,10 @@ public struct BridgeJSLink { for unified in skeletons { let moduleName = unified.moduleName - let collector = ClosureSignatureCollectorVisitor() - var walker = BridgeTypeWalker(visitor: collector) + let collector = ClosureSignatureCollectorVisitor(moduleName: moduleName) + var walker = BridgeSkeletonWalker(visitor: collector) walker.walk(unified) let closureSignatures = walker.visitor.signatures - guard !closureSignatures.isEmpty else { continue } intrinsicRegistry.register(name: "swiftClosureHelpers") { helperPrinter in @@ -742,7 +741,12 @@ public struct BridgeJSLink { signature: ClosureSignature, functionName: String ) throws -> [String] { - let thunkBuilder = ImportedThunkBuilder(context: .exportSwift, intrinsicRegistry: intrinsicRegistry) + let thunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: signature.isAsync, isThrows: signature.isThrows), + returnType: signature.returnType, + context: .exportSwift, + intrinsicRegistry: intrinsicRegistry + ) thunkBuilder.parameterNames.append("callbackId") thunkBuilder.body.write("const callback = \(JSGlueVariableScope.reservedSwift).memory.getObject(callbackId);") @@ -751,13 +755,9 @@ public struct BridgeJSLink { try thunkBuilder.liftParameter(param: Parameter(label: nil, name: paramName, type: paramType)) } - let returnExpr = try thunkBuilder.call(calleeExpr: "callback", returnType: signature.returnType) + try thunkBuilder.call(calleeExpr: "callback") - var functionLines = thunkBuilder.renderFunction( - name: nil, - returnExpr: returnExpr, - returnType: signature.returnType - ) + var functionLines = thunkBuilder.renderFunction(name: nil) functionLines[0] = "bjs[\"\(functionName)\"] = " + functionLines[0] return functionLines @@ -1233,7 +1233,7 @@ public struct BridgeJSLink { for method in type.methods { let methodName = method.jsName ?? method.name let methodSignature = - "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: Effects(isAsync: false, isThrows: false)));" + "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" printer.write(methodSignature) } @@ -2164,15 +2164,25 @@ extension BridgeJSLink { class ImportedThunkBuilder { let body: CodeFragmentPrinter let scope: JSGlueVariableScope + let effects: Effects + let returnType: BridgeType let context: BridgeContext var parameterNames: [String] = [] var parameterForwardings: [String] = [] + var returnExpr: String? let printContext: IntrinsicJSFragment.PrintCodeContext - init(context: BridgeContext = .importTS, intrinsicRegistry: JSIntrinsicRegistry) { + init( + effects: Effects, + returnType: BridgeType, + context: BridgeContext = .importTS, + intrinsicRegistry: JSIntrinsicRegistry + ) { self.body = CodeFragmentPrinter() self.scope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry) self.context = context + self.effects = effects + self.returnType = returnType self.printContext = IntrinsicJSFragment.PrintCodeContext( scope: scope, printer: body, @@ -2202,7 +2212,15 @@ extension BridgeJSLink { parameterForwardings.append(contentsOf: liftedValues) } - func renderFunction( + func renderFunction(name: String?) -> [String] { + if effects.isAsync { + return renderAsyncFunction(name: name) + } else { + return renderSyncFunction(name: name, returnExpr: returnExpr, returnType: returnType) + } + } + + private func renderSyncFunction( name: String?, returnExpr: String?, returnType: BridgeType @@ -2232,21 +2250,44 @@ extension BridgeJSLink { return printer.lines } - func call(name: String, fromObjectExpr: String, returnType: BridgeType) throws -> String? { + /// Renders an async import function with resolve/reject closure refs. + /// + /// The generated function takes `resolveRef` and `rejectRef` as the first parameters, + /// looks up the resolve/reject closures from memory, and executes the body which + /// chains `.then(resolve, reject)` on the import's returned Promise. + private func renderAsyncFunction(name: String?) -> [String] { + let printer = CodeFragmentPrinter() + let allParams = ["resolveRef", "rejectRef"] + parameterNames + printer.write("function\(name.map { " \($0)" } ?? "")(\(allParams.joined(separator: ", "))) {") + printer.indent { + let s = JSGlueVariableScope.reservedSwift + printer.write("const resolve = \(s).memory.getObject(resolveRef);") + printer.write("const reject = \(s).memory.getObject(rejectRef);") + printer.write(contentsOf: body) + } + printer.write("}") + return printer.lines + } + + func call(name: String, fromObjectExpr: String) throws { let calleeExpr = Self.propertyAccessExpr(objectExpr: fromObjectExpr, propertyName: name) - return try self.call(calleeExpr: calleeExpr, returnType: returnType) + return try self.call(calleeExpr: calleeExpr) } - func call(name: String, returnType: BridgeType) throws -> String? { - return try call(name: name, fromObjectExpr: "imports", returnType: returnType) + func call(name: String) throws { + return try call(name: name, fromObjectExpr: "imports") } - func call(calleeExpr: String, returnType: BridgeType) throws -> String? { + func call(calleeExpr: String) throws { let callExpr = "\(calleeExpr)(\(parameterForwardings.joined(separator: ", ")))" - return try self.call(callExpr: callExpr, returnType: returnType) + try self.call(callExpr: callExpr) } - private func call(callExpr: String, returnType: BridgeType) throws -> String? { + private func call(callExpr: String) throws { + if effects.isAsync { + body.write("\(callExpr).then(resolve, reject);") + return + } let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: returnType, context: context) let returnExpr: String? if loweringFragment.parameters.count == 0 { @@ -2257,43 +2298,49 @@ extension BridgeJSLink { body.write("let \(resultVariable) = \(callExpr);") returnExpr = resultVariable } - return try lowerReturnValue( + self.returnExpr = try lowerReturnValue( returnType: returnType, returnExpr: returnExpr, loweringFragment: loweringFragment ) } - func callConstructor(jsName: String, swiftTypeName: String, fromObjectExpr: String) throws -> String? { + func callConstructor(jsName: String, swiftTypeName: String, fromObjectExpr: String) throws { let ctorExpr = Self.propertyAccessExpr(objectExpr: fromObjectExpr, propertyName: jsName) let call = "new \(ctorExpr)(\(parameterForwardings.joined(separator: ", ")))" let type: BridgeType = .jsObject(swiftTypeName) let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: type, context: context) - return try lowerReturnValue(returnType: type, returnExpr: call, loweringFragment: loweringFragment) + self.returnExpr = try lowerReturnValue( + returnType: type, + returnExpr: call, + loweringFragment: loweringFragment + ) } - func callConstructor(jsName: String, swiftTypeName: String) throws -> String? { + func callConstructor(jsName: String, swiftTypeName: String) throws { return try callConstructor(jsName: jsName, swiftTypeName: swiftTypeName, fromObjectExpr: "imports") } - func callMethod(name: String, returnType: BridgeType) throws -> String? { + func callMethod(name: String) throws { let objectExpr = "\(JSGlueVariableScope.reservedSwift).memory.getObject(self)" let calleeExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name) - return try call( - calleeExpr: calleeExpr, - returnType: returnType - ) + return try call(calleeExpr: calleeExpr) } - func callStaticMethod(on objectExpr: String, name: String, returnType: BridgeType) throws -> String? { + /// Generates an async method call with resolve/reject closure refs. + func callAsyncMethod(name: String) { + let objectExpr = "\(JSGlueVariableScope.reservedSwift).memory.getObject(self)" let calleeExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name) - return try call( - calleeExpr: calleeExpr, - returnType: returnType - ) + let callExpr = "\(calleeExpr)(\(parameterForwardings.joined(separator: ", ")))" + body.write("\(callExpr).then(resolve, reject);") + } + + func callStaticMethod(on objectExpr: String, name: String) throws { + let calleeExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name) + return try call(calleeExpr: calleeExpr) } - func callPropertyGetter(name: String, returnType: BridgeType) throws -> String? { + func callPropertyGetter(name: String) throws { let objectExpr = "\(JSGlueVariableScope.reservedSwift).memory.getObject(self)" let accessExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name) if context == .exportSwift, returnType.usesSideChannelForOptionalReturn() { @@ -2308,24 +2355,22 @@ extension BridgeJSLink { let fragment = try IntrinsicJSFragment.protocolPropertyOptionalToSideChannel(wrappedType: wrappedType) _ = try fragment.printCode([resultVar], printContext) - - return nil // Side-channel types return nil (no direct return value) + // Side-channel types return nil (no direct return value) + self.returnExpr = nil + return } - return try call( - callExpr: accessExpr, - returnType: returnType - ) + return try call(callExpr: accessExpr) } - func callPropertySetter(name: String, returnType: BridgeType) { + func callPropertySetter(name: String) { let objectExpr = "\(JSGlueVariableScope.reservedSwift).memory.getObject(self)" let accessExpr = Self.propertyAccessExpr(objectExpr: objectExpr, propertyName: name) let call = "\(accessExpr) = \(parameterForwardings.joined(separator: ", "))" body.write("\(call);") } - func getImportProperty(name: String, fromObjectExpr: String, returnType: BridgeType) throws -> String? { + func getImportProperty(name: String, fromObjectExpr: String, returnType: BridgeType) throws { if returnType == .void { throw BridgeJSLinkError(message: "Void is not supported for imported JS properties") } @@ -2343,14 +2388,14 @@ extension BridgeJSLink { returnExpr = resultVariable } - return try lowerReturnValue( + self.returnExpr = try lowerReturnValue( returnType: returnType, returnExpr: returnExpr, loweringFragment: loweringFragment ) } - func getImportProperty(name: String, returnType: BridgeType) throws -> String? { + func getImportProperty(name: String, returnType: BridgeType) throws { return try getImportProperty(name: name, fromObjectExpr: "imports", returnType: returnType) } @@ -3118,27 +3163,23 @@ extension BridgeJSLink { importObjectBuilder: ImportObjectBuilder, function: ImportedFunctionSkeleton ) throws { - let thunkBuilder = ImportedThunkBuilder(intrinsicRegistry: intrinsicRegistry) + let thunkBuilder = ImportedThunkBuilder( + effects: function.effects, + returnType: function.returnType, + intrinsicRegistry: intrinsicRegistry + ) for param in function.parameters { try thunkBuilder.liftParameter(param: param) } let jsName = function.jsName ?? function.name let importRootExpr = function.from == .global ? "globalThis" : "imports" - let returnExpr = try thunkBuilder.call( - name: jsName, - fromObjectExpr: importRootExpr, - returnType: function.returnType - ) - let funcLines = thunkBuilder.renderFunction( - name: function.abiName(context: nil), - returnExpr: returnExpr, - returnType: function.returnType - ) - let effects = Effects(isAsync: false, isThrows: false) + + try thunkBuilder.call(name: jsName, fromObjectExpr: importRootExpr) + let funcLines = thunkBuilder.renderFunction(name: function.abiName(context: nil)) if function.from == nil { importObjectBuilder.appendDts( [ - "\(renderTSPropertyName(jsName))\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: effects));" + "\(renderTSPropertyName(jsName))\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ] ) } @@ -3149,20 +3190,20 @@ extension BridgeJSLink { importObjectBuilder: ImportObjectBuilder, getter: ImportedGetterSkeleton ) throws { - let thunkBuilder = ImportedThunkBuilder(intrinsicRegistry: intrinsicRegistry) + let thunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: true), + returnType: getter.type, + intrinsicRegistry: intrinsicRegistry + ) let jsName = getter.jsName ?? getter.name let importRootExpr = getter.from == .global ? "globalThis" : "imports" - let returnExpr = try thunkBuilder.getImportProperty( + try thunkBuilder.getImportProperty( name: jsName, fromObjectExpr: importRootExpr, returnType: getter.type ) let abiName = getter.abiName(context: nil) - let funcLines = thunkBuilder.renderFunction( - name: abiName, - returnExpr: returnExpr, - returnType: getter.type - ) + let funcLines = thunkBuilder.renderFunction(name: abiName) if getter.from == nil { importObjectBuilder.appendDts(["readonly \(renderTSPropertyName(jsName)): \(getter.type.tsType);"]) } @@ -3186,10 +3227,7 @@ extension BridgeJSLink { getter: getter, abiName: getterAbiName, emitCall: { thunkBuilder in - return try thunkBuilder.callPropertyGetter( - name: getter.jsName ?? getter.name, - returnType: getter.type - ) + return try thunkBuilder.callPropertyGetter(name: getter.jsName ?? getter.name) } ) importObjectBuilder.assignToImportObject(name: getterAbiName, function: js) @@ -3205,8 +3243,7 @@ extension BridgeJSLink { try thunkBuilder.liftParameter( param: Parameter(label: nil, name: "newValue", type: setter.type) ) - thunkBuilder.callPropertySetter(name: setter.jsName ?? setter.name, returnType: setter.type) - return nil + thunkBuilder.callPropertySetter(name: setter.jsName ?? setter.name) } ) importObjectBuilder.assignToImportObject(name: setterAbiName, function: js) @@ -3231,7 +3268,7 @@ extension BridgeJSLink { for method in type.staticMethods { let methodName = method.jsName ?? method.name let signature = - "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: Effects(isAsync: false, isThrows: false)));" + "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" dtsPrinter.write(signature) } } @@ -3250,55 +3287,54 @@ extension BridgeJSLink { type: ImportedTypeSkeleton, constructor: ImportedConstructorSkeleton ) throws { - let thunkBuilder = ImportedThunkBuilder(intrinsicRegistry: intrinsicRegistry) + let thunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: true), + returnType: BridgeType.jsObject(type.name), + intrinsicRegistry: intrinsicRegistry + ) for param in constructor.parameters { try thunkBuilder.liftParameter(param: param) } - let returnType = BridgeType.jsObject(type.name) let importRootExpr = type.from == .global ? "globalThis" : "imports" - let returnExpr = try thunkBuilder.callConstructor( + try thunkBuilder.callConstructor( jsName: type.jsName ?? type.name, swiftTypeName: type.name, fromObjectExpr: importRootExpr ) let abiName = constructor.abiName(context: type) - let funcLines = thunkBuilder.renderFunction( - name: abiName, - returnExpr: returnExpr, - returnType: returnType - ) + let funcLines = thunkBuilder.renderFunction(name: abiName) importObjectBuilder.assignToImportObject(name: abiName, function: funcLines) } func renderImportedGetter( getter: ImportedGetterSkeleton, abiName: String, - emitCall: (ImportedThunkBuilder) throws -> String? + emitCall: (ImportedThunkBuilder) throws -> Void ) throws -> (js: [String], dts: [String]) { - let thunkBuilder = ImportedThunkBuilder(intrinsicRegistry: intrinsicRegistry) - thunkBuilder.liftSelf() - let returnExpr = try emitCall(thunkBuilder) - let funcLines = thunkBuilder.renderFunction( - name: abiName, - returnExpr: returnExpr, - returnType: getter.type + let thunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: true), + returnType: getter.type, + intrinsicRegistry: intrinsicRegistry ) + thunkBuilder.liftSelf() + try emitCall(thunkBuilder) + let funcLines = thunkBuilder.renderFunction(name: abiName) return (funcLines, []) } func renderImportedSetter( setter: ImportedSetterSkeleton, abiName: String, - emitCall: (ImportedThunkBuilder) throws -> String? + emitCall: (ImportedThunkBuilder) throws -> Void ) throws -> (js: [String], dts: [String]) { - let thunkBuilder = ImportedThunkBuilder(intrinsicRegistry: intrinsicRegistry) - thunkBuilder.liftSelf() - let returnExpr = try emitCall(thunkBuilder) - let funcLines = thunkBuilder.renderFunction( - name: abiName, - returnExpr: returnExpr, - returnType: .void + let thunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: true), + returnType: .void, + intrinsicRegistry: intrinsicRegistry ) + thunkBuilder.liftSelf() + try emitCall(thunkBuilder) + let funcLines = thunkBuilder.renderFunction(name: abiName) return (funcLines, []) } @@ -3306,7 +3342,11 @@ extension BridgeJSLink { context: ImportedTypeSkeleton, method: ImportedFunctionSkeleton ) throws -> (js: [String], dts: [String]) { - let thunkBuilder = ImportedThunkBuilder(intrinsicRegistry: intrinsicRegistry) + let thunkBuilder = ImportedThunkBuilder( + effects: method.effects, + returnType: method.returnType, + intrinsicRegistry: intrinsicRegistry + ) for param in method.parameters { try thunkBuilder.liftParameter(param: param) } @@ -3315,16 +3355,9 @@ extension BridgeJSLink { objectExpr: importRootExpr, propertyName: context.jsName ?? context.name ) - let returnExpr = try thunkBuilder.callStaticMethod( - on: constructorExpr, - name: method.jsName ?? method.name, - returnType: method.returnType - ) - let funcLines = thunkBuilder.renderFunction( - name: method.abiName(context: context, operation: "static"), - returnExpr: returnExpr, - returnType: method.returnType - ) + + try thunkBuilder.callStaticMethod(on: constructorExpr, name: method.jsName ?? method.name) + let funcLines = thunkBuilder.renderFunction(name: method.abiName(context: context, operation: "static")) return (funcLines, []) } @@ -3332,17 +3365,18 @@ extension BridgeJSLink { context: ImportedTypeSkeleton, method: ImportedFunctionSkeleton ) throws -> (js: [String], dts: [String]) { - let thunkBuilder = ImportedThunkBuilder(intrinsicRegistry: intrinsicRegistry) + let thunkBuilder = ImportedThunkBuilder( + effects: method.effects, + returnType: method.returnType, + intrinsicRegistry: intrinsicRegistry + ) thunkBuilder.liftSelf() for param in method.parameters { try thunkBuilder.liftParameter(param: param) } - let returnExpr = try thunkBuilder.callMethod(name: method.jsName ?? method.name, returnType: method.returnType) - let funcLines = thunkBuilder.renderFunction( - name: method.abiName(context: context), - returnExpr: returnExpr, - returnType: method.returnType - ) + + try thunkBuilder.callMethod(name: method.jsName ?? method.name) + let funcLines = thunkBuilder.renderFunction(name: method.abiName(context: context)) return (funcLines, []) } @@ -3360,16 +3394,14 @@ extension BridgeJSLink { ) let getterThunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: true), + returnType: property.type, context: .exportSwift, intrinsicRegistry: intrinsicRegistry ) getterThunkBuilder.liftSelf() - let returnExpr = try getterThunkBuilder.callPropertyGetter(name: property.name, returnType: property.type) - let getterLines = getterThunkBuilder.renderFunction( - name: getterAbiName, - returnExpr: returnExpr, - returnType: property.type - ) + try getterThunkBuilder.callPropertyGetter(name: property.name) + let getterLines = getterThunkBuilder.renderFunction(name: getterAbiName) importObjectBuilder.assignToImportObject(name: getterAbiName, function: getterLines) if !property.isReadonly { @@ -3381,6 +3413,8 @@ extension BridgeJSLink { className: `protocol`.name ) let setterThunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: false), + returnType: .void, context: .exportSwift, intrinsicRegistry: intrinsicRegistry ) @@ -3388,12 +3422,8 @@ extension BridgeJSLink { try setterThunkBuilder.liftParameter( param: Parameter(label: nil, name: "value", type: property.type) ) - setterThunkBuilder.callPropertySetter(name: property.name, returnType: property.type) - let setterLines = setterThunkBuilder.renderFunction( - name: setterAbiName, - returnExpr: nil, - returnType: .void - ) + setterThunkBuilder.callPropertySetter(name: property.name) + let setterLines = setterThunkBuilder.renderFunction(name: setterAbiName) importObjectBuilder.assignToImportObject(name: setterAbiName, function: setterLines) } } @@ -3404,6 +3434,8 @@ extension BridgeJSLink { method: ExportedFunction ) throws { let thunkBuilder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: false), + returnType: method.returnType, context: .exportSwift, intrinsicRegistry: intrinsicRegistry ) @@ -3411,12 +3443,8 @@ extension BridgeJSLink { for param in method.parameters { try thunkBuilder.liftParameter(param: param) } - let returnExpr = try thunkBuilder.callMethod(name: method.name, returnType: method.returnType) - let funcLines = thunkBuilder.renderFunction( - name: method.abiName, - returnExpr: returnExpr, - returnType: method.returnType - ) + try thunkBuilder.callMethod(name: method.name) + let funcLines = thunkBuilder.renderFunction(name: method.abiName) importObjectBuilder.assignToImportObject(name: method.abiName, function: funcLines) } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 1f03e09ba..c5672c79c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -101,24 +101,31 @@ public struct ClosureSignature: Codable, Equatable, Hashable, Sendable { public let isAsync: Bool public let isThrows: Bool public let moduleName: String + /// When true, closure parameters are annotated with `sending` in Swift. + /// Used for async Promise resolve/reject callbacks where values are + /// transferred through a continuation. + public let sendingParameters: Bool public init( parameters: [BridgeType], returnType: BridgeType, moduleName: String, isAsync: Bool = false, - isThrows: Bool = false + isThrows: Bool = false, + sendingParameters: Bool = false ) { self.parameters = parameters self.returnType = returnType self.moduleName = moduleName self.isAsync = isAsync self.isThrows = isThrows + self.sendingParameters = sendingParameters let paramPart = parameters.isEmpty ? "y" : parameters.map { $0.mangleTypeName }.joined() - let signaturePart = "\(paramPart)_\(returnType.mangleTypeName)" + let sendingPart = sendingParameters ? "s" : "" + let signaturePart = "\(sendingPart)\(paramPart)_\(returnType.mangleTypeName)" self.mangleName = "\(moduleName.count)\(moduleName)\(signaturePart)" } } @@ -388,13 +395,19 @@ public struct Parameter: Codable, Equatable, Sendable { } } -// MARK: - BridgeType Visitor +// MARK: - BridgeSkeleton Visitor -public protocol BridgeTypeVisitor { +public protocol BridgeSkeletonVisitor { mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) + mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) } -public struct BridgeTypeWalker { +public extension BridgeSkeletonVisitor { + mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) {} + mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) {} +} + +public struct BridgeSkeletonWalker { public var visitor: Visitor public init(visitor: Visitor) { @@ -480,6 +493,7 @@ public struct BridgeTypeWalker { } } public mutating func walk(_ function: ImportedFunctionSkeleton) { + visitor.visitImportedFunction(function) walk(function.parameters) walk(function.returnType) } @@ -923,6 +937,7 @@ public struct ImportedFunctionSkeleton: Codable { public let from: JSImportFrom? public let parameters: [Parameter] public let returnType: BridgeType + public let effects: Effects public let documentation: String? public init( @@ -931,6 +946,7 @@ public struct ImportedFunctionSkeleton: Codable { from: JSImportFrom? = nil, parameters: [Parameter], returnType: BridgeType, + effects: Effects = Effects(isAsync: false, isThrows: true), documentation: String? = nil ) { self.name = name @@ -938,6 +954,7 @@ public struct ImportedFunctionSkeleton: Codable { self.from = from self.parameters = parameters self.returnType = returnType + self.effects = effects self.documentation = documentation } @@ -1150,16 +1167,57 @@ public struct ImportedModuleSkeleton: Codable { // MARK: - Closure signature collection visitor -public struct ClosureSignatureCollectorVisitor: BridgeTypeVisitor { +public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { public var signatures: Set = [] + let moduleName: String - public init(signatures: Set = []) { + public init(moduleName: String, signatures: Set = []) { + self.moduleName = moduleName self.signatures = signatures } public mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) { signatures.insert(signature) } + public mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) { + guard function.effects.isAsync else { return } + + // When async imports exist, inject closure signatures for the typed resolve + // and reject callbacks used by _bjs_awaitPromise. + // - Reject always uses (sending JSValue) -> Void + // - Resolve uses a typed closure matching the return type (or () -> Void for void) + // All async callback closures use `sending` parameters so values can be + // transferred through the checked continuation without Sendable constraints. + + // Reject callback + signatures.insert( + ClosureSignature( + parameters: [.jsValue], + returnType: .void, + moduleName: moduleName, + sendingParameters: true + ) + ) + // Resolve callback (typed per return type) + if function.returnType == .void { + signatures.insert( + ClosureSignature( + parameters: [], + returnType: .void, + moduleName: moduleName + ) + ) + } else { + signatures.insert( + ClosureSignature( + parameters: [function.returnType], + returnType: .void, + moduleName: moduleName, + sendingParameters: true + ) + ) + } + } } // MARK: - Unified Skeleton diff --git a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js index 9617a5261..91a42a9ef 100644 --- a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js +++ b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js @@ -313,8 +313,8 @@ export class TypeProcessor { const parameters = signature.getParameters(); const parameterNameMap = this.buildParameterNameMap(parameters); const params = this.renderParameters(parameters, decl); - const returnType = this.visitType(signature.getReturnType(), decl); - const effects = this.renderEffects({ isAsync: false }); + const { returnType, isAsync } = this.unwrapPromiseReturnType(signature.getReturnType(), decl); + const effects = this.renderEffects({ isAsync }); const annotation = this.renderMacroAnnotation("JSFunction", args); this.emitDocComment(decl, { indent: "", parameterNameMap }); @@ -581,8 +581,8 @@ export class TypeProcessor { const parameters = signature.getParameters(); const parameterNameMap = this.buildParameterNameMap(parameters); const params = this.renderParameters(parameters, node); - const returnType = this.visitType(signature.getReturnType(), node); - const effects = this.renderEffects({ isAsync: false }); + const { returnType, isAsync } = this.unwrapPromiseReturnType(signature.getReturnType(), node); + const effects = this.renderEffects({ isAsync }); const swiftFuncName = this.renderIdentifier(swiftName); this.emitDocComment(node, { parameterNameMap }); @@ -1210,8 +1210,8 @@ export class TypeProcessor { const parameters = signature.getParameters(); const parameterNameMap = this.buildParameterNameMap(parameters); const params = this.renderParameters(parameters, node); - const returnType = this.visitType(signature.getReturnType(), node); - const effects = this.renderEffects({ isAsync: false }); + const { returnType, isAsync } = this.unwrapPromiseReturnType(signature.getReturnType(), node); + const effects = this.renderEffects({ isAsync }); const swiftMethodName = this.renderIdentifier(swiftName); const isStatic = node.modifiers?.some( (modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword @@ -1281,6 +1281,27 @@ export class TypeProcessor { return parts.join(" "); } + /** + * Check if a type is Promise and extract the return type and async flag. + * @param {ts.Type} type - The return type to check + * @param {ts.Node} node - The node for type visiting context + * @returns {{ returnType: string, isAsync: boolean }} + * @private + */ + unwrapPromiseReturnType(type, node) { + if (isTypeReference(type)) { + const symbol = type.target?.getSymbol(); + if (symbol?.name === "Promise") { + const typeArgs = this.checker.getTypeArguments(/** @type {ts.TypeReference} */ (type)); + const innerType = typeArgs && typeArgs.length > 0 + ? this.visitType(typeArgs[0], node) + : "Void"; + return { returnType: innerType, isAsync: true }; + } + } + return { returnType: this.visitType(type, node), isAsync: false }; + } + /** * @param {ts.Node} node * @returns {boolean} diff --git a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap index 4122f4148..643ac8441 100644 --- a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap +++ b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap @@ -32,19 +32,19 @@ exports[`ts2swift > snapshots Swift output for Async.d.ts > Async 1`] = ` @_spi(BridgeJS) import JavaScriptKit -@JSFunction func asyncReturnVoid() throws(JSException) -> JSPromise +@JSFunction func asyncReturnVoid() async throws(JSException) -> Void -@JSFunction func asyncRoundTripInt(_ v: Double) throws(JSException) -> JSPromise +@JSFunction func asyncRoundTripInt(_ v: Double) async throws(JSException) -> Double -@JSFunction func asyncRoundTripString(_ v: String) throws(JSException) -> JSPromise +@JSFunction func asyncRoundTripString(_ v: String) async throws(JSException) -> String -@JSFunction func asyncRoundTripBool(_ v: Bool) throws(JSException) -> JSPromise +@JSFunction func asyncRoundTripBool(_ v: Bool) async throws(JSException) -> Bool -@JSFunction func asyncRoundTripFloat(_ v: Double) throws(JSException) -> JSPromise +@JSFunction func asyncRoundTripFloat(_ v: Double) async throws(JSException) -> Double -@JSFunction func asyncRoundTripDouble(_ v: Double) throws(JSException) -> JSPromise +@JSFunction func asyncRoundTripDouble(_ v: Double) async throws(JSException) -> Double -@JSFunction func asyncRoundTripJSObject(_ v: JSValue) throws(JSException) -> JSPromise +@JSFunction func asyncRoundTripJSObject(_ v: JSValue) async throws(JSException) -> JSValue " `; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncImport.swift new file mode 100644 index 000000000..02563cbdf --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncImport.swift @@ -0,0 +1,6 @@ +@JSFunction func asyncReturnVoid() async throws(JSException) +@JSFunction func asyncRoundTripInt(_ v: Int) async throws(JSException) -> Int +@JSFunction func asyncRoundTripString(_ v: String) async throws(JSException) -> String +@JSFunction func asyncRoundTripBool(_ v: Bool) async throws(JSException) -> Bool +@JSFunction func asyncRoundTripDouble(_ v: Double) async throws(JSException) -> Double +@JSFunction func asyncRoundTripJSObject(_ v: JSObject) async throws(JSException) -> JSObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncStaticImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncStaticImport.swift new file mode 100644 index 000000000..1afd758bf --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncStaticImport.swift @@ -0,0 +1,4 @@ +@JSClass struct AsyncBox { + @JSFunction static func asyncStaticRoundTrip(_ v: Double) async throws(JSException) -> Double + @JSFunction static func asyncStaticVoid() async throws(JSException) +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json index 3664fa339..d071d8c52 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json @@ -1331,6 +1331,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "checkArray", "parameters" : [ { @@ -1349,6 +1354,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "checkArrayWithLength", "parameters" : [ { @@ -1375,6 +1385,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "importProcessNumbers", "parameters" : [ { @@ -1397,6 +1412,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "importGetNumbers", "parameters" : [ @@ -1412,6 +1432,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "importTransformNumbers", "parameters" : [ { @@ -1438,6 +1463,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "importProcessStrings", "parameters" : [ { @@ -1464,6 +1494,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "importProcessBooleans", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json new file mode 100644 index 000000000..263578d20 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json @@ -0,0 +1,151 @@ +{ + "imported" : { + "children" : [ + { + "functions" : [ + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncReturnVoid", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncRoundTripInt", + "parameters" : [ + { + "name" : "v", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncRoundTripString", + "parameters" : [ + { + "name" : "v", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncRoundTripBool", + "parameters" : [ + { + "name" : "v", + "type" : { + "bool" : { + + } + } + } + ], + "returnType" : { + "bool" : { + + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncRoundTripDouble", + "parameters" : [ + { + "name" : "v", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "double" : { + + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncRoundTripJSObject", + "parameters" : [ + { + "name" : "v", + "type" : { + "jsObject" : { + + } + } + } + ], + "returnType" : { + "jsObject" : { + + } + } + } + ], + "types" : [ + + ] + } + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.swift new file mode 100644 index 000000000..7a60bc6b7 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.swift @@ -0,0 +1,569 @@ +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules7JSValueV_y") +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + return invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(callback, param0Kind, param0Payload1, param0Payload2) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules7JSValueV_y") +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModules7JSValueV_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending JSValue) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0Kind, param0Payload1, param0Payload2) = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModules7JSValueV_y(callbackValue, param0Kind, param0Payload1, param0Payload2) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending JSValue) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending JSValue) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModules7JSValueV_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +public func _invoke_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending JSValue) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSValue.bridgeJSLiftParameter(param0Kind, param0Payload1, param0Payload2)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules8JSObjectC_y") +fileprivate func invoke_js_callback_TestModule_10TestModules8JSObjectC_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModules8JSObjectC_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules8JSObjectC_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModules8JSObjectC_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules8JSObjectC_y") +fileprivate func make_swift_closure_TestModule_10TestModules8JSObjectC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModules8JSObjectC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules8JSObjectC_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModules8JSObjectC_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModules8JSObjectC_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending JSObject) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModules8JSObjectC_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending JSObject) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending JSObject) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModules8JSObjectC_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules8JSObjectC_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModules8JSObjectC_y") +public func _invoke_swift_closure_TestModule_10TestModules8JSObjectC_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending JSObject) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSObject.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSS_y") +fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModulesSS_y_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSS_y") +fileprivate func make_swift_closure_TestModule_10TestModulesSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModulesSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSS_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModulesSS_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModulesSS_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending String) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModulesSS_y(callbackValue, param0Bytes, param0Length) + } + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending String) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending String) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModulesSS_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSS_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModulesSS_y") +public func _invoke_swift_closure_TestModule_10TestModulesSS_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending String) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSb_y") +fileprivate func invoke_js_callback_TestModule_10TestModulesSb_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModulesSb_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSb_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModulesSb_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSb_y") +fileprivate func make_swift_closure_TestModule_10TestModulesSb_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModulesSb_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSb_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModulesSb_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModulesSb_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Bool) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModulesSb_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Bool) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Bool) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModulesSb_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSb_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModulesSb_y") +public func _invoke_swift_closure_TestModule_10TestModulesSb_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Bool) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Bool.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSd_y") +fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y(_ callback: Int32, _ param0: Float64) -> Void { + return invoke_js_callback_TestModule_10TestModulesSd_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSd_y") +fileprivate func make_swift_closure_TestModule_10TestModulesSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModulesSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSd_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModulesSd_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModulesSd_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Double) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModulesSd_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Double) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Double) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModulesSd_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSd_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModulesSd_y") +public func _invoke_swift_closure_TestModule_10TestModulesSd_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Double) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Double.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSi_y") +fileprivate func invoke_js_callback_TestModule_10TestModulesSi_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModulesSi_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSi_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModulesSi_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSi_y") +fileprivate func make_swift_closure_TestModule_10TestModulesSi_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModulesSi_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSi_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModulesSi_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModulesSi_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Int) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModulesSi_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Int) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Int) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModulesSi_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSi_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModulesSi_y") +public func _invoke_swift_closure_TestModule_10TestModulesSi_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Int) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Int.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuley_y") +fileprivate func invoke_js_callback_TestModule_10TestModuley_y_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuley_y_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuley_y(_ callback: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuley_y_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuley_y") +fileprivate func make_swift_closure_TestModule_10TestModuley_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuley_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuley_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuley_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuley_y { + static func bridgeJSLift(_ callbackId: Int32) -> () -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModuley_y(callbackValue) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == () -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping () -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuley_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuley_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModuley_y") +public func _invoke_swift_closure_TestModule_10TestModuley_y(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<() -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_asyncReturnVoid") +fileprivate func bjs_asyncReturnVoid_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void +#else +fileprivate func bjs_asyncReturnVoid_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_asyncReturnVoid(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_asyncReturnVoid_extern(resolveRef, rejectRef) +} + +func _$asyncReturnVoid() async throws(JSException) -> Void { + try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<() -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + bjs_asyncReturnVoid(resolveRef, rejectRef) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_asyncRoundTripInt") +fileprivate func bjs_asyncRoundTripInt_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void +#else +fileprivate func bjs_asyncRoundTripInt_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_asyncRoundTripInt(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + return bjs_asyncRoundTripInt_extern(resolveRef, rejectRef, v) +} + +func _$asyncRoundTripInt(_ v: Int) async throws(JSException) -> Int { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Int) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vValue = v.bridgeJSLowerParameter() + bjs_asyncRoundTripInt(resolveRef, rejectRef, vValue) + } + return resolved +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_asyncRoundTripString") +fileprivate func bjs_asyncRoundTripString_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void +#else +fileprivate func bjs_asyncRoundTripString_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_asyncRoundTripString(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + return bjs_asyncRoundTripString_extern(resolveRef, rejectRef, vBytes, vLength) +} + +func _$asyncRoundTripString(_ v: String) async throws(JSException) -> String { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending String) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + v.bridgeJSWithLoweredParameter { (vBytes, vLength) in + bjs_asyncRoundTripString(resolveRef, rejectRef, vBytes, vLength) + } + } + return resolved +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_asyncRoundTripBool") +fileprivate func bjs_asyncRoundTripBool_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void +#else +fileprivate func bjs_asyncRoundTripBool_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_asyncRoundTripBool(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + return bjs_asyncRoundTripBool_extern(resolveRef, rejectRef, v) +} + +func _$asyncRoundTripBool(_ v: Bool) async throws(JSException) -> Bool { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Bool) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vValue = v.bridgeJSLowerParameter() + bjs_asyncRoundTripBool(resolveRef, rejectRef, vValue) + } + return resolved +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_asyncRoundTripDouble") +fileprivate func bjs_asyncRoundTripDouble_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void +#else +fileprivate func bjs_asyncRoundTripDouble_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_asyncRoundTripDouble(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void { + return bjs_asyncRoundTripDouble_extern(resolveRef, rejectRef, v) +} + +func _$asyncRoundTripDouble(_ v: Double) async throws(JSException) -> Double { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Double) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vValue = v.bridgeJSLowerParameter() + bjs_asyncRoundTripDouble(resolveRef, rejectRef, vValue) + } + return resolved +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_asyncRoundTripJSObject") +fileprivate func bjs_asyncRoundTripJSObject_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void +#else +fileprivate func bjs_asyncRoundTripJSObject_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_asyncRoundTripJSObject(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + return bjs_asyncRoundTripJSObject_extern(resolveRef, rejectRef, v) +} + +func _$asyncRoundTripJSObject(_ v: JSObject) async throws(JSException) -> JSObject { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending JSObject) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vValue = v.bridgeJSLowerParameter() + bjs_asyncRoundTripJSObject(resolveRef, rejectRef, vValue) + } + return resolved +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json new file mode 100644 index 000000000..972a532c6 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json @@ -0,0 +1,67 @@ +{ + "imported" : { + "children" : [ + { + "functions" : [ + + ], + "types" : [ + { + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "AsyncBox", + "setters" : [ + + ], + "staticMethods" : [ + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncStaticRoundTrip", + "parameters" : [ + { + "name" : "v", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "double" : { + + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncStaticVoid", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ] + } + ] + } + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.swift new file mode 100644 index 000000000..ee7dc73e7 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.swift @@ -0,0 +1,227 @@ +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules7JSValueV_y") +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + return invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(callback, param0Kind, param0Payload1, param0Payload2) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules7JSValueV_y") +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModules7JSValueV_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending JSValue) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0Kind, param0Payload1, param0Payload2) = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModules7JSValueV_y(callbackValue, param0Kind, param0Payload1, param0Payload2) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending JSValue) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending JSValue) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModules7JSValueV_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +public func _invoke_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending JSValue) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSValue.bridgeJSLiftParameter(param0Kind, param0Payload1, param0Payload2)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSd_y") +fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSd_y(_ callback: Int32, _ param0: Float64) -> Void { + return invoke_js_callback_TestModule_10TestModulesSd_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSd_y") +fileprivate func make_swift_closure_TestModule_10TestModulesSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModulesSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSd_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModulesSd_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModulesSd_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Double) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModulesSd_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Double) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Double) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModulesSd_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSd_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModulesSd_y") +public func _invoke_swift_closure_TestModule_10TestModulesSd_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Double) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Double.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuley_y") +fileprivate func invoke_js_callback_TestModule_10TestModuley_y_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuley_y_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuley_y(_ callback: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuley_y_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuley_y") +fileprivate func make_swift_closure_TestModule_10TestModuley_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuley_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuley_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuley_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuley_y { + static func bridgeJSLift(_ callbackId: Int32) -> () -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModuley_y(callbackValue) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == () -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping () -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuley_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuley_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModuley_y") +public func _invoke_swift_closure_TestModule_10TestModuley_y(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<() -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_AsyncBox_asyncStaticRoundTrip_static") +fileprivate func bjs_AsyncBox_asyncStaticRoundTrip_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void +#else +fileprivate func bjs_AsyncBox_asyncStaticRoundTrip_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncBox_asyncStaticRoundTrip_static(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void { + return bjs_AsyncBox_asyncStaticRoundTrip_static_extern(resolveRef, rejectRef, v) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_AsyncBox_asyncStaticVoid_static") +fileprivate func bjs_AsyncBox_asyncStaticVoid_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void +#else +fileprivate func bjs_AsyncBox_asyncStaticVoid_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncBox_asyncStaticVoid_static(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_AsyncBox_asyncStaticVoid_static_extern(resolveRef, rejectRef) +} + +func _$AsyncBox_asyncStaticRoundTrip(_ v: Double) async throws(JSException) -> Double { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Double) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vValue = v.bridgeJSLowerParameter() + bjs_AsyncBox_asyncStaticRoundTrip_static(resolveRef, rejectRef, vValue) + } + return resolved +} + +func _$AsyncBox_asyncStaticVoid() async throws(JSException) -> Void { + try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<() -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + bjs_AsyncBox_asyncStaticVoid_static(resolveRef, rejectRef) + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json index 4d7495a7c..a0c2c80c6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json @@ -4,6 +4,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "fetchNumber", "parameters" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json index c740dc46f..ea707098d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json @@ -235,6 +235,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "importMirrorDictionary", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json index ba36405ba..fc4a7ae52 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json @@ -1526,6 +1526,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "takesFeatureFlag", "parameters" : [ { @@ -1545,6 +1550,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "returnsFeatureFlag", "parameters" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json index bef9cbc88..15a20f72e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json @@ -269,6 +269,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripInt8", "parameters" : [ { @@ -293,6 +298,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripUInt8", "parameters" : [ { @@ -317,6 +327,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripInt16", "parameters" : [ { @@ -341,6 +356,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripUInt16", "parameters" : [ { @@ -365,6 +385,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripInt32", "parameters" : [ { @@ -389,6 +414,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripUInt32", "parameters" : [ { @@ -413,6 +443,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripInt64", "parameters" : [ { @@ -437,6 +472,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripUInt64", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json index 55ac7dd70..f750fc6a5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json @@ -22,6 +22,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "log", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json index 5e002e34f..809a9ad99 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json @@ -4,6 +4,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "from" : "global", "jsName" : "parseInt", "name" : "parseInt", @@ -42,6 +47,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "log", "parameters" : [ { @@ -87,6 +97,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "close", "parameters" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json index 7f79a8146..3f9cb8e32 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json @@ -4,6 +4,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundtrip", "parameters" : [ { @@ -36,6 +41,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "logStrings", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json index 935f7a7f2..1ad99f397 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json @@ -4,6 +4,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "createWeirdObject", "parameters" : [ @@ -15,6 +20,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "createWeirdClass", "parameters" : [ @@ -100,6 +110,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "as", "parameters" : [ @@ -111,6 +126,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "try", "parameters" : [ @@ -218,6 +238,11 @@ "jsName" : "$Weird", "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "jsName" : "method-with-dashes", "name" : "method_with_dashes", "parameters" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json index 689e86150..ef8eba9ba 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json @@ -4,6 +4,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "returnAnimatable", "parameters" : [ @@ -49,6 +54,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "greet", "parameters" : [ @@ -60,6 +70,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "changeName", "parameters" : [ { @@ -100,6 +115,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "animate", "parameters" : [ { @@ -126,6 +146,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "getAnimations", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json index a8b64558f..18f7cfaac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json @@ -12,6 +12,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "value", "parameters" : [ @@ -29,6 +34,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "create", "parameters" : [ { @@ -47,6 +57,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "value", "parameters" : [ @@ -58,6 +73,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "makeDefault", "parameters" : [ @@ -69,6 +89,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "jsName" : "with-dashes", "name" : "dashed", "parameters" : [ @@ -107,6 +132,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "create", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json index 5bd83be27..fb8601ae7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json @@ -321,6 +321,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsEchoJSValue", "parameters" : [ { @@ -339,6 +344,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsEchoJSValueArray", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json index 67d97821c..3e6d6c60c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json @@ -1152,6 +1152,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripStringOrNull", "parameters" : [ { @@ -1180,6 +1185,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripStringOrUndefined", "parameters" : [ { @@ -1208,6 +1218,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripDoubleOrNull", "parameters" : [ { @@ -1236,6 +1251,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripDoubleOrUndefined", "parameters" : [ { @@ -1264,6 +1284,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripBoolOrNull", "parameters" : [ { @@ -1292,6 +1317,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripBoolOrUndefined", "parameters" : [ { @@ -1320,6 +1350,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripIntOrNull", "parameters" : [ { @@ -1354,6 +1389,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "roundTripIntOrUndefined", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json index f75bf7610..cf76f3878 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json @@ -88,6 +88,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "check", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json index cded9a973..b0398c161 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json @@ -112,6 +112,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "checkNumber", "parameters" : [ @@ -123,6 +128,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "checkBoolean", "parameters" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json index 4ba7ba9a5..36d6941d3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json @@ -84,7 +84,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -130,7 +131,8 @@ "swiftProtocol" : { "_0" : "Renderable" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -166,7 +168,8 @@ "swiftProtocol" : { "_0" : "Renderable" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -191,7 +194,8 @@ "swiftProtocol" : { "_0" : "Renderable" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -232,7 +236,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json index b0aa8c35b..75462af81 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json @@ -71,6 +71,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "checkString", "parameters" : [ { @@ -89,6 +94,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "checkStringWithLength", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json index 3f9271592..1088a5cab 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json @@ -38,6 +38,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "checkString", "parameters" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index 6ab78c82c..ceda64904 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -213,6 +213,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripGreeter", "parameters" : [ { @@ -231,6 +236,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalGreeter", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json index f610d4bde..41662e48b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json @@ -61,7 +61,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -313,7 +314,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -338,7 +340,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -380,7 +383,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -411,7 +415,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -447,7 +452,8 @@ "bool" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -472,7 +478,8 @@ "bool" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -508,7 +515,8 @@ "float" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -533,7 +541,8 @@ "float" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -569,7 +578,8 @@ "double" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -594,7 +604,8 @@ "double" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -640,7 +651,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -675,7 +687,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -727,7 +740,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -768,7 +782,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -814,7 +829,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -849,7 +865,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -895,7 +912,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -930,7 +948,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -976,7 +995,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1011,7 +1031,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1047,7 +1068,8 @@ "swiftHeapObject" : { "_0" : "Person" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1072,7 +1094,8 @@ "swiftHeapObject" : { "_0" : "Person" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1118,7 +1141,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1153,7 +1177,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1189,7 +1214,8 @@ "caseEnum" : { "_0" : "Direction" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1214,7 +1240,8 @@ "caseEnum" : { "_0" : "Direction" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1252,7 +1279,8 @@ "_0" : "Theme", "_1" : "String" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1279,7 +1307,8 @@ "_0" : "Theme", "_1" : "String" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1317,7 +1346,8 @@ "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1344,7 +1374,8 @@ "_0" : "HttpStatus", "_1" : "Int" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1380,7 +1411,8 @@ "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1405,7 +1437,8 @@ "associatedValueEnum" : { "_0" : "APIResult" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1451,7 +1484,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1486,7 +1520,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1534,7 +1569,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1571,7 +1607,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1619,7 +1656,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1656,7 +1694,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1702,7 +1741,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1737,7 +1777,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1783,7 +1824,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -1818,7 +1860,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json index 4359b50ec..a78b1bf5d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json @@ -4,6 +4,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "applyInt", "parameters" : [ { @@ -43,7 +48,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -60,6 +66,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "makeAdder", "parameters" : [ { @@ -98,7 +109,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json index c1329cd79..ccd3043ac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json @@ -56,6 +56,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "translate", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json index 14da32841..7f19c18bf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json @@ -38,6 +38,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "check", "parameters" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts new file mode 100644 index 000000000..e612ae1e1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.d.ts @@ -0,0 +1,23 @@ +// 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 type Exports = { +} +export type Imports = { + asyncReturnVoid(): Promise; + asyncRoundTripInt(v: number): Promise; + asyncRoundTripString(v: string): Promise; + asyncRoundTripBool(v: boolean): Promise; + asyncRoundTripDouble(v: number): Promise; + asyncRoundTripJSObject(v: any): Promise; +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js new file mode 100644 index 000000000..89ab29827 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js @@ -0,0 +1,507 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + 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 swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.unregistered) { return; } + instance?.exports?.bjs_release_swift_closure(state.pointer); + }); + const makeClosure = (pointer, file, line, func) => { + const state = { pointer, file, line, unregistered: false }; + const real = (...args) => { + if (state.unregistered) { + const bytes = new Uint8Array(memory.buffer, state.file); + let length = 0; + while (bytes[length] !== 0) { length += 1; } + const fileID = decodeString(state.file, length); + throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); + } + return func(...args); + }; + real.__unregister = () => { + if (state.unregistered) { return; } + state.unregistered = true; + swiftClosureRegistry.unregister(state); + }; + swiftClosureRegistry.register(real, state, state); + return swift.memory.retain(real); + }; + + + 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); + 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, len); + 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(); + } + 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) {} + bjs["swift_js_closure_unregister"] = function(funcRef) { + const func = swift.memory.getObject(funcRef); + func.__unregister(); + } + bjs["invoke_js_callback_TestModule_10TestModules7JSValueV_y"] = function(callbackId, param0Kind, param0Payload1, param0Payload2) { + try { + const callback = swift.memory.getObject(callbackId); + const jsValue = __bjs_jsValueLift(param0Kind, param0Payload1, param0Payload2); + callback(jsValue); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModules7JSValueV_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModules7JSValueV_y = function(param0) { + const [param0Kind, param0Payload1, param0Payload2] = __bjs_jsValueLower(param0); + instance.exports.invoke_swift_closure_TestModule_10TestModules7JSValueV_y(boxPtr, param0Kind, param0Payload1, param0Payload2); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModules7JSValueV_y); + } + bjs["invoke_js_callback_TestModule_10TestModules8JSObjectC_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(swift.memory.getObject(param0)); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModules8JSObjectC_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModules8JSObjectC_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModules8JSObjectC_y(boxPtr, swift.memory.retain(param0)); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModules8JSObjectC_y); + } + bjs["invoke_js_callback_TestModule_10TestModulesSS_y"] = function(callbackId, param0Bytes, param0Count) { + try { + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + callback(string); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModulesSS_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModulesSS_y = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + instance.exports.invoke_swift_closure_TestModule_10TestModulesSS_y(boxPtr, param0Id, param0Bytes.length); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModulesSS_y); + } + bjs["invoke_js_callback_TestModule_10TestModulesSb_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(param0 !== 0); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModulesSb_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModulesSb_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModulesSb_y(boxPtr, param0); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModulesSb_y); + } + bjs["invoke_js_callback_TestModule_10TestModulesSd_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(param0); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModulesSd_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModulesSd_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModulesSd_y(boxPtr, param0); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModulesSd_y); + } + bjs["invoke_js_callback_TestModule_10TestModulesSi_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(param0); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModulesSi_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModulesSi_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModulesSi_y(boxPtr, param0); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModulesSi_y); + } + bjs["invoke_js_callback_TestModule_10TestModuley_y"] = function(callbackId) { + try { + const callback = swift.memory.getObject(callbackId); + callback(); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModuley_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuley_y = function() { + instance.exports.invoke_swift_closure_TestModule_10TestModuley_y(boxPtr); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuley_y); + } + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_asyncReturnVoid"] = function bjs_asyncReturnVoid(resolveRef, rejectRef) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + imports.asyncReturnVoid().then(resolve, reject); + } + TestModule["bjs_asyncRoundTripInt"] = function bjs_asyncRoundTripInt(resolveRef, rejectRef, v) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + imports.asyncRoundTripInt(v).then(resolve, reject); + } + TestModule["bjs_asyncRoundTripString"] = function bjs_asyncRoundTripString(resolveRef, rejectRef, vBytes, vCount) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + const string = decodeString(vBytes, vCount); + imports.asyncRoundTripString(string).then(resolve, reject); + } + TestModule["bjs_asyncRoundTripBool"] = function bjs_asyncRoundTripBool(resolveRef, rejectRef, v) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + imports.asyncRoundTripBool(v !== 0).then(resolve, reject); + } + TestModule["bjs_asyncRoundTripDouble"] = function bjs_asyncRoundTripDouble(resolveRef, rejectRef, v) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + imports.asyncRoundTripDouble(v).then(resolve, reject); + } + TestModule["bjs_asyncRoundTripJSObject"] = function bjs_asyncRoundTripJSObject(resolveRef, rejectRef, v) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + imports.asyncRoundTripJSObject(swift.memory.getObject(v)).then(resolve, reject); + } + }, + 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const exports = { + }; + _exports = exports; + return 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 new file mode 100644 index 000000000..491a66795 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.d.ts @@ -0,0 +1,23 @@ +// 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 interface AsyncBox { +} +export type Exports = { +} +export type Imports = { + AsyncBox: { + asyncStaticRoundTrip(v: number): Promise; + asyncStaticVoid(): Promise; + } +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js new file mode 100644 index 000000000..7fd6a0d6b --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js @@ -0,0 +1,402 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + 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 swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.unregistered) { return; } + instance?.exports?.bjs_release_swift_closure(state.pointer); + }); + const makeClosure = (pointer, file, line, func) => { + const state = { pointer, file, line, unregistered: false }; + const real = (...args) => { + if (state.unregistered) { + const bytes = new Uint8Array(memory.buffer, state.file); + let length = 0; + while (bytes[length] !== 0) { length += 1; } + const fileID = decodeString(state.file, length); + throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); + } + return func(...args); + }; + real.__unregister = () => { + if (state.unregistered) { return; } + state.unregistered = true; + swiftClosureRegistry.unregister(state); + }; + swiftClosureRegistry.register(real, state, state); + return swift.memory.retain(real); + }; + + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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(); + } + 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) {} + bjs["swift_js_closure_unregister"] = function(funcRef) { + const func = swift.memory.getObject(funcRef); + func.__unregister(); + } + bjs["invoke_js_callback_TestModule_10TestModules7JSValueV_y"] = function(callbackId, param0Kind, param0Payload1, param0Payload2) { + try { + const callback = swift.memory.getObject(callbackId); + const jsValue = __bjs_jsValueLift(param0Kind, param0Payload1, param0Payload2); + callback(jsValue); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModules7JSValueV_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModules7JSValueV_y = function(param0) { + const [param0Kind, param0Payload1, param0Payload2] = __bjs_jsValueLower(param0); + instance.exports.invoke_swift_closure_TestModule_10TestModules7JSValueV_y(boxPtr, param0Kind, param0Payload1, param0Payload2); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModules7JSValueV_y); + } + bjs["invoke_js_callback_TestModule_10TestModulesSd_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(param0); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModulesSd_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModulesSd_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModulesSd_y(boxPtr, param0); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModulesSd_y); + } + bjs["invoke_js_callback_TestModule_10TestModuley_y"] = function(callbackId) { + try { + const callback = swift.memory.getObject(callbackId); + callback(); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModuley_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuley_y = function() { + instance.exports.invoke_swift_closure_TestModule_10TestModuley_y(boxPtr); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuley_y); + } + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_AsyncBox_asyncStaticRoundTrip_static"] = function bjs_AsyncBox_asyncStaticRoundTrip_static(resolveRef, rejectRef, v) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + imports.AsyncBox.asyncStaticRoundTrip(v).then(resolve, reject); + } + TestModule["bjs_AsyncBox_asyncStaticVoid_static"] = function bjs_AsyncBox_asyncStaticVoid_static(resolveRef, rejectRef) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + imports.AsyncBox.asyncStaticVoid().then(resolve, reject); + } + }, + 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const exports = { + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 180567ed1..867d0e835 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -4,6 +4,7 @@ /// by the BridgeJS system. import _CJavaScriptKit +import _Concurrency #if !arch(wasm32) @usableFromInline func _onlyAvailableOnWasm() -> Never { @@ -2083,3 +2084,91 @@ extension _BridgedAsOptional { Wrapped.bridgeJSStackPushAsOptional(asOptional) } } + +// MARK: Async Promise Awaiting + +/// Protocol for type-erasing `JSTypedClosure` in `_bjs_awaitPromise`. +/// +/// The library cannot name concrete `JSTypedClosure<(Int) -> Void>` etc. because +/// those require per-module generated convenience inits. This protocol provides +/// access to the underlying JS object ref and cleanup. +@_spi(BridgeJS) public protocol _BridgeJSReleasableClosure { + var jsObject: JSObject { get } + func release() +} + +@_spi(BridgeJS) extension JSTypedClosure: _BridgeJSReleasableClosure {} + +/// Awaits a JavaScript Promise using typed resolve/reject `JSTypedClosure` callbacks. +/// +/// The closure factories are dependency-injected because this library cannot +/// reference per-module generated `make_swift_closure_*` externs. The generated +/// code passes `{ JSTypedClosure<(T) -> Void>($0) }` which uses the per-module +/// convenience init. +/// +/// - Parameters: +/// - makeResolveClosure: A factory that wraps a `(T) -> Void` Swift closure +/// into a typed `JSTypedClosure`, creating the corresponding JS function. +/// - makeRejectClosure: A factory that wraps a `(JSValue) -> Void` Swift closure +/// into a `JSTypedClosure`, for the rejection path. +/// - body: A closure that receives the resolve and reject JS object refs +/// (as `Int32`) and should pass them to the appropriate JS extern function. +/// - Returns: The resolved value of type `T` from the Promise. +/// - Throws: `JSException` if the Promise rejects. +@_spi(BridgeJS) public func _bjs_awaitPromise( + makeResolveClosure: (@escaping (sending T) -> Void) -> R, + makeRejectClosure: (@escaping (sending JSValue) -> Void) -> E, + _ body: (_ resolveRef: Int32, _ rejectRef: Int32) -> Void +) async throws(JSException) -> T { + var resolveClosure: R? + var rejectClosure: E? + let result: Result = await withCheckedContinuation { continuation in + let resolve = makeResolveClosure { value in + continuation.resume(returning: .success(value)) + } + let reject = makeRejectClosure { value in + continuation.resume(returning: .failure(JSException(value))) + } + resolveClosure = resolve + rejectClosure = reject + body( + Int32(bitPattern: resolve.jsObject.id), + Int32(bitPattern: reject.jsObject.id) + ) + } + resolveClosure?.release() + rejectClosure?.release() + return try result.get() +} + +/// Void-returning overload of `_bjs_awaitPromise`. +/// +/// Needed because `(Void) -> Void` is not the same as `() -> Void` in Swift (SE-0110), +/// so the generic overload cannot handle void returns. +@_spi(BridgeJS) public func _bjs_awaitPromise( + makeResolveClosure: (@escaping () -> Void) -> R, + makeRejectClosure: (@escaping (sending JSValue) -> Void) -> E, + _ body: (_ resolveRef: Int32, _ rejectRef: Int32) -> Void +) async throws(JSException) { + var resolveClosure: R? + var rejectClosure: E? + let error: JSException? = await withCheckedContinuation { continuation in + let resolve = makeResolveClosure { + continuation.resume(returning: nil) + } + let reject = makeRejectClosure { value in + continuation.resume(returning: JSException(value)) + } + resolveClosure = resolve + rejectClosure = reject + body( + Int32(bitPattern: resolve.jsObject.id), + Int32(bitPattern: reject.jsObject.id) + ) + } + resolveClosure?.release() + rejectClosure?.release() + if let error { + throw error + } +} diff --git a/Tests/BridgeJSRuntimeTests/AsyncImportTests.swift b/Tests/BridgeJSRuntimeTests/AsyncImportTests.swift new file mode 100644 index 000000000..041f251f4 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/AsyncImportTests.swift @@ -0,0 +1,85 @@ +import Testing +import JavaScriptKit + +@JSClass struct AsyncImportImports { + @JSFunction static func jsAsyncRoundTripVoid() async throws(JSException) + @JSFunction static func jsAsyncRoundTripNumber(_ v: Double) async throws(JSException) -> Double + @JSFunction static func jsAsyncRoundTripBool(_ v: Bool) async throws(JSException) -> Bool + @JSFunction static func jsAsyncRoundTripString(_ v: String) async throws(JSException) -> String + @JSFunction static func jsAsyncRoundTripOptionalString(_ v: String?) async throws(JSException) -> String? + @JSFunction static func jsAsyncRoundTripOptionalNumber(_ v: Double?) async throws(JSException) -> Double? + @JSFunction static func jsAsyncRoundTripBoolArray(_ values: [Bool]) async throws(JSException) -> [Bool] + @JSFunction static func jsAsyncRoundTripIntArray(_ values: [Double]) async throws(JSException) -> [Double] + @JSFunction static func jsAsyncRoundTripStringArray(_ values: [String]) async throws(JSException) -> [String] + @JSFunction static func jsAsyncRoundTripFeatureFlag(_ v: FeatureFlag) async throws(JSException) -> FeatureFlag +} + +@Suite struct AsyncImportTests { + @Test func asyncRoundTripVoid() async throws { + try await AsyncImportImports.jsAsyncRoundTripVoid() + } + + @Test(arguments: [0.0, 1.0, -1.0, Double.pi, Double.infinity]) + func asyncRoundTripNumber(v: Double) async throws { + try #expect(await AsyncImportImports.jsAsyncRoundTripNumber(v) == v) + } + + @Test(arguments: [true, false]) + func asyncRoundTripBool(v: Bool) async throws { + try #expect(await AsyncImportImports.jsAsyncRoundTripBool(v) == v) + } + + @Test(arguments: ["", "Hello, world!", "🧑‍🧑‍🧒"]) + func asyncRoundTripString(v: String) async throws { + try #expect(await AsyncImportImports.jsAsyncRoundTripString(v) == v) + } + + // MARK: - Stack ABI types + + @Test(arguments: ["hello" as String?, nil, "🧑‍🧑‍🧒" as String?]) + func asyncRoundTripOptionalString(v: String?) async throws { + try #expect(await AsyncImportImports.jsAsyncRoundTripOptionalString(v) == v) + } + + @Test(arguments: [42.0 as Double?, nil, 0.0 as Double?]) + func asyncRoundTripOptionalNumber(v: Double?) async throws { + try #expect(await AsyncImportImports.jsAsyncRoundTripOptionalNumber(v) == v) + } + + @Test func asyncRoundTripBoolArray() async throws { + let values: [Bool] = [true, false, true] + try #expect(await AsyncImportImports.jsAsyncRoundTripBoolArray(values) == values) + try #expect(await AsyncImportImports.jsAsyncRoundTripBoolArray([]) == []) + } + + @Test func asyncRoundTripIntArray() async throws { + let values: [Double] = [1, 2, 3, 4, 5] + try #expect(await AsyncImportImports.jsAsyncRoundTripIntArray(values) == values) + try #expect(await AsyncImportImports.jsAsyncRoundTripIntArray([]) == []) + } + + @Test func asyncRoundTripStringArray() async throws { + let values = ["Hello", "World", "🎉"] + try #expect(await AsyncImportImports.jsAsyncRoundTripStringArray(values) == values) + try #expect(await AsyncImportImports.jsAsyncRoundTripStringArray([]) == []) + } + + @Test(arguments: [FeatureFlag.foo, .bar]) + func asyncRoundTripFeatureFlag(v: FeatureFlag) async throws { + try #expect(await AsyncImportImports.jsAsyncRoundTripFeatureFlag(v) == v) + } + + // MARK: - Structured return type + + @Test func fetchWeatherData() async throws { + let weather = try await BridgeJSRuntimeTests.fetchWeatherData("London") + #expect(try weather.temperature == 15.5) + #expect(try weather.description == "Cloudy") + #expect(try weather.humidity == 80) + + let weather2 = try await BridgeJSRuntimeTests.fetchWeatherData("Tokyo") + #expect(try weather2.temperature == 25.0) + #expect(try weather2.description == "Sunny") + #expect(try weather2.humidity == 40) + } +} diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 171d0dd3a..3db9497fc 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -1301,6 +1301,6 @@ class ExportAPITests: XCTestCase { } func testAllAsync() async throws { - _ = try await runAsyncWorks().value() + try await runAsyncWorks() } } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift index ac9ad0bc6..e3a6eec61 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift @@ -41,7 +41,18 @@ extension FeatureFlag: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum {} @JSFunction func changeName(_ name: String) throws(JSException) -> Void } -@JSFunction func runAsyncWorks() throws(JSException) -> JSPromise +@JSFunction func runAsyncWorks() async throws(JSException) -> Void + +@JSFunction func fetchWeatherData(_ city: String) async throws(JSException) -> WeatherData + +@JSClass struct WeatherData { + @JSGetter var temperature: Double + @JSSetter func setTemperature(_ value: Double) throws(JSException) + @JSGetter var description: String + @JSSetter func setDescription(_ value: String) throws(JSException) + @JSGetter var humidity: Double + @JSSetter func setHumidity(_ value: Double) throws(JSException) +} @JSFunction(jsName: "$jsWeirdFunction") func _jsWeirdFunction() throws(JSException) -> Double diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index b54106be9..71e5ef537 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -1674,6 +1674,680 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqS #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestss11FeatureFlagO_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending FeatureFlag) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y(callbackValue, param0Bytes, param0Length) + } + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending FeatureFlag) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending FeatureFlag) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11FeatureFlagO_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending FeatureFlag) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(FeatureFlag.bridgeJSLiftParameter(param0Bytes, param0Length)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestss11WeatherDataC_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending WeatherData) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending WeatherData) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending WeatherData) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11WeatherDataC_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending WeatherData) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(WeatherData.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y_extern(callback, param0Kind, param0Payload1, param0Payload2) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestss7JSValueV_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending JSValue) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0Kind, param0Payload1, param0Payload2) = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y(callbackValue, param0Kind, param0Payload1, param0Payload2) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending JSValue) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending JSValue) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending JSValue) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSValue.bridgeJSLiftParameter(param0Kind, param0Payload1, param0Payload2)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSS_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending String) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y(callbackValue, param0Bytes, param0Length) + } + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending String) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending String) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending String) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y(_ callback: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSaSS_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending [String]) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let _ = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y(callbackValue) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending [String]) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending [String]) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSS_y(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending [String]) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure([String].bridgeJSLiftParameter()) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y(_ callback: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSaSb_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending [Bool]) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let _ = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y(callbackValue) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending [Bool]) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending [Bool]) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSb_y(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending [Bool]) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure([Bool].bridgeJSLiftParameter()) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y(_ callback: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSaSd_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending [Double]) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let _ = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y(callbackValue) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending [Double]) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending [Double]) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSaSd_y(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending [Double]) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure([Double].bridgeJSLiftParameter()) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSb_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Bool) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Bool) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Bool) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSb_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Bool) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Bool.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y_extern(_ callback: Int32, _ param0: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y(_ callback: Int32, _ param0: Float64) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSd_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Double) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Double) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Double) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Double) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Double.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y_extern(callback, param0IsSome, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSqSS_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Optional) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0IsSome, param0Bytes, param0Length) in + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y(callbackValue, param0IsSome, param0Bytes, param0Length) + } + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Optional) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Optional) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Optional) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Bytes, param0Length)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Float64) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Float64) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y_extern(callback, param0IsSome, param0Value) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSqSd_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Optional) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y(callbackValue, param0IsSome, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Optional) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Optional) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSd_y(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Optional) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsy_13DataProcessorP_extern(_ callback: Int32) -> Int32 @@ -10489,6 +11163,247 @@ func _$ArraySupportImports_runJsArraySupportTests() throws(JSException) -> Void } } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripVoid_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripVoid_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripVoid_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripVoid_static(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripVoid_static_extern(resolveRef, rejectRef) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripNumber_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripNumber_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripNumber_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripNumber_static(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Float64) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripNumber_static_extern(resolveRef, rejectRef, v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripBool_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripBool_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripBool_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripBool_static(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripBool_static_extern(resolveRef, rejectRef, v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripString_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripString_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripString_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripString_static(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripString_static_extern(resolveRef, rejectRef, vBytes, vLength) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripOptionalString_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalString_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalString_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalString_static(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripOptionalString_static_extern(resolveRef, rejectRef, vIsSome, vBytes, vLength) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripOptionalNumber_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalNumber_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vValue: Float64) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalNumber_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalNumber_static(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vValue: Float64) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripOptionalNumber_static_extern(resolveRef, rejectRef, vIsSome, vValue) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripBoolArray_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripBoolArray_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripBoolArray_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripBoolArray_static(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripBoolArray_static_extern(resolveRef, rejectRef) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripIntArray_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripIntArray_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripIntArray_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripIntArray_static(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripIntArray_static_extern(resolveRef, rejectRef) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripStringArray_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripStringArray_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripStringArray_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripStringArray_static(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripStringArray_static_extern(resolveRef, rejectRef) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static(_ resolveRef: Int32, _ rejectRef: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static_extern(resolveRef, rejectRef, vBytes, vLength) +} + +func _$AsyncImportImports_jsAsyncRoundTripVoid() async throws(JSException) -> Void { + try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<() -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + bjs_AsyncImportImports_jsAsyncRoundTripVoid_static(resolveRef, rejectRef) + } +} + +func _$AsyncImportImports_jsAsyncRoundTripNumber(_ v: Double) async throws(JSException) -> Double { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Double) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vValue = v.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripNumber_static(resolveRef, rejectRef, vValue) + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripBool(_ v: Bool) async throws(JSException) -> Bool { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Bool) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vValue = v.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripBool_static(resolveRef, rejectRef, vValue) + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripString(_ v: String) async throws(JSException) -> String { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending String) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + v.bridgeJSWithLoweredParameter { (vBytes, vLength) in + bjs_AsyncImportImports_jsAsyncRoundTripString_static(resolveRef, rejectRef, vBytes, vLength) + } + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripOptionalString(_ v: Optional) async throws(JSException) -> Optional { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Optional) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + v.bridgeJSWithLoweredParameter { (vIsSome, vBytes, vLength) in + bjs_AsyncImportImports_jsAsyncRoundTripOptionalString_static(resolveRef, rejectRef, vIsSome, vBytes, vLength) + } + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripOptionalNumber(_ v: Optional) async throws(JSException) -> Optional { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Optional) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let (vIsSome, vValue) = v.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripOptionalNumber_static(resolveRef, rejectRef, vIsSome, vValue) + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripBoolArray(_ values: [Bool]) async throws(JSException) -> [Bool] { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending [Bool]) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let _ = values.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripBoolArray_static(resolveRef, rejectRef) + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripIntArray(_ values: [Double]) async throws(JSException) -> [Double] { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending [Double]) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let _ = values.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripIntArray_static(resolveRef, rejectRef) + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripStringArray(_ values: [String]) async throws(JSException) -> [String] { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending [String]) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let _ = values.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripStringArray_static(resolveRef, rejectRef) + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripFeatureFlag(_ v: FeatureFlag) async throws(JSException) -> FeatureFlag { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending FeatureFlag) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + v.bridgeJSWithLoweredParameter { (vBytes, vLength) in + bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static(resolveRef, rejectRef, vBytes, vLength) + } + } + return resolved +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ClosureSupportImports_jsApplyVoid_static") fileprivate func bjs_ClosureSupportImports_jsApplyVoid_static_extern(_ callback: Int32) -> Void @@ -11296,22 +12211,49 @@ func _$jsRoundTripFeatureFlag(_ flag: FeatureFlag) throws(JSException) -> Featur #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_runAsyncWorks") -fileprivate func bjs_runAsyncWorks_extern() -> Int32 +fileprivate func bjs_runAsyncWorks_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void #else -fileprivate func bjs_runAsyncWorks_extern() -> Int32 { +fileprivate func bjs_runAsyncWorks_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_runAsyncWorks() -> Int32 { - return bjs_runAsyncWorks_extern() +@inline(never) fileprivate func bjs_runAsyncWorks(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_runAsyncWorks_extern(resolveRef, rejectRef) } -func _$runAsyncWorks() throws(JSException) -> JSPromise { - let ret = bjs_runAsyncWorks() - if let error = _swift_js_take_exception() { - throw error +func _$runAsyncWorks() async throws(JSException) -> Void { + try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<() -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + bjs_runAsyncWorks(resolveRef, rejectRef) } - return JSPromise.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_fetchWeatherData") +fileprivate func bjs_fetchWeatherData_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ cityBytes: Int32, _ cityLength: Int32) -> Void +#else +fileprivate func bjs_fetchWeatherData_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ cityBytes: Int32, _ cityLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_fetchWeatherData(_ resolveRef: Int32, _ rejectRef: Int32, _ cityBytes: Int32, _ cityLength: Int32) -> Void { + return bjs_fetchWeatherData_extern(resolveRef, rejectRef, cityBytes, cityLength) +} + +func _$fetchWeatherData(_ city: String) async throws(JSException) -> WeatherData { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending WeatherData) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + city.bridgeJSWithLoweredParameter { (cityBytes, cityLength) in + bjs_fetchWeatherData(resolveRef, rejectRef, cityBytes, cityLength) + } + } + return resolved } #if arch(wasm32) @@ -11492,6 +12434,133 @@ func _$JsGreeter_changeName(_ self: JSObject, _ name: String) throws(JSException } } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_WeatherData_temperature_get") +fileprivate func bjs_WeatherData_temperature_get_extern(_ self: Int32) -> Float64 +#else +fileprivate func bjs_WeatherData_temperature_get_extern(_ self: Int32) -> Float64 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WeatherData_temperature_get(_ self: Int32) -> Float64 { + return bjs_WeatherData_temperature_get_extern(self) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_WeatherData_description_get") +fileprivate func bjs_WeatherData_description_get_extern(_ self: Int32) -> Int32 +#else +fileprivate func bjs_WeatherData_description_get_extern(_ self: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WeatherData_description_get(_ self: Int32) -> Int32 { + return bjs_WeatherData_description_get_extern(self) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_WeatherData_humidity_get") +fileprivate func bjs_WeatherData_humidity_get_extern(_ self: Int32) -> Float64 +#else +fileprivate func bjs_WeatherData_humidity_get_extern(_ self: Int32) -> Float64 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WeatherData_humidity_get(_ self: Int32) -> Float64 { + return bjs_WeatherData_humidity_get_extern(self) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_WeatherData_temperature_set") +fileprivate func bjs_WeatherData_temperature_set_extern(_ self: Int32, _ newValue: Float64) -> Void +#else +fileprivate func bjs_WeatherData_temperature_set_extern(_ self: Int32, _ newValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WeatherData_temperature_set(_ self: Int32, _ newValue: Float64) -> Void { + return bjs_WeatherData_temperature_set_extern(self, newValue) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_WeatherData_description_set") +fileprivate func bjs_WeatherData_description_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void +#else +fileprivate func bjs_WeatherData_description_set_extern(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WeatherData_description_set(_ self: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void { + return bjs_WeatherData_description_set_extern(self, newValueBytes, newValueLength) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_WeatherData_humidity_set") +fileprivate func bjs_WeatherData_humidity_set_extern(_ self: Int32, _ newValue: Float64) -> Void +#else +fileprivate func bjs_WeatherData_humidity_set_extern(_ self: Int32, _ newValue: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WeatherData_humidity_set(_ self: Int32, _ newValue: Float64) -> Void { + return bjs_WeatherData_humidity_set_extern(self, newValue) +} + +func _$WeatherData_temperature_get(_ self: JSObject) throws(JSException) -> Double { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_WeatherData_temperature_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Double.bridgeJSLiftReturn(ret) +} + +func _$WeatherData_description_get(_ self: JSObject) throws(JSException) -> String { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_WeatherData_description_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return String.bridgeJSLiftReturn(ret) +} + +func _$WeatherData_humidity_get(_ self: JSObject) throws(JSException) -> Double { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_WeatherData_humidity_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Double.bridgeJSLiftReturn(ret) +} + +func _$WeatherData_temperature_set(_ self: JSObject, _ newValue: Double) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let newValueValue = newValue.bridgeJSLowerParameter() + bjs_WeatherData_temperature_set(selfValue, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WeatherData_description_set(_ self: JSObject, _ newValue: String) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + newValue.bridgeJSWithLoweredParameter { (newValueBytes, newValueLength) in + bjs_WeatherData_description_set(selfValue, newValueBytes, newValueLength) + } + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$WeatherData_humidity_set(_ self: JSObject, _ newValue: Double) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let newValueValue = newValue.bridgeJSLowerParameter() + bjs_WeatherData_humidity_set(selfValue, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs__WeirdClass_init") fileprivate func bjs__WeirdClass_init_extern() -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 842bcff24..60b02020d 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -49,7 +49,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -97,7 +98,8 @@ "double" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -145,7 +147,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -202,7 +205,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -250,7 +254,8 @@ "double" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -298,7 +303,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -591,7 +597,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -641,7 +648,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -684,7 +692,8 @@ "swiftHeapObject" : { "_0" : "Greeter" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -724,7 +733,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -2931,7 +2941,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3017,7 +3028,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3059,7 +3071,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3100,7 +3113,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3151,7 +3165,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3199,7 +3214,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3246,7 +3262,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3282,7 +3299,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3318,7 +3336,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3362,7 +3381,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3409,7 +3429,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3455,7 +3476,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3497,7 +3519,8 @@ "bool" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3533,7 +3556,8 @@ "bool" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3572,7 +3596,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3607,7 +3632,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3648,7 +3674,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3697,7 +3724,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3745,7 +3773,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3792,7 +3821,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3828,7 +3858,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3866,7 +3897,8 @@ "swiftProtocol" : { "_0" : "DataProcessor" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3902,7 +3934,8 @@ "swiftProtocol" : { "_0" : "DataProcessor" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3927,7 +3960,8 @@ "swiftProtocol" : { "_0" : "DataProcessor" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -3968,7 +4002,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -10604,7 +10639,8 @@ }, "_1" : "null" } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -13606,7 +13642,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -13656,7 +13693,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -13708,7 +13746,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } @@ -16372,6 +16411,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsIntArrayLength", "parameters" : [ { @@ -16400,6 +16444,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripIntArray", "parameters" : [ { @@ -16432,6 +16481,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripNumberArray", "parameters" : [ { @@ -16458,6 +16512,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripStringArray", "parameters" : [ { @@ -16484,6 +16543,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripBoolArray", "parameters" : [ { @@ -16510,6 +16574,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripJSValueArray", "parameters" : [ { @@ -16536,6 +16605,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripJSObjectArray", "parameters" : [ { @@ -16562,6 +16636,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripJSClassArray", "parameters" : [ { @@ -16588,6 +16667,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalIntArray", "parameters" : [ { @@ -16630,6 +16714,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalStringArray", "parameters" : [ { @@ -16666,6 +16755,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalBoolArray", "parameters" : [ { @@ -16702,6 +16796,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalJSValueArray", "parameters" : [ { @@ -16738,6 +16837,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalJSObjectArray", "parameters" : [ { @@ -16774,6 +16878,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalJSClassArray", "parameters" : [ { @@ -16810,6 +16919,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsSumNumberArray", "parameters" : [ { @@ -16832,6 +16946,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsCreateNumberArray", "parameters" : [ @@ -16847,6 +16966,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "runJsArraySupportTests", "parameters" : [ @@ -16873,36 +16997,20 @@ "methods" : [ ], - "name" : "ClosureSupportImports", + "name" : "AsyncImportImports", "setters" : [ ], "staticMethods" : [ { - "name" : "jsApplyVoid", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripVoid", "parameters" : [ - { - "name" : "callback", - "type" : { - "closure" : { - "_0" : { - "isAsync" : false, - "isThrows" : false, - "mangleName" : "20BridgeJSRuntimeTestsy_y", - "moduleName" : "BridgeJSRuntimeTests", - "parameters" : [ - - ], - "returnType" : { - "void" : { - } - } - }, - "useJSTypedClosure" : true - } - } - } ], "returnType" : { "void" : { @@ -16911,139 +17019,474 @@ } }, { - "name" : "jsApplyBool", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripNumber", "parameters" : [ { - "name" : "callback", + "name" : "v", "type" : { - "closure" : { - "_0" : { - "isAsync" : false, - "isThrows" : false, - "mangleName" : "20BridgeJSRuntimeTestsy_Sb", - "moduleName" : "BridgeJSRuntimeTests", - "parameters" : [ - - ], - "returnType" : { - "bool" : { + "double" : { - } - } - }, - "useJSTypedClosure" : true } } } ], "returnType" : { - "bool" : { + "double" : { } } }, { - "name" : "jsApplyInt", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripBool", "parameters" : [ { - "name" : "value", - "type" : { - "integer" : { - "_0" : { - "isSigned" : true, - "width" : "word" - } - } - } - }, - { - "name" : "transform", + "name" : "v", "type" : { - "closure" : { - "_0" : { - "isAsync" : false, - "isThrows" : false, - "mangleName" : "20BridgeJSRuntimeTestsSi_Si", - "moduleName" : "BridgeJSRuntimeTests", - "parameters" : [ - { - "integer" : { - "_0" : { - "isSigned" : true, - "width" : "word" - } - } - } - ], - "returnType" : { - "integer" : { - "_0" : { - "isSigned" : true, - "width" : "word" - } - } - } - }, - "useJSTypedClosure" : true + "bool" : { + } } } ], "returnType" : { - "integer" : { - "_0" : { - "isSigned" : true, - "width" : "word" - } + "bool" : { + } } }, { - "name" : "jsApplyDouble", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripString", "parameters" : [ { - "name" : "value", + "name" : "v", "type" : { - "double" : { + "string" : { } } - }, + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripOptionalString", + "parameters" : [ { - "name" : "transform", + "name" : "v", "type" : { - "closure" : { + "nullable" : { "_0" : { - "isAsync" : false, - "isThrows" : false, - "mangleName" : "20BridgeJSRuntimeTestsSd_Sd", - "moduleName" : "BridgeJSRuntimeTests", - "parameters" : [ - { - "double" : { - - } - } - ], - "returnType" : { - "double" : { + "string" : { - } } }, - "useJSTypedClosure" : true + "_1" : "null" } } } ], "returnType" : { - "double" : { + "nullable" : { + "_0" : { + "string" : { + } + }, + "_1" : "null" } } }, { - "name" : "jsApplyString", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripOptionalNumber", + "parameters" : [ + { + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "double" : { + + } + }, + "_1" : "null" + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripBoolArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "array" : { + "_0" : { + "bool" : { + + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "bool" : { + + } + } + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripIntArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "array" : { + "_0" : { + "double" : { + + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "double" : { + + } + } + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripStringArray", + "parameters" : [ + { + "name" : "values", + "type" : { + "array" : { + "_0" : { + "string" : { + + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "string" : { + + } + } + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripFeatureFlag", + "parameters" : [ + { + "name" : "v", + "type" : { + "rawValueEnum" : { + "_0" : "FeatureFlag", + "_1" : "String" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "FeatureFlag", + "_1" : "String" + } + } + } + ] + } + ] + }, + { + "functions" : [ + + ], + "types" : [ + { + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "ClosureSupportImports", + "setters" : [ + + ], + "staticMethods" : [ + { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsApplyVoid", + "parameters" : [ + { + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsy_y", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsApplyBool", + "parameters" : [ + { + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsy_Sb", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + + ], + "returnType" : { + "bool" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "bool" : { + + } + } + }, + { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsApplyInt", + "parameters" : [ + { + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsSi_Si", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsApplyDouble", + "parameters" : [ + { + "name" : "value", + "type" : { + "double" : { + + } + } + }, + { + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsSd_Sd", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "double" : { + + } + } + ], + "returnType" : { + "double" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "double" : { + + } + } + }, + { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsApplyString", "parameters" : [ { "name" : "value", @@ -17073,7 +17516,8 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17087,6 +17531,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsApplyJSObject", "parameters" : [ { @@ -17117,7 +17566,8 @@ "jsObject" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17131,6 +17581,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsMakeIntToInt", "parameters" : [ { @@ -17169,13 +17624,19 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsMakeDoubleToDouble", "parameters" : [ { @@ -17205,13 +17666,19 @@ "double" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsMakeStringToString", "parameters" : [ { @@ -17241,13 +17708,19 @@ "string" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : false } } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsCallTwice", "parameters" : [ { @@ -17284,7 +17757,8 @@ "void" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17301,6 +17775,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsCallBinary", "parameters" : [ { @@ -17337,7 +17816,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17354,6 +17834,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsCallTriple", "parameters" : [ { @@ -17398,7 +17883,8 @@ "width" : "word" } } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17415,6 +17901,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsCallAfterRelease", "parameters" : [ { @@ -17433,7 +17924,8 @@ "void" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17447,6 +17939,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsOptionalInvoke", "parameters" : [ { @@ -17467,7 +17964,8 @@ "bool" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17484,6 +17982,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsStoreClosure", "parameters" : [ { @@ -17502,7 +18005,8 @@ "void" : { } - } + }, + "sendingParameters" : false }, "useJSTypedClosure" : true } @@ -17516,6 +18020,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsCallStoredClosure", "parameters" : [ @@ -17527,6 +18036,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsHeapCount", "parameters" : [ @@ -17541,6 +18055,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "runJsClosureSupportTests", "parameters" : [ @@ -17573,6 +18092,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "runJsDefaultArgumentTests", "parameters" : [ @@ -17605,6 +18129,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripDictionaryInt", "parameters" : [ { @@ -17637,6 +18166,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripDictionaryBool", "parameters" : [ { @@ -17663,6 +18197,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripDictionaryDouble", "parameters" : [ { @@ -17689,6 +18228,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripDictionaryJSObject", "parameters" : [ { @@ -17715,6 +18259,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripDictionaryJSValue", "parameters" : [ { @@ -17741,6 +18290,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripDictionaryDoubleArray", "parameters" : [ { @@ -17822,6 +18376,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripVoid", "parameters" : [ @@ -17833,6 +18392,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripNumber", "parameters" : [ { @@ -17851,6 +18415,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripBool", "parameters" : [ { @@ -17869,6 +18438,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripString", "parameters" : [ { @@ -17887,6 +18461,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripJSValue", "parameters" : [ { @@ -17905,6 +18484,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsThrowOrVoid", "parameters" : [ { @@ -17923,6 +18507,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsThrowOrNumber", "parameters" : [ { @@ -17941,6 +18530,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsThrowOrBool", "parameters" : [ { @@ -17959,6 +18553,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsThrowOrString", "parameters" : [ { @@ -17977,6 +18576,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripFeatureFlag", "parameters" : [ { @@ -17997,17 +18601,50 @@ } }, { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, "name" : "runAsyncWorks", "parameters" : [ + ], + "returnType" : { + "void" : { + + } + } + }, + { + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "fetchWeatherData", + "parameters" : [ + { + "name" : "city", + "type" : { + "string" : { + + } + } + } ], "returnType" : { "jsObject" : { - "_0" : "JSPromise" + "_0" : "WeatherData" } } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "jsName" : "$jsWeirdFunction", "name" : "_jsWeirdFunction", "parameters" : [ @@ -18020,6 +18657,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "from" : "global", "name" : "parseInt", "parameters" : [ @@ -18092,6 +18734,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "greet", "parameters" : [ @@ -18103,6 +18750,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "changeName", "parameters" : [ { @@ -18137,6 +18789,70 @@ ] }, + { + "getters" : [ + { + "name" : "temperature", + "type" : { + "double" : { + + } + } + }, + { + "name" : "description", + "type" : { + "string" : { + + } + } + }, + { + "name" : "humidity", + "type" : { + "double" : { + + } + } + } + ], + "methods" : [ + + ], + "name" : "WeatherData", + "setters" : [ + { + "functionName" : "temperature_set", + "name" : "temperature", + "type" : { + "double" : { + + } + } + }, + { + "functionName" : "description_set", + "name" : "description", + "type" : { + "string" : { + + } + } + }, + { + "functionName" : "humidity_set", + "name" : "humidity", + "type" : { + "double" : { + + } + } + } + ], + "staticMethods" : [ + + ] + }, { "constructor" : { "parameters" : [ @@ -18149,6 +18865,11 @@ "jsName" : "$WeirdClass", "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "jsName" : "method-with-dashes", "name" : "method_with_dashes", "parameters" : [ @@ -18187,6 +18908,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "value", "parameters" : [ @@ -18204,6 +18930,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "create", "parameters" : [ { @@ -18222,6 +18953,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "value", "parameters" : [ @@ -18233,6 +18969,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "makeDefault", "parameters" : [ @@ -18244,6 +18985,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "jsName" : "with-dashes", "name" : "with_dashes", "parameters" : [ @@ -18315,6 +19061,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "bark", "parameters" : [ @@ -18326,6 +19077,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "getIsCat", "parameters" : [ @@ -18376,6 +19132,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsTranslatePoint", "parameters" : [ { @@ -18438,6 +19199,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripInt", "parameters" : [ { @@ -18462,6 +19228,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripUInt", "parameters" : [ { @@ -18486,6 +19257,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripInt8", "parameters" : [ { @@ -18510,6 +19286,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripUInt8", "parameters" : [ { @@ -18534,6 +19315,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripInt16", "parameters" : [ { @@ -18558,6 +19344,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripUInt16", "parameters" : [ { @@ -18582,6 +19373,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripInt32", "parameters" : [ { @@ -18606,6 +19402,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripUInt32", "parameters" : [ { @@ -18630,6 +19431,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripInt64", "parameters" : [ { @@ -18654,6 +19460,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripUInt64", "parameters" : [ { @@ -18678,6 +19489,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "runJsIntegerTypesSupportTests", "parameters" : [ @@ -18760,6 +19576,11 @@ ], "methods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "concatNumbers", "parameters" : [ { @@ -18792,6 +19613,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "concatLabels", "parameters" : [ { @@ -18818,6 +19644,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "firstLabel", "parameters" : [ { @@ -18889,6 +19720,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "makeJSClassWithArrayMembers", "parameters" : [ { @@ -19002,6 +19838,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsFunctionWithPackageAccess", "parameters" : [ @@ -19013,6 +19854,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsFunctionWithPublicAccess", "parameters" : [ @@ -19024,6 +19870,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsFunctionWithInternalAccess", "parameters" : [ @@ -19035,6 +19886,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsFunctionWithFilePrivateAccess", "parameters" : [ @@ -19046,6 +19902,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsFunctionWithPrivateAccess", "parameters" : [ @@ -19079,6 +19940,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalNumberNull", "parameters" : [ { @@ -19113,6 +19979,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalNumberUndefined", "parameters" : [ { @@ -19147,6 +20018,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalStringNull", "parameters" : [ { @@ -19175,6 +20051,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalStringUndefined", "parameters" : [ { @@ -19203,6 +20084,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalJSValueArrayNull", "parameters" : [ { @@ -19239,6 +20125,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalJSValueArrayUndefined", "parameters" : [ { @@ -19275,6 +20166,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalStringToStringDictionaryNull", "parameters" : [ { @@ -19311,6 +20207,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalStringToStringDictionaryUndefined", "parameters" : [ { @@ -19347,6 +20248,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "runJsOptionalSupportTests", "parameters" : [ @@ -19364,6 +20270,11 @@ { "functions" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "from" : "global", "name" : "gc", "parameters" : [ @@ -19390,6 +20301,11 @@ ], "staticMethods" : [ { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripGreeter", "parameters" : [ { @@ -19408,6 +20324,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripUUID", "parameters" : [ { @@ -19426,6 +20347,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsRoundTripOptionalGreeter", "parameters" : [ { @@ -19454,6 +20380,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsConsumeLeakCheck", "parameters" : [ { @@ -19472,6 +20403,11 @@ } }, { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, "name" : "jsConsumeOptionalLeakCheck", "parameters" : [ { diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs new file mode 100644 index 000000000..f64531d4a --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs @@ -0,0 +1,46 @@ +// @ts-check + +import assert from 'node:assert'; + +/** + * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["AsyncImportImports"]} + */ +export function getImports(importsContext) { + return { + jsAsyncRoundTripVoid: () => { + return Promise.resolve(); + }, + jsAsyncRoundTripNumber: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripBool: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripString: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripOptionalString: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripOptionalNumber: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripBoolArray: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripIntArray: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripStringArray: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripFeatureFlag: (v) => { + return Promise.resolve(v); + }, + }; +} + +/** @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ +export async function runAsyncWorksTests(exports) { + await exports.asyncRoundTripVoid(); +} diff --git a/Tests/BridgeJSRuntimeTests/bridge-js.d.ts b/Tests/BridgeJSRuntimeTests/bridge-js.d.ts index e8533a3d8..9fef391c1 100644 --- a/Tests/BridgeJSRuntimeTests/bridge-js.d.ts +++ b/Tests/BridgeJSRuntimeTests/bridge-js.d.ts @@ -26,6 +26,13 @@ export class JsGreeter { export function runAsyncWorks(): Promise; +export interface WeatherData { + temperature: number; + description: string; + humidity: number; +} +export function fetchWeatherData(city: string): Promise; + // jsName tests export function $jsWeirdFunction(): number; diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 8eb9a0270..bb285aaee 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -13,6 +13,7 @@ import { getImports as getDictionarySupportImports } from './BridgeJSRuntimeTest import { getImports as getDefaultArgumentImports } from './BridgeJSRuntimeTests/JavaScript/DefaultArgumentTests.mjs'; import { getImports as getJSClassSupportImports, JSClassWithArrayMembers } from './BridgeJSRuntimeTests/JavaScript/JSClassSupportTests.mjs'; import { getImports as getIntegerTypesSupportImports } from './BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs'; +import { getImports as getAsyncImportImports, runAsyncWorksTests } from './BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs'; /** @type {import('../.build/plugins/PackageToJS/outputs/PackageTests/test.d.ts').SetupOptionsFn} */ export async function setupOptions(options, context) { @@ -124,9 +125,17 @@ export async function setupOptions(options, context) { if (!exports) { throw new Error("No exports!?"); } - BridgeJSRuntimeTests_runAsyncWorks(exports); + await runAsyncWorksTests(exports); return; }, + AsyncImportImports: getAsyncImportImports(importsContext), + fetchWeatherData: (city) => { + return Promise.resolve({ + temperature: city === "London" ? 15.5 : 25.0, + description: city === "London" ? "Cloudy" : "Sunny", + humidity: city === "London" ? 80 : 40, + }); + }, jsTranslatePoint: (point, dx, dy) => { return { x: (point.x | 0) + (dx | 0), y: (point.y | 0) + (dy | 0) }; }, @@ -1009,11 +1018,6 @@ function testStructSupport(exports) { assert.equal(fooContainerResult2.optionalFoo, null); } -/** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ -async function BridgeJSRuntimeTests_runAsyncWorks(exports) { - await exports.asyncRoundTripVoid(); -} - /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ function BridgeJSRuntimeTests_runJsStructWorks(exports) { testStructSupport(exports); From df32a66879cd5e1bbd12308d2fc248cf84fef5d3 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 2 Apr 2026 17:27:37 +0100 Subject: [PATCH 21/68] Add JSRemote (#711) Add `JSRemote` API for accessing JSObjects without transfer The new API allows creating a handle for a `JSObject` that remains on its original JavaScript thread and hopping back to that thread to access the object when needed. This is useful for cases where the object cannot be transferred to another thread, but occasional access is still required or when we want to guarantee that an object is always accessed on the same thread for safety (it should be statically guaranteed with strict Sendable checking, but modules with language mode 5 don't have that). Example: ```swift let document = JSObject.global.document.object! let remoteDocument = JSRemote(document) let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) let title = try await Task(executorPreference: executor) { try await remoteDocument.withJSObject { document in document.title.string ?? "" } }.value ``` --- Examples/ActorOnWebWorker/Package.swift | 2 +- Examples/Multithreading/Package.swift | 2 +- Examples/OffscrenCanvas/Package.swift | 2 +- Plugins/PackageToJS/Templates/runtime.d.ts | 6 + Plugins/PackageToJS/Templates/runtime.mjs | 80 +++++++-- Runtime/src/index.ts | 125 +++++++++++--- Runtime/src/itc.ts | 9 + Runtime/src/types.ts | 1 + Sources/JavaScriptEventLoop/JSRemote.swift | 155 ++++++++++++++++++ .../_CJavaScriptKit/include/_CJavaScriptKit.h | 5 + .../WebWorkerTaskExecutorTests.swift | 146 +++++++++++++++++ 11 files changed, 495 insertions(+), 38 deletions(-) create mode 100644 Sources/JavaScriptEventLoop/JSRemote.swift diff --git a/Examples/ActorOnWebWorker/Package.swift b/Examples/ActorOnWebWorker/Package.swift index 82e87dfdc..04441a9a3 100644 --- a/Examples/ActorOnWebWorker/Package.swift +++ b/Examples/ActorOnWebWorker/Package.swift @@ -6,7 +6,7 @@ let package = Package( name: "Example", platforms: [.macOS("15"), .iOS("18"), .watchOS("11"), .tvOS("18"), .visionOS("2")], dependencies: [ - .package(path: "../../") + .package(name: "JavaScriptKit", path: "../../") ], targets: [ .executableTarget( diff --git a/Examples/Multithreading/Package.swift b/Examples/Multithreading/Package.swift index 4d1ebde70..ca147c5d8 100644 --- a/Examples/Multithreading/Package.swift +++ b/Examples/Multithreading/Package.swift @@ -6,7 +6,7 @@ let package = Package( name: "Example", platforms: [.macOS("15"), .iOS("18"), .watchOS("11"), .tvOS("18"), .visionOS("2")], dependencies: [ - .package(path: "../../"), + .package(name: "JavaScriptKit", path: "../../"), .package( url: "https://github.com/kateinoigakukun/chibi-ray", revision: "c8cab621a3338dd2f8e817d3785362409d3b8cf1" diff --git a/Examples/OffscrenCanvas/Package.swift b/Examples/OffscrenCanvas/Package.swift index ca6d7357f..54fa57747 100644 --- a/Examples/OffscrenCanvas/Package.swift +++ b/Examples/OffscrenCanvas/Package.swift @@ -6,7 +6,7 @@ let package = Package( name: "Example", platforms: [.macOS("15"), .iOS("18"), .watchOS("11"), .tvOS("18"), .visionOS("2")], dependencies: [ - .package(path: "../../") + .package(name: "JavaScriptKit", path: "../../") ], targets: [ .executableTarget( diff --git a/Plugins/PackageToJS/Templates/runtime.d.ts b/Plugins/PackageToJS/Templates/runtime.d.ts index 353db3894..87cbeea72 100644 --- a/Plugins/PackageToJS/Templates/runtime.d.ts +++ b/Plugins/PackageToJS/Templates/runtime.d.ts @@ -97,6 +97,10 @@ declare class ITCInterface { sendingContext: pointer; transfer: Transferable[]; }; + invokeRemoteJSObjectBody(invocationContext: pointer): { + object: undefined; + transfer: Transferable[]; + }; release(objectRef: ref): { object: undefined; transfer: Transferable[]; @@ -140,6 +144,8 @@ type ResponseMessage = { sourceTid: number; /** The context pointer of the request */ context: pointer; + /** The request method this response corresponds to */ + requestMethod: keyof ITCInterface; /** The response content */ response: { ok: true; diff --git a/Plugins/PackageToJS/Templates/runtime.mjs b/Plugins/PackageToJS/Templates/runtime.mjs index d79275476..ab85e7893 100644 --- a/Plugins/PackageToJS/Templates/runtime.mjs +++ b/Plugins/PackageToJS/Templates/runtime.mjs @@ -135,6 +135,9 @@ class ITCInterface { const transfer = transferringObjects.map((ref) => this.memory.getObject(ref)); return { object: objects, sendingContext, transfer }; } + invokeRemoteJSObjectBody(invocationContext) { + return { object: undefined, transfer: [] }; + } release(objectRef) { this.memory.release(objectRef); return { object: undefined, transfer: [] }; @@ -455,13 +458,51 @@ class SwiftRuntime { if (broker) return broker; const itcInterface = new ITCInterface(this.memory); + const defaultRequestHandler = (message) => { + const request = message.data.request; + // @ts-ignore dynamic dispatch by method name + const result = itcInterface[request.method].apply(itcInterface, request.parameters); + return { ok: true, value: result }; + }; + const requestHandlers = { + invokeRemoteJSObjectBody: (message) => { + const invocationContext = message.data.request + .parameters[0]; + const hasError = this.exports.swjs_invoke_remote_jsobject_body(invocationContext); + return { + ok: true, + value: { + object: hasError, + sendingContext: message.data.context, + transfer: [], + }, + }; + }, + }; + const defaultResponseHandler = (message) => { + if (message.data.response.ok) { + const object = this.memory.retain(message.data.response.value.object); + this.exports.swjs_receive_response(object, message.data.context); + } + else { + const error = deserializeError(message.data.response.error); + const errorObject = this.memory.retain(error); + this.exports.swjs_receive_error(errorObject, message.data.context); + } + }; + const responseHandlers = { + invokeRemoteJSObjectBody: (_message) => { + // Swift continuation is resumed on the owner thread. + }, + }; const newBroker = new MessageBroker((_a = this.tid) !== null && _a !== void 0 ? _a : -1, threadChannel, { onRequest: (message) => { + var _a; let returnValue; try { - // @ts-ignore - const result = itcInterface[message.data.request.method](...message.data.request.parameters); - returnValue = { ok: true, value: result }; + const method = message.data.request.method; + const handler = (_a = requestHandlers[method]) !== null && _a !== void 0 ? _a : defaultRequestHandler; + returnValue = handler(message); } catch (error) { returnValue = { @@ -474,6 +515,7 @@ class SwiftRuntime { data: { sourceTid: message.data.sourceTid, context: message.data.context, + requestMethod: message.data.request.method, response: returnValue, }, }; @@ -489,15 +531,10 @@ class SwiftRuntime { } }, onResponse: (message) => { - if (message.data.response.ok) { - const object = this.memory.retain(message.data.response.value.object); - this.exports.swjs_receive_response(object, message.data.context); - } - else { - const error = deserializeError(message.data.response.error); - const errorObject = this.memory.retain(error); - this.exports.swjs_receive_error(errorObject, message.data.context); - } + var _a; + const method = message.data.requestMethod; + const handler = (_a = responseHandlers[method]) !== null && _a !== void 0 ? _a : defaultResponseHandler; + handler(message); }, }); broker = newBroker; @@ -842,6 +879,25 @@ class SwiftRuntime { }, }); }, + swjs_request_remote_jsobject_body: (object_source_tid, invocation_context) => { + var _a; + if (!this.options.threadChannel) { + throw new Error("threadChannel is not set in options given to SwiftRuntime. Please set it to request remote JSObject access."); + } + const broker = getMessageBroker(this.options.threadChannel); + broker.request({ + type: "request", + data: { + sourceTid: (_a = this.tid) !== null && _a !== void 0 ? _a : MAIN_THREAD_TID, + targetTid: object_source_tid, + context: invocation_context, + request: { + method: "invokeRemoteJSObjectBody", + parameters: [invocation_context], + }, + }, + }); + }, }; } postMessageToMainThread(message, transfer = []) { diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index 5d6fe258f..7d75a6801 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -11,6 +11,7 @@ import { deserializeError, MainToWorkerMessage, MessageBroker, + RequestMessage, ResponseMessage, ITCInterface, serializeError, @@ -265,29 +266,98 @@ export class SwiftRuntime { const getMessageBroker = (threadChannel: SwiftRuntimeThreadChannel) => { if (broker) return broker; const itcInterface = new ITCInterface(this.memory); + type ITCMethodName = keyof ITCInterface; + + const defaultRequestHandler = ( + message: RequestMessage, + ): ResponseMessage["data"]["response"] => { + const request = message.data.request; + // @ts-ignore dynamic dispatch by method name + const result = itcInterface[request.method].apply( + itcInterface, + request.parameters as any[], + ); + return { ok: true, value: result }; + }; + + const requestHandlers: Partial< + Record< + ITCMethodName, + ( + message: RequestMessage, + ) => ResponseMessage["data"]["response"] + > + > = { + invokeRemoteJSObjectBody: (message) => { + const invocationContext = message.data.request + .parameters[0] as pointer; + const hasError = + this.exports.swjs_invoke_remote_jsobject_body( + invocationContext, + ); + return { + ok: true, + value: { + object: hasError, + sendingContext: message.data.context, + transfer: [], + }, + }; + }, + }; + + const defaultResponseHandler = (message: ResponseMessage) => { + if (message.data.response.ok) { + const object = this.memory.retain( + message.data.response.value.object, + ); + this.exports.swjs_receive_response( + object, + message.data.context, + ); + } else { + const error = deserializeError(message.data.response.error); + const errorObject = this.memory.retain(error); + this.exports.swjs_receive_error( + errorObject, + message.data.context, + ); + } + }; + + const responseHandlers: Partial< + Record void> + > = { + invokeRemoteJSObjectBody: (_message) => { + // Swift continuation is resumed on the owner thread. + }, + }; + const newBroker = new MessageBroker(this.tid ?? -1, threadChannel, { onRequest: (message) => { let returnValue: ResponseMessage["data"]["response"]; try { - // @ts-ignore - const result = itcInterface[ - message.data.request.method - ](...message.data.request.parameters); - returnValue = { ok: true, value: result }; + const method = message.data.request.method; + const handler = + requestHandlers[method] ?? defaultRequestHandler; + returnValue = handler(message); } catch (error) { returnValue = { ok: false, error: serializeError(error), }; } + const responseMessage: ResponseMessage = { type: "response", data: { sourceTid: message.data.sourceTid, context: message.data.context, + requestMethod: message.data.request.method, response: returnValue, }, }; + try { newBroker.reply(responseMessage); } catch (error) { @@ -303,24 +373,10 @@ export class SwiftRuntime { } }, onResponse: (message) => { - if (message.data.response.ok) { - const object = this.memory.retain( - message.data.response.value.object, - ); - this.exports.swjs_receive_response( - object, - message.data.context, - ); - } else { - const error = deserializeError( - message.data.response.error, - ); - const errorObject = this.memory.retain(error); - this.exports.swjs_receive_error( - errorObject, - message.data.context, - ); - } + const method = message.data.requestMethod; + const handler = + responseHandlers[method] ?? defaultResponseHandler; + handler(message); }, }); broker = newBroker; @@ -934,6 +990,29 @@ export class SwiftRuntime { }, }); }, + swjs_request_remote_jsobject_body: ( + object_source_tid: number, + invocation_context: pointer, + ) => { + if (!this.options.threadChannel) { + throw new Error( + "threadChannel is not set in options given to SwiftRuntime. Please set it to request remote JSObject access.", + ); + } + const broker = getMessageBroker(this.options.threadChannel); + broker.request({ + type: "request", + data: { + sourceTid: this.tid ?? MAIN_THREAD_TID, + targetTid: object_source_tid, + context: invocation_context, + request: { + method: "invokeRemoteJSObjectBody", + parameters: [invocation_context], + }, + }, + }); + }, }; } diff --git a/Runtime/src/itc.ts b/Runtime/src/itc.ts index 9fadff54a..5d110762b 100644 --- a/Runtime/src/itc.ts +++ b/Runtime/src/itc.ts @@ -117,6 +117,13 @@ export class ITCInterface { return { object: objects, sendingContext, transfer }; } + invokeRemoteJSObjectBody(invocationContext: pointer): { + object: undefined; + transfer: Transferable[]; + } { + return { object: undefined, transfer: [] }; + } + release(objectRef: ref): { object: undefined; transfer: Transferable[] } { this.memory.release(objectRef); return { object: undefined, transfer: [] }; @@ -163,6 +170,8 @@ export type ResponseMessage = { sourceTid: number; /** The context pointer of the request */ context: pointer; + /** The request method this response corresponds to */ + requestMethod: keyof ITCInterface; /** The response content */ response: | { diff --git a/Runtime/src/types.ts b/Runtime/src/types.ts index b39e949b2..bc83fcd22 100644 --- a/Runtime/src/types.ts +++ b/Runtime/src/types.ts @@ -22,6 +22,7 @@ export interface ExportedFunctions { swjs_wake_worker_thread(): void; swjs_receive_response(object: ref, transferring: pointer): void; swjs_receive_error(error: ref, context: number): void; + swjs_invoke_remote_jsobject_body(context: pointer): number; } export const enum LibraryFeatures { diff --git a/Sources/JavaScriptEventLoop/JSRemote.swift b/Sources/JavaScriptEventLoop/JSRemote.swift new file mode 100644 index 000000000..4f488d7b8 --- /dev/null +++ b/Sources/JavaScriptEventLoop/JSRemote.swift @@ -0,0 +1,155 @@ +import _Concurrency +@_spi(JSObject_id) import JavaScriptKit +import _CJavaScriptKit + +/// A sendable handle for temporarily accessing a `JSObject` on its owning thread. +/// +/// `JSRemote` lets you share a reference to a JavaScript object across Swift concurrency +/// domains without transferring or cloning the object itself. Instead, the object stays +/// owned by its original JavaScript thread, and `withJSObject(_:)` schedules a closure to +/// run on that owner when needed. +/// +/// This is useful when you need occasional coordinated access to a JavaScript object from +/// another thread, but cannot or should not move the object with `JSSending`. +/// +/// - Note: `JSRemote` does not make the underlying `JSObject` itself thread-safe. The object +/// may only be touched inside `withJSObject(_:)`. +/// +/// ## Example +/// +/// ```swift +/// let document = JSObject.global.document.object! +/// let remoteDocument = JSRemote(document) +/// +/// let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) +/// let title = try await Task(executorPreference: executor) { +/// try await remoteDocument.withJSObject { document in +/// document.title.string ?? "" +/// } +/// }.value +/// ``` +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +public struct JSRemote: @unchecked Sendable { + private final class Storage { + let sourceObject: JSObject + let sourceTid: Int32 + + init(sourceObject: JSObject, sourceTid: Int32) { + self.sourceObject = sourceObject + self.sourceTid = sourceTid + } + } + + private let storage: Storage + + fileprivate init(sourceObject: JSObject, sourceTid: Int32) { + self.storage = Storage(sourceObject: sourceObject, sourceTid: sourceTid) + } +} + +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +extension JSRemote where T == JSObject { + /// Creates a remote handle for a `JSObject`. + /// + /// The object remains owned by its current JavaScript thread. Access it later by calling + /// `withJSObject(_:)`, which executes the closure on the owning thread when necessary. + /// + /// ## Example + /// + /// ```swift + /// let remoteWindow = JSRemote(JSObject.global) + /// ``` + /// + /// - Parameter object: The JavaScript object to reference remotely. + public init(_ object: JSObject) { + #if compiler(>=6.1) && _runtime(_multithreaded) + self.init(sourceObject: object, sourceTid: object.ownerTid) + #else + self.init(sourceObject: object, sourceTid: -1) + #endif + } + + /// Performs an operation with the underlying `JSObject` on its owning thread. + /// + /// If the caller is already running on the thread that owns the object, `body` executes + /// immediately. Otherwise, this method asynchronously requests execution on the owner and + /// resumes when the closure completes. + /// + /// Use this API when the object must stay on its original thread but a result derived from + /// that object needs to be produced in another Swift concurrency context. + /// + /// ## Example + /// + /// ```swift + /// let location = try await remoteWindow.withJSObject { window in + /// window.location.href.string ?? "" + /// } + /// ``` + /// + /// - Parameter body: A sendable closure that receives the owned `JSObject`. + /// - Returns: The value produced by `body`. + /// - Throws: Any error thrown by `body`. + public func withJSObject( + _ body: @Sendable @escaping (JSObject) throws(E) -> R + ) async throws(E) -> sending R { + #if compiler(>=6.1) && _runtime(_multithreaded) + if storage.sourceTid == swjs_get_worker_thread_id_cached() { + return try body(storage.sourceObject) + } + let result: Result = await withCheckedContinuation { continuation in + let context = _JSRemoteContext( + sourceObject: storage.sourceObject, + body: body, + continuation: continuation + ) + swjs_request_remote_jsobject_body( + storage.sourceTid, + Unmanaged.passRetained(context).toOpaque() + ) + } + return try result.get() + #else + return try body(storage.sourceObject) + #endif + } +} + +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +private final class _JSRemoteContext: @unchecked Sendable { + let invokeBody: () -> Bool + + init( + sourceObject: JSObject, + body: @escaping @Sendable (JSObject) throws(E) -> R, + continuation: CheckedContinuation, Never> + ) { + self.invokeBody = { + // NOTE: Sendability violation here for `sourceObject` + // Even though `JSObject` is not Sendable, it is safe to access it here + // because this invokeBody closure will only be executed on the owning thread. + do throws(E) { + continuation.resume(returning: .success(try body(sourceObject))) + } catch { + continuation.resume(returning: .failure(error)) + } + return false + } + } +} + +#if compiler(>=6.1) +@_expose(wasm, "swjs_invoke_remote_jsobject_body") +@_cdecl("swjs_invoke_remote_jsobject_body") +#endif +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +func _swjs_invoke_remote_jsobject_body(_ contextPtr: UnsafeRawPointer?) -> Bool { + #if compiler(>=6.1) && _runtime(_multithreaded) + guard let contextPtr else { return true } + let context = Unmanaged<_JSRemoteContext>.fromOpaque(contextPtr).takeRetainedValue() + + return context.invokeBody() + #else + _ = contextPtr + return true + #endif +} diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index 28e7b5e3d..3800a6d9e 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -355,4 +355,9 @@ IMPORT_JS_FUNCTION(swjs_request_sending_objects, void, (const JavaScriptObjectRe int object_source_tid, void * _Nonnull sending_context)) +/// Requests invoking a Swift closure associated with `invocation_context` on `object_source_tid`. +/// This must be called from a non-owner thread and will asynchronously notify completion. +IMPORT_JS_FUNCTION(swjs_request_remote_jsobject_body, void, (int object_source_tid, + void * _Nonnull invocation_context)) + #endif /* _CJavaScriptKit_h */ diff --git a/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift b/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift index f743d8ef0..54559f3d8 100644 --- a/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift +++ b/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift @@ -618,6 +618,152 @@ final class WebWorkerTaskExecutorTests: XCTestCase { XCTAssertEqual(object["test"].string!, "Hello, World!") } + func testRemoteMainToWorkerAccess() async throws { + let object = JSObject.global.Object.function!.new() + object["value"] = 42 + let remote = JSRemote(object) + + let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) + defer { executor.terminate() } + + let task = Task(executorPreference: executor) { + try await remote.withJSObject { object in + object["value"].number! + } + } + + let value = try await task.value + XCTAssertEqual(value, 42) + } + + func testRemoteWorkerToMainAccess() async throws { + let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) + defer { executor.terminate() } + + let task = Task(executorPreference: executor) { + let object = JSObject.global.Object.function!.new() + object["value"] = 99 + let remote = JSRemote(object) + return remote + } + + let remote = await task.value + let result = try await remote.withJSObject { object in + object["value"].number! + } + XCTAssertEqual(result, 99) + } + + func testRemoteSameThreadFastPath() async throws { + let object = JSObject.global.Object.function!.new() + object["flag"] = 1 + let remote = JSRemote(object) + + let result = try await remote.withJSObject { object in + object["flag"].number! + } + XCTAssertEqual(result, 1) + } + + func testRemoteCanBeUsedMultipleTimesAcrossThreads() async throws { + let object = JSObject.global.Object.function!.new() + object["count"] = 0 + let remote = JSRemote(object) + + let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) + defer { executor.terminate() } + + let task = Task(executorPreference: executor) { + let first = try await remote.withJSObject { object in + let nextValue = object["count"].number! + 1 + object["count"] = .number(nextValue) + return nextValue + } + let second = try await remote.withJSObject { object in + let nextValue = object["count"].number! + 1 + object["count"] = .number(nextValue) + return nextValue + } + return (first, second) + } + + let (first, second) = try await task.value + XCTAssertEqual(first, 1) + XCTAssertEqual(second, 2) + XCTAssertEqual(object["count"].number!, 2) + } + + func testRemoteConcurrentAccessFromWorkerTasks() async throws { + let object = JSObject.global.Object.function!.new() + object["value"] = 42 + let remote = JSRemote(object) + + let executor = try await WebWorkerTaskExecutor(numberOfThreads: 2) + defer { executor.terminate() } + + let results = try await withThrowingTaskGroup(of: Int.self, returning: [Int].self) { group in + for _ in 0..<8 { + group.addTask(executorPreference: executor) { + try await remote.withJSObject { object in + Int(object["value"].number!) + } + } + } + + var results: [Int] = [] + for try await value in group { + results.append(value) + } + return results + } + + XCTAssertEqual(results.count, 8) + XCTAssertEqual(results, Array(repeating: 42, count: 8)) + } + + func testRemoteMutationIsVisibleOnOwnerThread() async throws { + let object = JSObject.global.Object.function!.new() + object["value"] = 10 + let remote = JSRemote(object) + + let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) + defer { executor.terminate() } + + let task = Task(executorPreference: executor) { + try await remote.withJSObject { object in + object["value"] = .number(object["value"].number! + 5) + } + } + + _ = try await task.value + XCTAssertEqual(object["value"].number!, 15) + } + + func testRemoteThrowsTypedError() async throws { + struct TestError: Error, Equatable { + let message: String + } + + let object = JSObject.global.Object.function!.new() + let remote = JSRemote(object) + let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) + defer { executor.terminate() } + + let task = Task(executorPreference: executor) { + do { + _ = try await remote.withJSObject { _ in + throw TestError(message: "boom") + } + return "unexpected" + } catch { + return String(describing: error) + } + } + + let errorDescription = try await task.value + XCTAssertTrue(errorDescription.contains("boom"), errorDescription) + } + func testThrowJSExceptionAcrossThreads() async throws { let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) let task = Task(executorPreference: executor) { From 5ceeb0802d71c59e126d58ea8cea7f97c6c61e35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:56:02 +0000 Subject: [PATCH 22/68] Bump vite from 7.3.1 to 7.3.2 (#712) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.3.1 to 7.3.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.3.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5eab62401..1c95a1ce2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1582,9 +1582,9 @@ "dev": true }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, "license": "MIT", "dependencies": { From 76543856201aca11bec46c3cb1cbd9c619ac3d4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 10:19:19 +0100 Subject: [PATCH 23/68] Bump actions/deploy-pages from 4 to 5 (#710) Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 4 to 5. - [Release notes](https://github.com/actions/deploy-pages/releases) - [Commits](https://github.com/actions/deploy-pages/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/deploy-pages dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 419c772a0..e8118a481 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -199,4 +199,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 From af88676816797ac9e4ab68870813999a8267ce28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 10:19:55 +0100 Subject: [PATCH 24/68] Bump picomatch from 4.0.3 to 4.0.4 (#713) Bumps [picomatch](https://github.com/micromatch/picomatch) from 4.0.3 to 4.0.4. - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4) --- updated-dependencies: - dependency-name: picomatch dependency-version: 4.0.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1c95a1ce2..ea24d1645 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1289,9 +1289,9 @@ "dev": true }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { From 9f149ccbae947e79c1d4607a941dba06b5c55947 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 9 Apr 2026 12:35:21 +0200 Subject: [PATCH 25/68] BridgeJS: Fix for-loop emission in stack codegen Three `StackCodegen` helpers built their `for`-loops from separate `CodeBlockItemSyntax` fragments ("for ... {", body, "}"). swift-syntax 603's formatter then renders such partial statements with the closing brace glued to the previous line. Combine each for-loop into a single multi-line `CodeBlockItemSyntax` so the formatter produces consistent output across swift-syntax 600-603. Also fix a latent bug in `StructCodegen.generateStructLowerCode` and `EnumCodegen.generatePayloadPushingCode`: they concatenated lowering statements via `CodeBlockItemListSyntax(statements).description` which does not insert separators between items that lack leading trivia. The thunk builder path was fine because `append` explicitly adds `.newline` trivia, but any multi-statement lowering routed through a struct field or enum payload was silently glued onto a single line. Iterate over the statements and write each one individually through the printer. Add regression coverage for the previously untested codepaths: - `[String: MyProtocol]` as a function return, class property getter, and parameter (exercises `lowerProtocolDictionaryStatements`). - A `@JS struct` field of type `[String: Int?]` (exercises `lowerDictionaryStatementsInline` via `generateStructLowerCode`). --- .../Sources/BridgeJSCore/ExportSwift.swift | 97 +++++++++++-------- .../Inputs/MacroSwift/DictionaryTypes.swift | 6 ++ .../Inputs/MacroSwift/Protocol.swift | 8 ++ .../BridgeJSCodegenTests/DictionaryTypes.json | 65 +++++++++++++ .../DictionaryTypes.swift | 65 +++++++++++++ .../BridgeJSCodegenTests/Protocol.json | 47 +++++++++ .../BridgeJSCodegenTests/Protocol.swift | 46 ++++++++- .../BridgeJSLinkTests/DictionaryTypes.d.ts | 5 + .../BridgeJSLinkTests/DictionaryTypes.js | 56 +++++++++++ .../BridgeJSLinkTests/Protocol.d.ts | 2 + .../BridgeJSLinkTests/Protocol.js | 51 ++++++++++ .../Generated/BridgeJS.swift | 11 ++- 12 files changed, 411 insertions(+), 48 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index ca7bdc3c2..f7824711f 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -827,15 +827,15 @@ struct StackCodegen { accessor: String, varPrefix: String ) -> [CodeBlockItemSyntax] { - var statements: [CodeBlockItemSyntax] = [] let elemVar = "__bjs_elem_\(varPrefix)" - statements.append("for \(raw: elemVar) in \(raw: accessor) {") - statements.append( - " _swift_js_push_i32((\(raw: elemVar) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" - ) - statements.append("}") - statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))") - return statements + return [ + """ + for \(raw: elemVar) in \(raw: accessor) { + _swift_js_push_i32((\(raw: elemVar) as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } + """, + "_swift_js_push_i32(Int32(\(raw: accessor).count))", + ] } private func lowerDictionaryStatements( @@ -866,49 +866,58 @@ struct StackCodegen { accessor: String, varPrefix: String ) -> [CodeBlockItemSyntax] { - var statements: [CodeBlockItemSyntax] = [] let pairVarName = "__bjs_kv_\(varPrefix)" - statements.append("for \(raw: pairVarName) in \(raw: accessor) {") - statements.append("let __bjs_key_\(raw: varPrefix) = \(raw: pairVarName).key") - statements.append("let __bjs_value_\(raw: varPrefix) = \(raw: pairVarName).value") - - let keyStatements = lowerStatements( - for: .string, - accessor: "__bjs_key_\(varPrefix)", - varPrefix: "\(varPrefix)_key" + let keyVarName = "__bjs_key_\(varPrefix)" + let valueVarName = "__bjs_value_\(varPrefix)" + + // The dispatch in `lowerDictionaryStatements` routes only .nullable and .closure value + // types into this helper, both of which produce single-line lowering statements, so we can + // join their descriptions into the for-body as plain lines without worrying about nested + // multi-statement lowering. + var bodyLines: [String] = [ + "let \(keyVarName) = \(pairVarName).key", + "let \(valueVarName) = \(pairVarName).value", + ] + bodyLines.append( + contentsOf: lowerStatements( + for: .string, + accessor: keyVarName, + varPrefix: "\(varPrefix)_key" + ).map { $0.description } ) - for stmt in keyStatements { - statements.append(stmt) - } - - let valueStatements = lowerStatements( - for: valueType, - accessor: "__bjs_value_\(varPrefix)", - varPrefix: "\(varPrefix)_value" + bodyLines.append( + contentsOf: lowerStatements( + for: valueType, + accessor: valueVarName, + varPrefix: "\(varPrefix)_value" + ).map { $0.description } ) - for stmt in valueStatements { - statements.append(stmt) - } + let body = bodyLines.joined(separator: "\n ") - statements.append("}") - statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))") - return statements + return [ + """ + for \(raw: pairVarName) in \(raw: accessor) { + \(raw: body) + } + """, + "_swift_js_push_i32(Int32(\(raw: accessor).count))", + ] } private func lowerProtocolDictionaryStatements( accessor: String, varPrefix: String ) -> [CodeBlockItemSyntax] { - var statements: [CodeBlockItemSyntax] = [] let pairVar = "__bjs_kv_\(varPrefix)" - statements.append("for \(raw: pairVar) in \(raw: accessor) {") - statements.append(" \(raw: pairVar).key.bridgeJSStackPush()") - statements.append( - " _swift_js_push_i32((\(raw: pairVar).value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())" - ) - statements.append("}") - statements.append("_swift_js_push_i32(Int32(\(raw: accessor).count))") - return statements + return [ + """ + for \(raw: pairVar) in \(raw: accessor) { + \(raw: pairVar).key.bridgeJSStackPush() + _swift_js_push_i32((\(raw: pairVar).value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } + """, + "_swift_js_push_i32(Int32(\(raw: accessor).count))", + ] } } @@ -1073,7 +1082,9 @@ struct EnumCodegen { accessor: paramName, varPrefix: paramName ) - printer.write(multilineString: CodeBlockItemListSyntax(statements).description) + for statement in statements { + printer.write(multilineString: statement.description) + } } } @@ -1207,7 +1218,9 @@ struct StructCodegen { accessor: accessor, varPrefix: property.name ) - printer.write(multilineString: CodeBlockItemListSyntax(statements).description) + for statement in statements { + printer.write(multilineString: statement.description) + } } return printer.lines diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/DictionaryTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/DictionaryTypes.swift index c699ea79b..a45bf1dd8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/DictionaryTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/DictionaryTypes.swift @@ -6,10 +6,16 @@ } } +@JS struct Counters { + var name: String + var counts: [String: Int?] +} + @JS func mirrorDictionary(_ values: [String: Int]) -> [String: Int] @JS func optionalDictionary(_ values: [String: String]?) -> [String: String]? @JS func nestedDictionary(_ values: [String: [Int]]) -> [String: [Int]] @JS func boxDictionary(_ boxes: [String: Box]) -> [String: Box] @JS func optionalBoxDictionary(_ boxes: [String: Box?]) -> [String: Box?] +@JS func roundtripCounters(_ counters: Counters) -> Counters @JSFunction func importMirrorDictionary(_ values: [String: Double]) throws(JSException) -> [String: Double] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift index fbbad0615..bdb700d69 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Protocol.swift @@ -102,8 +102,12 @@ import JavaScriptKit @JS var delegates: [MyViewControllerDelegate] + @JS + var delegatesByName: [String: MyViewControllerDelegate] + @JS init(delegates: [MyViewControllerDelegate]) { self.delegates = delegates + self.delegatesByName = [:] } @JS func notifyAll() { @@ -114,3 +118,7 @@ import JavaScriptKit } @JS func processDelegates(_ delegates: [MyViewControllerDelegate]) -> [MyViewControllerDelegate] + +@JS func processDelegatesByName( + _ delegates: [String: MyViewControllerDelegate] +) -> [String: MyViewControllerDelegate] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json index ea707098d..e18586e1c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json @@ -221,13 +221,78 @@ } } } + }, + { + "abiName" : "bjs_roundtripCounters", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripCounters", + "parameters" : [ + { + "label" : "_", + "name" : "counters", + "type" : { + "swiftStruct" : { + "_0" : "Counters" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Counters" + } + } } ], "protocols" : [ ], "structs" : [ + { + "methods" : [ + + ], + "name" : "Counters", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "counts", + "type" : { + "dictionary" : { + "_0" : { + "nullable" : { + "_0" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "_1" : "null" + } + } + } + } + } + ], + "swiftCallName" : "Counters" + } ] }, "imported" : { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift index dc0a54bcf..26a4c087e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.swift @@ -1,3 +1,57 @@ +extension Counters: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Counters { + let counts = [String: Optional].bridgeJSStackPop() + let name = String.bridgeJSStackPop() + return Counters(name: name, counts: counts) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.name.bridgeJSStackPush() + for __bjs_kv_counts in self.counts { + let __bjs_key_counts = __bjs_kv_counts.key + let __bjs_value_counts = __bjs_kv_counts.value + __bjs_key_counts.bridgeJSStackPush() + __bjs_value_counts.bridgeJSStackPush() + } + _swift_js_push_i32(Int32(self.counts.count)) + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Counters(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Counters())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Counters") +fileprivate func _bjs_struct_lower_Counters_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Counters_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Counters(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Counters_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Counters") +fileprivate func _bjs_struct_lift_Counters_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Counters_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Counters() -> Int32 { + return _bjs_struct_lift_Counters_extern() +} + @_expose(wasm, "bjs_mirrorDictionary") @_cdecl("bjs_mirrorDictionary") public func _bjs_mirrorDictionary() -> Void { @@ -53,6 +107,17 @@ public func _bjs_optionalBoxDictionary() -> Void { #endif } +@_expose(wasm, "bjs_roundtripCounters") +@_cdecl("bjs_roundtripCounters") +public func _bjs_roundtripCounters() -> Void { + #if arch(wasm32) + let ret = roundtripCounters(_: Counters.bridgeJSLiftParameter()) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Box_deinit") @_cdecl("bjs_Box_deinit") public func _bjs_Box_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json index 757115c59..b46d1125e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json @@ -317,6 +317,20 @@ } } } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "delegatesByName", + "type" : { + "dictionary" : { + "_0" : { + "swiftProtocol" : { + "_0" : "MyViewControllerDelegate" + } + } + } + } } ], "swiftCallName" : "DelegateManager" @@ -502,6 +516,39 @@ } } } + }, + { + "abiName" : "bjs_processDelegatesByName", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processDelegatesByName", + "parameters" : [ + { + "label" : "_", + "name" : "delegates", + "type" : { + "dictionary" : { + "_0" : { + "swiftProtocol" : { + "_0" : "MyViewControllerDelegate" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "swiftProtocol" : { + "_0" : "MyViewControllerDelegate" + } + } + } + } } ], "protocols" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index cf7464cc3..745ec6cc9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -698,7 +698,23 @@ public func _bjs_processDelegates() -> Void { #if arch(wasm32) let ret = processDelegates(_: [AnyMyViewControllerDelegate].bridgeJSStackPop()) for __bjs_elem_ret in ret { - _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } + _swift_js_push_i32(Int32(ret.count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_processDelegatesByName") +@_cdecl("bjs_processDelegatesByName") +public func _bjs_processDelegatesByName() -> Void { + #if arch(wasm32) + let ret = processDelegatesByName(_: [String: AnyMyViewControllerDelegate].bridgeJSLiftParameter()) + for __bjs_kv_ret in ret { + __bjs_kv_ret.key.bridgeJSStackPush() + _swift_js_push_i32((__bjs_kv_ret.value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") @@ -955,7 +971,8 @@ public func _bjs_DelegateManager_delegates_get(_ _self: UnsafeMutableRawPointer) #if arch(wasm32) let ret = DelegateManager.bridgeJSLiftParameter(_self).delegates for __bjs_elem_ret in ret { - _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") @@ -972,6 +989,31 @@ public func _bjs_DelegateManager_delegates_set(_ _self: UnsafeMutableRawPointer) #endif } +@_expose(wasm, "bjs_DelegateManager_delegatesByName_get") +@_cdecl("bjs_DelegateManager_delegatesByName_get") +public func _bjs_DelegateManager_delegatesByName_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = DelegateManager.bridgeJSLiftParameter(_self).delegatesByName + for __bjs_kv_ret in ret { + __bjs_kv_ret.key.bridgeJSStackPush() + _swift_js_push_i32((__bjs_kv_ret.value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } + _swift_js_push_i32(Int32(ret.count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DelegateManager_delegatesByName_set") +@_cdecl("bjs_DelegateManager_delegatesByName_set") +public func _bjs_DelegateManager_delegatesByName_set(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + DelegateManager.bridgeJSLiftParameter(_self).delegatesByName = [String: AnyMyViewControllerDelegate].bridgeJSLiftParameter() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_DelegateManager_deinit") @_cdecl("bjs_DelegateManager_deinit") public func _bjs_DelegateManager_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts index dadcc74ba..f14b29aa4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.d.ts @@ -4,6 +4,10 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. +export interface Counters { + name: string; + counts: Record; +} /// Represents a Swift heap object like a class instance or an actor instance. export interface SwiftHeapObject { /// Release the heap object. @@ -21,6 +25,7 @@ export type Exports = { nestedDictionary(values: Record): Record; boxDictionary(boxes: Record): Record; optionalBoxDictionary(boxes: Record): Record; + roundtripCounters(counters: Counters): Counters; } export type Imports = { importMirrorDictionary(values: Record): Record; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 1e9059e34..b6cf2c253 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -30,6 +30,46 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + 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); + }, + 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 }; + } + }); return { /** @@ -99,6 +139,13 @@ export async function createInstantiator(options, swift) { bjs["swift_js_pop_i64"] = function() { return i64Stack.pop(); } + bjs["swift_js_struct_lower_Counters"] = function(objectId) { + structHelpers.Counters.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Counters"] = function() { + const value = structHelpers.Counters.lift(); + return swift.memory.retain(value); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -271,6 +318,9 @@ export async function createInstantiator(options, swift) { } } + const CountersHelpers = __bjs_createCountersHelpers(); + structHelpers.Counters = CountersHelpers; + const exports = { Box, mirrorDictionary: function bjs_mirrorDictionary(values) { @@ -414,6 +464,12 @@ export async function createInstantiator(options, swift) { } return dictResult; }, + roundtripCounters: function bjs_roundtripCounters(counters) { + structHelpers.Counters.lower(counters); + instance.exports.bjs_roundtripCounters(); + const structValue = structHelpers.Counters.lift(); + return structValue; + }, }; _exports = exports; return exports; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts index 4c09ad85f..27cd9212b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.d.ts @@ -93,6 +93,7 @@ export interface MyViewController extends SwiftHeapObject { export interface DelegateManager extends SwiftHeapObject { notifyAll(): void; delegates: MyViewControllerDelegate[]; + delegatesByName: Record; } export type Exports = { Helper: { @@ -105,6 +106,7 @@ export type Exports = { new(delegates: MyViewControllerDelegate[]): DelegateManager; } processDelegates(delegates: MyViewControllerDelegate[]): MyViewControllerDelegate[]; + processDelegatesByName(delegates: Record): Record; Direction: DirectionObject ExampleEnum: ExampleEnumObject Result: ResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index e606c3a77..f82e41703 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -718,6 +718,33 @@ export async function createInstantiator(options, swift) { i32Stack.push(value.length); 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; + } + 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); + instance.exports.bjs_DelegateManager_delegatesByName_set(this.pointer); + } } const ResultHelpers = __bjs_createResultValuesHelpers(); enumHelpers.Result = ResultHelpers; @@ -744,6 +771,30 @@ export async function createInstantiator(options, swift) { arrayResult.reverse(); 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); + 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; + } + return dictResult; + }, Direction: DirectionValues, ExampleEnum: ExampleEnumValues, Result: ResultValues, diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 71e5ef537..4f5b6e477 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -3420,7 +3420,8 @@ public func _bjs_ArraySupportExports_static_roundTripProtocolArray() -> Void { #if arch(wasm32) let ret = ArraySupportExports.roundTripProtocolArray(_: [AnyArrayElementProtocol].bridgeJSStackPop()) for __bjs_elem_ret in ret { - _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") @@ -10089,7 +10090,8 @@ public func _bjs_ProtocolReturnTests_static_createNativeProcessorArray() -> Void #if arch(wasm32) let ret = ProtocolReturnTests.createNativeProcessorArray() for __bjs_elem_ret in ret { - _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + _swift_js_push_i32((__bjs_elem_ret as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") @@ -10102,8 +10104,9 @@ public func _bjs_ProtocolReturnTests_static_createNativeProcessorDictionary() -> #if arch(wasm32) let ret = ProtocolReturnTests.createNativeProcessorDictionary() for __bjs_kv_ret in ret { - __bjs_kv_ret.key.bridgeJSStackPush() - _swift_js_push_i32((__bjs_kv_ret.value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn())} + __bjs_kv_ret.key.bridgeJSStackPush() + _swift_js_push_i32((__bjs_kv_ret.value as! _BridgedSwiftProtocolExportable).bridgeJSLowerAsProtocolReturn()) + } _swift_js_push_i32(Int32(ret.count)) #else fatalError("Only available on WebAssembly") From 9f2b43213a5a1b33489a476a01555903f50a32a4 Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Thu, 9 Apr 2026 13:32:20 +0200 Subject: [PATCH 26/68] flip `Package.swift` file versioning (#715) makes `Package.swift` be the newest, while supporting older versions with concrete versions baked in as mentioned in https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/swiftversionspecificpackaging/#Version-specific-Manifest-Selection --- Package.swift | 19 +++++++++++++++---- ...swift-6.2.swift => Package@swift-6.1.swift | 19 ++++--------------- 2 files changed, 19 insertions(+), 19 deletions(-) rename Package@swift-6.2.swift => Package@swift-6.1.swift (91%) diff --git a/Package.swift b/Package.swift index 60adb7a5f..20583865b 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:6.1 +// swift-tools-version:6.2 import CompilerPluginSupport import PackageDescription @@ -7,6 +7,13 @@ import PackageDescription let shouldBuildForEmbedded = Context.environment["JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM"].flatMap(Bool.init) ?? false let useLegacyResourceBundling = Context.environment["JAVASCRIPTKIT_USE_LEGACY_RESOURCE_BUNDLING"].flatMap(Bool.init) ?? false +let enableTracingByEnv = Context.environment["JAVASCRIPTKIT_ENABLE_TRACING"].flatMap(Bool.init) ?? false + +let tracingTrait = Trait( + name: "Tracing", + description: "Enable opt-in Swift <-> JavaScript bridge tracing hooks.", + enabledTraits: [] +) let testingLinkerFlags: [LinkerSetting] = [ .unsafeFlags( @@ -39,6 +46,7 @@ let package = Package( .plugin(name: "BridgeJS", targets: ["BridgeJS"]), .plugin(name: "BridgeJSCommandPlugin", targets: ["BridgeJSCommandPlugin"]), ], + traits: [tracingTrait], dependencies: [ .package(url: "https://github.com/swiftlang/swift-syntax", "600.0.0"..<"603.0.0") ], @@ -53,8 +61,10 @@ let package = Package( .unsafeFlags(["-fdeclspec"]) ] : nil, swiftSettings: [ - .enableExperimentalFeature("Extern") + .enableExperimentalFeature("Extern"), + .define("Tracing", .when(traits: ["Tracing"])), ] + + (enableTracingByEnv ? [.define("Tracing")] : []) + (shouldBuildForEmbedded ? [ .enableExperimentalFeature("Embedded"), @@ -74,8 +84,9 @@ let package = Package( name: "JavaScriptKitTests", dependencies: ["JavaScriptKit"], swiftSettings: [ - .enableExperimentalFeature("Extern") - ], + .enableExperimentalFeature("Extern"), + .define("Tracing", .when(traits: ["Tracing"])), + ] + (enableTracingByEnv ? [.define("Tracing")] : []), linkerSettings: testingLinkerFlags ), diff --git a/Package@swift-6.2.swift b/Package@swift-6.1.swift similarity index 91% rename from Package@swift-6.2.swift rename to Package@swift-6.1.swift index 20583865b..60adb7a5f 100644 --- a/Package@swift-6.2.swift +++ b/Package@swift-6.1.swift @@ -1,4 +1,4 @@ -// swift-tools-version:6.2 +// swift-tools-version:6.1 import CompilerPluginSupport import PackageDescription @@ -7,13 +7,6 @@ import PackageDescription let shouldBuildForEmbedded = Context.environment["JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM"].flatMap(Bool.init) ?? false let useLegacyResourceBundling = Context.environment["JAVASCRIPTKIT_USE_LEGACY_RESOURCE_BUNDLING"].flatMap(Bool.init) ?? false -let enableTracingByEnv = Context.environment["JAVASCRIPTKIT_ENABLE_TRACING"].flatMap(Bool.init) ?? false - -let tracingTrait = Trait( - name: "Tracing", - description: "Enable opt-in Swift <-> JavaScript bridge tracing hooks.", - enabledTraits: [] -) let testingLinkerFlags: [LinkerSetting] = [ .unsafeFlags( @@ -46,7 +39,6 @@ let package = Package( .plugin(name: "BridgeJS", targets: ["BridgeJS"]), .plugin(name: "BridgeJSCommandPlugin", targets: ["BridgeJSCommandPlugin"]), ], - traits: [tracingTrait], dependencies: [ .package(url: "https://github.com/swiftlang/swift-syntax", "600.0.0"..<"603.0.0") ], @@ -61,10 +53,8 @@ let package = Package( .unsafeFlags(["-fdeclspec"]) ] : nil, swiftSettings: [ - .enableExperimentalFeature("Extern"), - .define("Tracing", .when(traits: ["Tracing"])), + .enableExperimentalFeature("Extern") ] - + (enableTracingByEnv ? [.define("Tracing")] : []) + (shouldBuildForEmbedded ? [ .enableExperimentalFeature("Embedded"), @@ -84,9 +74,8 @@ let package = Package( name: "JavaScriptKitTests", dependencies: ["JavaScriptKit"], swiftSettings: [ - .enableExperimentalFeature("Extern"), - .define("Tracing", .when(traits: ["Tracing"])), - ] + (enableTracingByEnv ? [.define("Tracing")] : []), + .enableExperimentalFeature("Extern") + ], linkerSettings: testingLinkerFlags ), From 6d2c0703c97dd47f1901e4a827416037b40466f6 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 9 Apr 2026 13:51:01 +0200 Subject: [PATCH 27/68] BridgeJS: Emit static methods and properties on namespaced class entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TypeScript `.d.ts` namespace-entry builder for `@JS(namespace:)` classes only emitted the constructor, silently dropping any `@JS static func` or `@JS static var` declared on the class. The equivalent path for non-namespaced classes (`renderExportedClass` → `dtsExportEntryPrinter`) iterates `klass.methods.filter(\.effects.isStatic)` and the static subset of `klass.properties`, so the output mismatched between the two paths. The generated JS class still carries the static members via `declarationPrefixKeyword: "static"` in `renderExportedClass`, and the namespace tree references it by symbol, so the JavaScript runtime works. TypeScript consumers, however, see an incomplete type and cannot call the static factory through `typeof MyNamespace.MyClass` without a hand-written augmentation. Mirror the non-namespaced path inside the `renderClassEntry` closure in `generateTypeScript` so namespaced classes emit their static methods and static properties alongside `new(...)`. Extended `Namespaces.swift` to exercise the codepath by adding a static factory and a static readonly property on the existing `__Swift.Foundation.Greeter` class. The Namespaces snapshot set captures the fixed output. --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 13 +++++++ .../Inputs/MacroSwift/Namespaces.swift | 11 ++++++ .../Namespaces.Global.json | 36 +++++++++++++++++++ .../Namespaces.Global.swift | 22 ++++++++++++ .../BridgeJSCodegenTests/Namespaces.json | 36 +++++++++++++++++++ .../BridgeJSCodegenTests/Namespaces.swift | 22 ++++++++++++ .../BridgeJSLinkTests/Namespaces.Global.d.ts | 3 ++ .../BridgeJSLinkTests/Namespaces.Global.js | 10 ++++++ .../BridgeJSLinkTests/Namespaces.d.ts | 2 ++ .../BridgeJSLinkTests/Namespaces.js | 10 ++++++ 10 files changed, 165 insertions(+) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 63b628eb3..f7527c600 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -901,6 +901,19 @@ public struct BridgeJSLink { "new\(self.renderTSSignature(parameters: constructor.parameters, returnType: .swiftHeapObject(klass.name), effects: constructor.effects));" ) } + // Static methods and static properties belong on the namespace + // entry alongside the constructor (same shape that + // `renderExportedClass` produces for non-namespaced classes via + // `dtsExportEntryPrinter`). + for method in klass.methods where method.effects.isStatic { + printer.write( + "\(method.name)\(self.renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + ) + } + for property in klass.properties where property.isStatic { + let readonly = property.isReadonly ? "readonly " : "" + printer.write("\(readonly)\(property.name): \(property.type.tsType);") + } } printer.write("}") return printer.lines diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Namespaces.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Namespaces.swift index cbe146ff5..7cd63c698 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Namespaces.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Namespaces.swift @@ -16,6 +16,17 @@ func changeName(name: String) { self.name = name } + + // Static methods and properties on a namespaced class must land on the + // class's namespace entry (alongside `new`), not on the instance + // interface and not silently dropped. Regression test for the + // `@JS(namespace:)` + `@JS static func` bug where the hierarchical + // exports builder only emitted the constructor. + @JS static func makeDefault() -> Greeter { + return Greeter(name: "World") + } + + @JS static var defaultGreeting: String { "Hello, world!" } } @JS(namespace: "Utils.Converters") class Converter { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json index 9ca72009d..080f9f959 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json @@ -38,6 +38,28 @@ } } + }, + { + "abiName" : "bjs___Swift_Foundation_Greeter_static_makeDefault", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "makeDefault", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "staticContext" : { + "className" : { + "_0" : "__Swift_Foundation_Greeter" + } + } } ], "name" : "Greeter", @@ -46,7 +68,21 @@ "Foundation" ], "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "__Swift_Foundation_Greeter" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Greeter" }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift index 86f0b8478..af7efbecd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift @@ -42,6 +42,28 @@ public func _bjs___Swift_Foundation_Greeter_greet(_ _self: UnsafeMutableRawPoint #endif } +@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_makeDefault") +@_cdecl("bjs___Swift_Foundation_Greeter_static_makeDefault") +public func _bjs___Swift_Foundation_Greeter_static_makeDefault() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter.makeDefault() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_defaultGreeting_get") +@_cdecl("bjs___Swift_Foundation_Greeter_static_defaultGreeting_get") +public func _bjs___Swift_Foundation_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = __Swift_Foundation_Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs___Swift_Foundation_Greeter_deinit") @_cdecl("bjs___Swift_Foundation_Greeter_deinit") public func _bjs___Swift_Foundation_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json index 0713a2f30..d471eeaca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json @@ -38,6 +38,28 @@ } } + }, + { + "abiName" : "bjs___Swift_Foundation_Greeter_static_makeDefault", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "makeDefault", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + }, + "staticContext" : { + "className" : { + "_0" : "__Swift_Foundation_Greeter" + } + } } ], "name" : "Greeter", @@ -46,7 +68,21 @@ "Foundation" ], "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "__Swift_Foundation_Greeter" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Greeter" }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift index 86f0b8478..af7efbecd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift @@ -42,6 +42,28 @@ public func _bjs___Swift_Foundation_Greeter_greet(_ _self: UnsafeMutableRawPoint #endif } +@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_makeDefault") +@_cdecl("bjs___Swift_Foundation_Greeter_static_makeDefault") +public func _bjs___Swift_Foundation_Greeter_static_makeDefault() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter.makeDefault() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_defaultGreeting_get") +@_cdecl("bjs___Swift_Foundation_Greeter_static_defaultGreeting_get") +public func _bjs___Swift_Foundation_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = __Swift_Foundation_Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs___Swift_Foundation_Greeter_deinit") @_cdecl("bjs___Swift_Foundation_Greeter_deinit") public func _bjs___Swift_Foundation_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { 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 4b7851c3e..1353220bc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts @@ -34,6 +34,7 @@ declare global { class Greeter { constructor(name: string); greet(): string; + makeDefault(): Greeter; release(): void; } class UUID { @@ -87,6 +88,8 @@ export type Exports = { Foundation: { Greeter: { new(name: string): Greeter; + makeDefault(): Greeter; + readonly defaultGreeting: string; } UUID: { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index 4a6ee1990..f4596dba7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -268,6 +268,16 @@ export async function createInstantiator(options, swift) { tmpRetString = undefined; return ret; } + static makeDefault() { + const ret = instance.exports.bjs___Swift_Foundation_Greeter_static_makeDefault(); + return Greeter.__construct(ret); + } + static get defaultGreeting() { + instance.exports.bjs___Swift_Foundation_Greeter_static_defaultGreeting_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } } class Converter extends SwiftHeapObject { static __construct(ptr) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts index fff65ce6d..6b2d65cd8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts @@ -47,6 +47,8 @@ export type Exports = { Foundation: { Greeter: { new(name: string): Greeter; + makeDefault(): Greeter; + readonly defaultGreeting: string; } UUID: { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 267d96152..92ce69cbb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -268,6 +268,16 @@ export async function createInstantiator(options, swift) { tmpRetString = undefined; return ret; } + static makeDefault() { + const ret = instance.exports.bjs___Swift_Foundation_Greeter_static_makeDefault(); + return Greeter.__construct(ret); + } + static get defaultGreeting() { + instance.exports.bjs___Swift_Foundation_Greeter_static_defaultGreeting_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } } class Converter extends SwiftHeapObject { static __construct(ptr) { From 9a56b282c157bd7cdfcdb30194912f17dae180b1 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 9 Apr 2026 14:07:24 +0200 Subject: [PATCH 28/68] BridgeJS: Consolidate namespaced and non-namespaced class DTS entry rendering The `renderClassEntry` closure passed to `buildHierarchicalExportsType` manually rebuilt the same `ClassName: { new(...); staticMethod(); ... }` block that `renderExportedClass` already produces as its `dtsExportEntry` return value. The two paths had to be kept in sync by hand. Replace the inline closure with a direct call to `renderExportedClass` that discards the JS and DTS-type outputs and returns only the `dtsExportEntry` slice. This makes the class namespace entry for namespaced and non-namespaced classes identical by construction. Thread `throws` through `buildHierarchicalExportsType`, `populateTypeScriptExportLines`, and `generateTypeScript` to accommodate the fact that `renderExportedClass` is throwing. Hoist the `buildHierarchicalExportsType` call out of the `printer.indent` closure so the `try` expression is in a throwing context. --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 63 ++++++------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index f7527c600..26ed8387f 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -796,7 +796,7 @@ public struct BridgeJSLink { return printer.lines } - private func generateTypeScript(data: LinkData) -> String { + private func generateTypeScript(data: LinkData) throws -> String { let header = """ // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. @@ -884,45 +884,22 @@ public struct BridgeJSLink { printer.write(lines: generateImportedTypeDefinitions()) // Exports type + let hierarchicalExportLines = try namespaceBuilder.buildHierarchicalExportsType( + exportedSkeletons: exportedSkeletons, + renderClassEntry: { klass in + let (_, _, dtsExportEntry) = try self.renderExportedClass(klass) + return dtsExportEntry + }, + renderFunctionSignature: { function in + "\(function.name)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + } + ) printer.write("export type Exports = {") printer.indent { // Add non-namespaced items printer.write(lines: data.dtsExportLines) - // Add hierarchical namespaced items - let hierarchicalLines = namespaceBuilder.buildHierarchicalExportsType( - exportedSkeletons: exportedSkeletons, - renderClassEntry: { klass in - let printer = CodeFragmentPrinter() - printer.write("\(klass.name): {") - printer.indent { - if let constructor = klass.constructor { - printer.write( - "new\(self.renderTSSignature(parameters: constructor.parameters, returnType: .swiftHeapObject(klass.name), effects: constructor.effects));" - ) - } - // Static methods and static properties belong on the namespace - // entry alongside the constructor (same shape that - // `renderExportedClass` produces for non-namespaced classes via - // `dtsExportEntryPrinter`). - for method in klass.methods where method.effects.isStatic { - printer.write( - "\(method.name)\(self.renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" - ) - } - for property in klass.properties where property.isStatic { - let readonly = property.isReadonly ? "readonly " : "" - printer.write("\(readonly)\(property.name): \(property.type.tsType);") - } - } - printer.write("}") - return printer.lines - }, - renderFunctionSignature: { function in - "\(function.name)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" - } - ) - printer.write(lines: hierarchicalLines) + printer.write(lines: hierarchicalExportLines) } printer.write("}") @@ -1118,7 +1095,7 @@ public struct BridgeJSLink { } let data = try collectLinkData() let outputJs = try generateJavaScript(data: data) - let outputDts = generateTypeScript(data: data) + let outputDts = try generateTypeScript(data: data) return (outputJs, outputDts) } @@ -2670,16 +2647,16 @@ extension BridgeJSLink { fileprivate func buildHierarchicalExportsType( exportedSkeletons: [ExportedSkeleton], - renderClassEntry: (ExportedClass) -> [String], + renderClassEntry: (ExportedClass) throws -> [String], renderFunctionSignature: (ExportedFunction) -> String - ) -> [String] { + ) throws -> [String] { let printer = CodeFragmentPrinter() let rootNode = NamespaceNode(name: "") buildExportsTree(rootNode: rootNode, exportedSkeletons: exportedSkeletons) for (_, node) in rootNode.children { - populateTypeScriptExportLines( + try populateTypeScriptExportLines( node: node, renderClassEntry: renderClassEntry, renderFunctionSignature: renderFunctionSignature @@ -2693,16 +2670,16 @@ extension BridgeJSLink { private func populateTypeScriptExportLines( node: NamespaceNode, - renderClassEntry: (ExportedClass) -> [String], + renderClassEntry: (ExportedClass) throws -> [String], renderFunctionSignature: (ExportedFunction) -> String - ) { + ) throws { for function in node.content.functions { let signature = renderFunctionSignature(function) node.content.functionDtsLines.append((function.name, [signature])) } for klass in node.content.classes { - let entry = renderClassEntry(klass) + let entry = try renderClassEntry(klass) node.content.classDtsLines.append((klass.name, entry)) } @@ -2711,7 +2688,7 @@ extension BridgeJSLink { } for (_, childNode) in node.children { - populateTypeScriptExportLines( + try populateTypeScriptExportLines( node: childNode, renderClassEntry: renderClassEntry, renderFunctionSignature: renderFunctionSignature From d1ed18594a0a471332b2abca78ceb30ad18275a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 9 Apr 2026 14:07:34 +0200 Subject: [PATCH 29/68] BridgeJS: Add e2e test for static method and property on namespaced class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the existing `__Swift.Foundation.UUID` class (which already has an `@JS init` and an `@JS func`) with a static factory `fromValue(_:)` and a static readonly property `placeholder`, then asserts both are reachable via `exports.__Swift.Foundation.UUID.fromValue` and `exports.__Swift.Foundation.UUID.placeholder` in `prelude.mjs`. This is the e2e counterpart to the snapshot regression added in the previous commit — it proves the generated JavaScript actually routes calls to the correct static thunks at runtime, not just that the `.d.ts` types are well-formed. --- .../BridgeJSRuntimeTests/ExportAPITests.swift | 6 +++ .../Generated/BridgeJS.swift | 22 ++++++++++ .../Generated/JavaScript/BridgeJS.json | 44 +++++++++++++++++++ Tests/prelude.mjs | 7 +++ 4 files changed, 79 insertions(+) diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 3db9497fc..6bfa40d65 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -433,6 +433,12 @@ class UUID { @JS func uuidString() -> String { return value } + + @JS static func fromValue(_ value: String) -> UUID { + return UUID(value: value) + } + + @JS static var placeholder: String { "00000000-0000-0000-0000-000000000000" } } @JS func createUUID(value: String) -> UUID { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 71e5ef537..676d969ce 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -8602,6 +8602,28 @@ public func _bjs___Swift_Foundation_UUID_uuidString(_ _self: UnsafeMutableRawPoi #endif } +@_expose(wasm, "bjs___Swift_Foundation_UUID_static_fromValue") +@_cdecl("bjs___Swift_Foundation_UUID_static_fromValue") +public func _bjs___Swift_Foundation_UUID_static_fromValue(_ valueBytes: Int32, _ valueLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = UUID.fromValue(_: String.bridgeJSLiftParameter(valueBytes, valueLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs___Swift_Foundation_UUID_static_placeholder_get") +@_cdecl("bjs___Swift_Foundation_UUID_static_placeholder_get") +public func _bjs___Swift_Foundation_UUID_static_placeholder_get() -> Void { + #if arch(wasm32) + let ret = __Swift_Foundation_UUID.placeholder + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs___Swift_Foundation_UUID_deinit") @_cdecl("bjs___Swift_Foundation_UUID_deinit") public func _bjs___Swift_Foundation_UUID_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 60b02020d..46ae95a32 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -1108,6 +1108,36 @@ } } + }, + { + "abiName" : "bjs___Swift_Foundation_UUID_static_fromValue", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "fromValue", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "UUID" + } + }, + "staticContext" : { + "className" : { + "_0" : "__Swift_Foundation_UUID" + } + } } ], "name" : "UUID", @@ -1116,7 +1146,21 @@ "Foundation" ], "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "placeholder", + "staticContext" : { + "className" : { + "_0" : "__Swift_Foundation_UUID" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "UUID" }, diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index bb285aaee..1bc9ae101 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -624,6 +624,13 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { roundTrippedUUID.release(); uuid.release(); + // Static method and property on a namespaced class (@JS(namespace:) + @JS static). + // These must be callable via the namespace path, not as instance members. + const uuidFromStatic = exports.__Swift.Foundation.UUID.fromValue("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + assert.equal(uuidFromStatic.uuidString(), "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + uuidFromStatic.release(); + assert.equal(exports.__Swift.Foundation.UUID.placeholder, "00000000-0000-0000-0000-000000000000"); + const createdServer = exports.createHTTPServer(); createdServer.call(exports.Networking.API.Method.Get); createdServer.release(); From 575b2bfa62ffe1d2f4b48c064b924a89e5a21d16 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 9 Apr 2026 14:15:25 +0200 Subject: [PATCH 30/68] BridgeJS: Avoid double-rendering namespaced class DTS export entries `renderExportedClass` was being called twice for every namespaced class: once in `collectLinkData` (to produce the JS body and instance interface) and once more inside the `renderClassEntry` closure (to produce the export-entry for `buildHierarchicalExportsType`), with the JS and instance-interface outputs discarded on the second call. Store the `dtsExportEntry` slice in `LinkData.namespacedClassDtsExportEntries` during the single `collectLinkData` pass, keyed by class name. The `renderClassEntry` closure is now a non-throwing dictionary lookup, so `buildHierarchicalExportsType`, `populateTypeScriptExportLines`, and `generateTypeScript` revert to non-throwing. --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 26ed8387f..60b34ff16 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -130,6 +130,7 @@ public struct BridgeJSLink { var classLines: [String] = [] var dtsExportLines: [String] = [] var dtsClassLines: [String] = [] + var namespacedClassDtsExportEntries: [String: [String]] = [:] var topLevelTypeLines: [String] = [] var topLevelDtsTypeLines: [String] = [] var importObjectBuilders: [ImportObjectBuilder] = [] @@ -161,13 +162,14 @@ public struct BridgeJSLink { for klass in skeleton.classes { let (jsType, dtsType, dtsExportEntry) = try renderExportedClass(klass) data.classLines.append(contentsOf: jsType) + data.dtsClassLines.append(contentsOf: dtsType) if klass.namespace == nil { data.exportsLines.append("\(klass.name),") data.dtsExportLines.append(contentsOf: dtsExportEntry) + } else { + data.namespacedClassDtsExportEntries[klass.name] = dtsExportEntry } - - data.dtsClassLines.append(contentsOf: dtsType) } // Process enums - collect top-level definitions and export entries @@ -796,7 +798,7 @@ public struct BridgeJSLink { return printer.lines } - private func generateTypeScript(data: LinkData) throws -> String { + private func generateTypeScript(data: LinkData) -> String { let header = """ // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. @@ -884,11 +886,10 @@ public struct BridgeJSLink { printer.write(lines: generateImportedTypeDefinitions()) // Exports type - let hierarchicalExportLines = try namespaceBuilder.buildHierarchicalExportsType( + let hierarchicalExportLines = namespaceBuilder.buildHierarchicalExportsType( exportedSkeletons: exportedSkeletons, renderClassEntry: { klass in - let (_, _, dtsExportEntry) = try self.renderExportedClass(klass) - return dtsExportEntry + data.namespacedClassDtsExportEntries[klass.name] ?? [] }, renderFunctionSignature: { function in "\(function.name)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" @@ -1095,7 +1096,7 @@ public struct BridgeJSLink { } let data = try collectLinkData() let outputJs = try generateJavaScript(data: data) - let outputDts = try generateTypeScript(data: data) + let outputDts = generateTypeScript(data: data) return (outputJs, outputDts) } @@ -2647,16 +2648,16 @@ extension BridgeJSLink { fileprivate func buildHierarchicalExportsType( exportedSkeletons: [ExportedSkeleton], - renderClassEntry: (ExportedClass) throws -> [String], + renderClassEntry: (ExportedClass) -> [String], renderFunctionSignature: (ExportedFunction) -> String - ) throws -> [String] { + ) -> [String] { let printer = CodeFragmentPrinter() let rootNode = NamespaceNode(name: "") buildExportsTree(rootNode: rootNode, exportedSkeletons: exportedSkeletons) for (_, node) in rootNode.children { - try populateTypeScriptExportLines( + populateTypeScriptExportLines( node: node, renderClassEntry: renderClassEntry, renderFunctionSignature: renderFunctionSignature @@ -2670,16 +2671,16 @@ extension BridgeJSLink { private func populateTypeScriptExportLines( node: NamespaceNode, - renderClassEntry: (ExportedClass) throws -> [String], + renderClassEntry: (ExportedClass) -> [String], renderFunctionSignature: (ExportedFunction) -> String - ) throws { + ) { for function in node.content.functions { let signature = renderFunctionSignature(function) node.content.functionDtsLines.append((function.name, [signature])) } for klass in node.content.classes { - let entry = try renderClassEntry(klass) + let entry = renderClassEntry(klass) node.content.classDtsLines.append((klass.name, entry)) } @@ -2688,7 +2689,7 @@ extension BridgeJSLink { } for (_, childNode) in node.children { - try populateTypeScriptExportLines( + populateTypeScriptExportLines( node: childNode, renderClassEntry: renderClassEntry, renderFunctionSignature: renderFunctionSignature From 0d6544f95427d6c1689b4908f961c0d5f566d5aa Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Thu, 9 Apr 2026 14:46:49 +0200 Subject: [PATCH 31/68] relax swift-syntax version constraint to allow 603 (#714) * relax swift-syntax version constraint to allow 603 Packages are updating to 603 and this can fail the dependency solver. * .. and also test against it --- .github/workflows/test.yml | 2 ++ Package.swift | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e8118a481..c3c19b1c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -81,6 +81,8 @@ jobs: swift-syntax-version: "601.0.0" - image: "swift:6.2" swift-syntax-version: "602.0.0" + - image: "swift:6.3" + swift-syntax-version: "603.0.0" runs-on: ubuntu-latest container: image: ${{ matrix.entry.image }} diff --git a/Package.swift b/Package.swift index 20583865b..820524177 100644 --- a/Package.swift +++ b/Package.swift @@ -48,7 +48,7 @@ let package = Package( ], traits: [tracingTrait], dependencies: [ - .package(url: "https://github.com/swiftlang/swift-syntax", "600.0.0"..<"603.0.0") + .package(url: "https://github.com/swiftlang/swift-syntax", "600.0.0"..<"604.0.0") ], targets: [ .target( From 57c1fd8300cd888eee1ad965c395d51995ca1c5d Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 9 Apr 2026 15:53:08 +0200 Subject: [PATCH 32/68] BridgeJS: Fix static property call expression for namespaced classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Static properties on `@JS(namespace:)` classes used `property.callName()` to build the Swift call expression. That method consults `property.staticContext`, which is stored as `.className(abiName)` (e.g. `__Swift_Foundation_UUID`), and emits `\(abiName).\(propertyName)`. The ABI-mangled name is not a valid Swift identifier so the generated thunk failed to compile. Static methods were unaffected because `renderSingleExportedMethod` passes `klass.swiftCallName` directly. Fix `PropertyRenderingContext.callName(for:)` for the `.classStatic` case to bypass `property.callName()` and build the expression directly from `klass.swiftCallName`. This preserves the ABI symbol name (which still comes through `context.className` → `klass.abiName` → `property.getterAbiName(className:)`) while producing a valid Swift call expression in the thunk body. Also remove the now-unnecessary comment from `prelude.mjs` that described what the test was checking (the assertion itself is self-explanatory). --- Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift | 6 +++++- .../BridgeJSCodegenTests/Namespaces.Global.swift | 2 +- .../__Snapshots__/BridgeJSCodegenTests/Namespaces.swift | 2 +- Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift | 2 +- Tests/prelude.mjs | 2 -- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index ca7bdc3c2..9515fd7cf 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -433,7 +433,11 @@ public class ExportSwift { switch self { case .enumStatic(let enumDef): return property.callName(prefix: enumDef.swiftCallName) - case .classStatic, .classInstance: + case .classStatic(let klass): + // property.callName() would use staticContext (the ABI name) as prefix; + // use swiftCallName directly so the emitted expression is valid Swift. + return "\(klass.swiftCallName).\(property.name)" + case .classInstance: return property.callName() case .structStatic(let structDef): return property.callName(prefix: structDef.swiftCallName) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift index af7efbecd..baa867eed 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift @@ -57,7 +57,7 @@ public func _bjs___Swift_Foundation_Greeter_static_makeDefault() -> UnsafeMutabl @_cdecl("bjs___Swift_Foundation_Greeter_static_defaultGreeting_get") public func _bjs___Swift_Foundation_Greeter_static_defaultGreeting_get() -> Void { #if arch(wasm32) - let ret = __Swift_Foundation_Greeter.defaultGreeting + let ret = Greeter.defaultGreeting return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift index af7efbecd..baa867eed 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift @@ -57,7 +57,7 @@ public func _bjs___Swift_Foundation_Greeter_static_makeDefault() -> UnsafeMutabl @_cdecl("bjs___Swift_Foundation_Greeter_static_defaultGreeting_get") public func _bjs___Swift_Foundation_Greeter_static_defaultGreeting_get() -> Void { #if arch(wasm32) - let ret = __Swift_Foundation_Greeter.defaultGreeting + let ret = Greeter.defaultGreeting return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 676d969ce..c91ddb81e 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -8617,7 +8617,7 @@ public func _bjs___Swift_Foundation_UUID_static_fromValue(_ valueBytes: Int32, _ @_cdecl("bjs___Swift_Foundation_UUID_static_placeholder_get") public func _bjs___Swift_Foundation_UUID_static_placeholder_get() -> Void { #if arch(wasm32) - let ret = __Swift_Foundation_UUID.placeholder + let ret = UUID.placeholder return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 1bc9ae101..0af033226 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -624,8 +624,6 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { roundTrippedUUID.release(); uuid.release(); - // Static method and property on a namespaced class (@JS(namespace:) + @JS static). - // These must be callable via the namespace path, not as instance members. const uuidFromStatic = exports.__Swift.Foundation.UUID.fromValue("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); assert.equal(uuidFromStatic.uuidString(), "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); uuidFromStatic.release(); From ff90c3e911f68679fa39e885e42a4a438065e6fa Mon Sep 17 00:00:00 2001 From: William Taylor Date: Tue, 14 Apr 2026 15:58:24 +1000 Subject: [PATCH 33/68] BridgeJS: fix code generation for public enums (#719) --- .../Sources/BridgeJSCore/ExportSwift.swift | 4 +-- .../BridgeJSCodegenTests/ArrayTypes.swift | 4 +-- .../DefaultParameters.swift | 4 +-- .../EnumAssociatedValue.swift | 4 +-- .../BridgeJSCodegenTests/EnumCase.swift | 16 +++++------ .../EnumNamespace.Global.swift | 8 +++--- .../BridgeJSCodegenTests/EnumNamespace.swift | 8 +++--- .../BridgeJSCodegenTests/Protocol.swift | 4 +-- .../StaticFunctions.Global.swift | 4 +-- .../StaticFunctions.swift | 4 +-- .../StaticProperties.Global.swift | 4 +-- .../StaticProperties.swift | 4 +-- .../BridgeJSCodegenTests/SwiftClosure.swift | 4 +-- .../Generated/BridgeJS.swift | 8 +++--- .../BridgeJSRuntimeTests/ExportAPITests.swift | 2 +- .../Generated/BridgeJS.swift | 28 +++++++++---------- .../Generated/JavaScript/BridgeJS.json | 1 + 17 files changed, 56 insertions(+), 55 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 07c24dee7..b649b244d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -966,7 +966,7 @@ struct EnumCodegen { ) printer.nextLine() - printer.write("private init?(bridgeJSRawValue: Int32) {") + printer.write("@_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) {") printer.indent { printer.write("switch bridgeJSRawValue {") for (index, enumCase) in enumDef.cases.enumerated() { @@ -984,7 +984,7 @@ struct EnumCodegen { printer.write("}") printer.nextLine() - printer.write("private var bridgeJSRawValue: Int32 {") + printer.write("@_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 {") printer.indent { printer.write("switch self {") for (index, enumCase) in enumDef.cases.enumerated() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift index cf65635d9..a058d13a7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.swift @@ -12,7 +12,7 @@ extension Direction: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -27,7 +27,7 @@ extension Direction: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift index 4c527315b..507827646 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.swift @@ -12,7 +12,7 @@ extension Status: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .active @@ -25,7 +25,7 @@ extension Status: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .active: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift index 1112fb5a4..6d5549699 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.swift @@ -203,7 +203,7 @@ extension CardinalDirection: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -218,7 +218,7 @@ extension CardinalDirection: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift index 06c3e1cd8..66692ee14 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.swift @@ -12,7 +12,7 @@ extension Direction: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -27,7 +27,7 @@ extension Direction: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 @@ -55,7 +55,7 @@ extension Status: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .loading @@ -68,7 +68,7 @@ extension Status: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .loading: return 0 @@ -94,7 +94,7 @@ extension TSDirection: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -109,7 +109,7 @@ extension TSDirection: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 @@ -137,7 +137,7 @@ extension PublicStatus: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .success @@ -146,7 +146,7 @@ extension PublicStatus: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .success: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift index 1a8608246..5bde4ff93 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift @@ -12,7 +12,7 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -27,7 +27,7 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 @@ -61,7 +61,7 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -72,7 +72,7 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift index 1a8608246..5bde4ff93 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift @@ -12,7 +12,7 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -27,7 +27,7 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 @@ -61,7 +61,7 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -72,7 +72,7 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift index 745ec6cc9..e8df6c966 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.swift @@ -633,7 +633,7 @@ extension Direction: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -648,7 +648,7 @@ extension Direction: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index d329c7a96..896258915 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -12,7 +12,7 @@ extension Calculator: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .scientific @@ -23,7 +23,7 @@ extension Calculator: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .scientific: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index d329c7a96..896258915 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -12,7 +12,7 @@ extension Calculator: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .scientific @@ -23,7 +23,7 @@ extension Calculator: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .scientific: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift index faec8821b..ded55dbd4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.swift @@ -12,7 +12,7 @@ extension PropertyEnum: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .value1 @@ -23,7 +23,7 @@ extension PropertyEnum: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .value1: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift index faec8821b..ded55dbd4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.swift @@ -12,7 +12,7 @@ extension PropertyEnum: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .value1 @@ -23,7 +23,7 @@ extension PropertyEnum: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .value1: return 0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index 472987fee..348f9a788 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -1280,7 +1280,7 @@ extension Direction: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -1295,7 +1295,7 @@ extension Direction: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 diff --git a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift index 7816681da..862debbf0 100644 --- a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift @@ -21,7 +21,7 @@ extension GlobalNetworking.API.CallMethod: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -36,7 +36,7 @@ extension GlobalNetworking.API.CallMethod: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 @@ -70,7 +70,7 @@ extension Internal.SupportedServerMethod: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -81,7 +81,7 @@ extension Internal.SupportedServerMethod: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 6bfa40d65..2562fe18e 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -207,7 +207,7 @@ extension Greeter { // MARK: - Enum Tests -@JS enum Direction { +@JS public enum Direction { case north case south case east diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 13a0f08b7..a37a7e4c5 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -3868,7 +3868,7 @@ extension Direction: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -3883,7 +3883,7 @@ extension Direction: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 @@ -3911,7 +3911,7 @@ extension Status: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .loading @@ -3924,7 +3924,7 @@ extension Status: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .loading: return 0 @@ -3968,7 +3968,7 @@ extension TSDirection: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .north @@ -3983,7 +3983,7 @@ extension TSDirection: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .north: return 0 @@ -4036,7 +4036,7 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -4051,7 +4051,7 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 @@ -4085,7 +4085,7 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .get @@ -4096,7 +4096,7 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .get: return 0 @@ -4369,7 +4369,7 @@ extension StaticCalculator: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .scientific @@ -4380,7 +4380,7 @@ extension StaticCalculator: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .scientific: return 0 @@ -4470,7 +4470,7 @@ extension StaticPropertyEnum: _BridgedSwiftCaseEnum { return bridgeJSLowerParameter() } - private init?(bridgeJSRawValue: Int32) { + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { switch bridgeJSRawValue { case 0: self = .option1 @@ -4481,7 +4481,7 @@ extension StaticPropertyEnum: _BridgedSwiftCaseEnum { } } - private var bridgeJSRawValue: Int32 { + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { switch self { case .option1: return 0 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 46ae95a32..dd4362fc1 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -7235,6 +7235,7 @@ } ], "emitStyle" : "const", + "explicitAccessControl" : "public", "name" : "Direction", "staticMethods" : [ From 94f02c351b93d840e55b7ecbf4ae77f8a1cd5c6f Mon Sep 17 00:00:00 2001 From: Ken Tominaga Date: Tue, 21 Apr 2026 01:27:37 -0700 Subject: [PATCH 34/68] JavaScriptKit: import Android module for non-Wasm Android targets (#722) Building JavaScriptKit for the Swift 6.3 Android SDK triples (e.g. aarch64-unknown-linux-android28, x86_64-unknown-linux-android30) fails in ThreadLocal.swift with: error: cannot find 'pthread_key_create' in scope error: cannot find 'pthread_key_t' in scope Android uses Bionic, exposed to Swift as the `Android` module, rather than Glibc. The existing conditional falls through to `#error("Unsupported platform")` on Android. Add a `canImport(Android)` branch between the Darwin and Glibc branches, matching the pattern already used by Foundation and swift-corelibs-libdispatch. No Wasm, Darwin, or Glibc behavior changes. --- Sources/JavaScriptKit/ThreadLocal.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/JavaScriptKit/ThreadLocal.swift b/Sources/JavaScriptKit/ThreadLocal.swift index e92ca32ac..12bf78773 100644 --- a/Sources/JavaScriptKit/ThreadLocal.swift +++ b/Sources/JavaScriptKit/ThreadLocal.swift @@ -4,6 +4,8 @@ import wasi_pthread #endif #elseif canImport(Darwin) import Darwin +#elseif canImport(Android) +import Android #elseif canImport(Glibc) import Glibc #else From f458fb61483a0e713604814d11c7080f39f9148c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:28:46 +0100 Subject: [PATCH 35/68] Bump actions/upload-pages-artifact from 4 to 5 (#721) Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-pages-artifact/releases) - [Commits](https://github.com/actions/upload-pages-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-pages-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c3c19b1c4..baba9c79b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -185,7 +185,7 @@ jobs: - run: ./Utilities/prepare-gh-pages.sh - name: Upload static files as artifact id: deployment - uses: actions/upload-pages-artifact@v4 + uses: actions/upload-pages-artifact@v5 with: path: ./_site deploy-examples: From d70aaff9cc573a5209580fbc20f43afa19762938 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 22 Apr 2026 10:40:13 +0200 Subject: [PATCH 36/68] feat: Add opt-in pointer identity mode for SwiftHeapObject wrappers --- Benchmarks/README.md | 37 +- Benchmarks/Sources/Benchmarks.swift | 103 ++++ Benchmarks/Sources/Generated/BridgeJS.swift | 442 ++++++++++++++++ .../Generated/JavaScript/BridgeJS.json | 500 ++++++++++++++++++ Benchmarks/run.js | 98 +++- Package.swift | 12 + Package@swift-6.1.swift | 12 + .../BridgeJS/Sources/BridgeJSCore/Misc.swift | 17 +- .../BridgeJSCore/SwiftToSkeleton.swift | 24 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 77 ++- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 16 +- .../Sources/BridgeJSTool/BridgeJSTool.swift | 3 +- .../BridgeJSToolTests/BridgeJSLinkTests.swift | 49 ++ .../Inputs/MacroSwift/IdentityModeClass.swift | 28 + .../IdentityModeClass.json | 148 ++++++ .../IdentityModeClass.swift | 188 +++++++ .../BridgeJSLinkTests/ArrayTypes.js | 40 +- .../BridgeJSLinkTests/DefaultParameters.js | 42 +- .../BridgeJSLinkTests/DictionaryTypes.js | 38 +- .../BridgeJSLinkTests/EnumAssociatedValue.js | 38 +- .../BridgeJSLinkTests/EnumNamespace.Global.js | 44 +- .../BridgeJSLinkTests/EnumNamespace.js | 44 +- .../IdentityModeClass.ConfigPointer.d.ts | 42 ++ .../IdentityModeClass.ConfigPointer.js | 342 ++++++++++++ .../IdentityModeClass.PerClass.d.ts | 42 ++ .../IdentityModeClass.PerClass.js | 340 ++++++++++++ .../BridgeJSLinkTests/IdentityModeClass.d.ts | 42 ++ .../BridgeJSLinkTests/IdentityModeClass.js | 340 ++++++++++++ .../BridgeJSLinkTests/JSValue.js | 38 +- .../BridgeJSLinkTests/MixedGlobal.js | 38 +- .../BridgeJSLinkTests/MixedModules.js | 40 +- .../BridgeJSLinkTests/MixedPrivate.js | 38 +- .../BridgeJSLinkTests/Namespaces.Global.js | 44 +- .../BridgeJSLinkTests/Namespaces.js | 44 +- .../BridgeJSLinkTests/Optionals.js | 40 +- .../BridgeJSLinkTests/PropertyTypes.js | 38 +- .../BridgeJSLinkTests/Protocol.js | 42 +- .../BridgeJSLinkTests/ProtocolInClosure.js | 38 +- .../StaticFunctions.Global.js | 38 +- .../BridgeJSLinkTests/StaticFunctions.js | 38 +- .../StaticProperties.Global.js | 38 +- .../BridgeJSLinkTests/StaticProperties.js | 38 +- .../BridgeJSLinkTests/SwiftClass.js | 42 +- .../BridgeJSLinkTests/SwiftClosure.js | 40 +- .../BridgeJSLinkTests/SwiftStruct.js | 38 +- .../BridgeJS/BridgeJS-Configuration.md | 30 ++ .../Exporting-Swift/Exporting-Swift-Class.md | 40 ++ Sources/JavaScriptKit/Macros.swift | 3 +- .../Generated/BridgeJS.swift | 353 +++++++++++++ .../Generated/JavaScript/BridgeJS.json | 447 ++++++++++++++++ .../IdentityModeTests.swift | 113 ++++ .../JavaScript/IdentityModeTests.mjs | 200 +++++++ .../bridge-js.config.json | 3 + Tests/prelude.mjs | 2 + Utilities/bridge-js-generate.sh | 1 + 55 files changed, 4769 insertions(+), 243 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/IdentityModeClass.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js create mode 100644 Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift create mode 100644 Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json create mode 100644 Tests/BridgeJSIdentityTests/IdentityModeTests.swift create mode 100644 Tests/BridgeJSIdentityTests/JavaScript/IdentityModeTests.mjs create mode 100644 Tests/BridgeJSIdentityTests/bridge-js.config.json diff --git a/Benchmarks/README.md b/Benchmarks/README.md index 65d867eba..3d1a1cf22 100644 --- a/Benchmarks/README.md +++ b/Benchmarks/README.md @@ -4,8 +4,6 @@ This directory contains performance benchmarks for JavaScriptKit. ## Building Benchmarks -Before running the benchmarks, you need to build the test suite: - ```bash swift package --swift-sdk $SWIFT_SDK_ID js -c release ``` @@ -19,19 +17,38 @@ node run.js # Save results to a JSON file node run.js --output=results.json -# Specify number of iterations -node run.js --runs=20 - # Run in adaptive mode until results stabilize node run.js --adaptive --output=stable-results.json -# Run benchmarks and compare with previous results +# Compare with previous results node run.js --baseline=previous-results.json -# Run only a subset of benchmarks -# Substring match +# Filter benchmarks by name node run.js --filter=Call -# Regex (with flags) node run.js --filter=/^Property access\// -node run.js --filter=/string/i ``` + +## Identity Mode Benchmarks + +The benchmark suite includes identity-mode variants (`@JS(identityMode: true)`) of the core classes to measure pointer identity caching. Both variants are in the same build and run as regular benchmarks alongside everything else. + +```bash +# Run only identity benchmarks +node --expose-gc run.js --filter=Identity + +# Run only pointer-mode identity benchmarks +node --expose-gc run.js --filter=Identity/pointer + +# Run only non-identity baseline +node --expose-gc run.js --filter=Identity/none +``` + +### Identity Scenarios + +| Scenario | What it measures | +|----------|-----------------| +| `passBothWaysRoundtrip` | Same object crossing boundary repeatedly (cache hit path) | +| `getPoolRepeated_100` | Bulk return of 100 cached objects (model collection pattern) | +| `churnObjects` | Create, roundtrip, release cycle (FinalizationRegistry cleanup pressure) | +| `swiftConsumesSameObject` | JS passes same object to Swift repeatedly | +| `swiftCreatesObject` | Fresh object creation overhead (cache miss path) | diff --git a/Benchmarks/Sources/Benchmarks.swift b/Benchmarks/Sources/Benchmarks.swift index 59da8c96c..3e24e597b 100644 --- a/Benchmarks/Sources/Benchmarks.swift +++ b/Benchmarks/Sources/Benchmarks.swift @@ -257,6 +257,109 @@ enum ComplexResult { } } +// MARK: - Class Array Performance Tests + +nonisolated(unsafe) var _classArrayPool: [SimpleClass] = [] + +@JS class ClassArrayRoundtrip { + @JS init() {} + + @JS func setupPool(_ count: Int) { + _classArrayPool = (0.. [SimpleClass] { + return _classArrayPool + } + + @JS func makeClassArray() -> [SimpleClass] { + return (0..<100).map { + SimpleClass(name: "Item \($0)", count: $0, flag: true, rate: 0.5, precise: 3.14) + } + } + + @JS func takeClassArray(_ values: [SimpleClass]) {} + + @JS func roundtripClassArray(_ values: [SimpleClass]) -> [SimpleClass] { + return values + } +} + +// MARK: - Identity Cache Benchmark + +nonisolated(unsafe) var _cachedPool: [SimpleClass] = [] + +@JS class IdentityCacheBenchmark { + @JS init() {} + + @JS func setupPool(_ count: Int) { + _cachedPool = (0.. [SimpleClass] { + return _cachedPool + } +} + +// MARK: - Identity Mode Benchmark Variants +// These classes use @JS(identityMode: true) so that identity cache benchmarks +// can run in the SAME build alongside the non-identity classes above. + +@JS(identityMode: true) +class SimpleClassIdentity { + @JS var name: String + @JS var count: Int + @JS var flag: Bool + @JS var rate: Float + @JS var precise: Double + + @JS init(name: String, count: Int, flag: Bool, rate: Float, precise: Double) { + self.name = name + self.count = count + self.flag = flag + self.rate = rate + self.precise = precise + } +} + +@JS(identityMode: true) +class ClassRoundtripIdentity { + @JS init() {} + + @JS func roundtripSimpleClassIdentity(_ obj: SimpleClassIdentity) -> SimpleClassIdentity { + return obj + } + + @JS func makeSimpleClassIdentity() -> SimpleClassIdentity { + return SimpleClassIdentity(name: "Hello", count: 42, flag: true, rate: 0.5, precise: 3.14159) + } + + @JS func takeSimpleClassIdentity(_ obj: SimpleClassIdentity) { + // consume without returning + } +} + +nonisolated(unsafe) var _cachedPoolIdentity: [SimpleClassIdentity] = [] + +@JS(identityMode: true) +class IdentityCacheBenchmarkIdentity { + @JS init() {} + + @JS func setupPool(_ count: Int) { + _cachedPoolIdentity = (0.. [SimpleClassIdentity] { + return _cachedPoolIdentity + } +} + // MARK: - Array Performance Tests @JS struct Point { diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index c9adb2b1a..e199e4a29 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -1373,6 +1373,448 @@ fileprivate func _bjs_ClassRoundtrip_wrap_extern(_ pointer: UnsafeMutableRawPoin return _bjs_ClassRoundtrip_wrap_extern(pointer) } +@_expose(wasm, "bjs_ClassArrayRoundtrip_init") +@_cdecl("bjs_ClassArrayRoundtrip_init") +public func _bjs_ClassArrayRoundtrip_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ClassArrayRoundtrip() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassArrayRoundtrip_setupPool") +@_cdecl("bjs_ClassArrayRoundtrip_setupPool") +public func _bjs_ClassArrayRoundtrip_setupPool(_ _self: UnsafeMutableRawPointer, _ count: Int32) -> Void { + #if arch(wasm32) + ClassArrayRoundtrip.bridgeJSLiftParameter(_self).setupPool(_: Int.bridgeJSLiftParameter(count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassArrayRoundtrip_getPool") +@_cdecl("bjs_ClassArrayRoundtrip_getPool") +public func _bjs_ClassArrayRoundtrip_getPool(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = ClassArrayRoundtrip.bridgeJSLiftParameter(_self).getPool() + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassArrayRoundtrip_makeClassArray") +@_cdecl("bjs_ClassArrayRoundtrip_makeClassArray") +public func _bjs_ClassArrayRoundtrip_makeClassArray(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = ClassArrayRoundtrip.bridgeJSLiftParameter(_self).makeClassArray() + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassArrayRoundtrip_takeClassArray") +@_cdecl("bjs_ClassArrayRoundtrip_takeClassArray") +public func _bjs_ClassArrayRoundtrip_takeClassArray(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + ClassArrayRoundtrip.bridgeJSLiftParameter(_self).takeClassArray(_: [SimpleClass].bridgeJSStackPop()) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassArrayRoundtrip_roundtripClassArray") +@_cdecl("bjs_ClassArrayRoundtrip_roundtripClassArray") +public func _bjs_ClassArrayRoundtrip_roundtripClassArray(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = ClassArrayRoundtrip.bridgeJSLiftParameter(_self).roundtripClassArray(_: [SimpleClass].bridgeJSStackPop()) + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassArrayRoundtrip_deinit") +@_cdecl("bjs_ClassArrayRoundtrip_deinit") +public func _bjs_ClassArrayRoundtrip_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension ClassArrayRoundtrip: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassArrayRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClassArrayRoundtrip_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "Benchmarks", name: "bjs_ClassArrayRoundtrip_wrap") +fileprivate func _bjs_ClassArrayRoundtrip_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_ClassArrayRoundtrip_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_ClassArrayRoundtrip_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_ClassArrayRoundtrip_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_IdentityCacheBenchmark_init") +@_cdecl("bjs_IdentityCacheBenchmark_init") +public func _bjs_IdentityCacheBenchmark_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = IdentityCacheBenchmark() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityCacheBenchmark_setupPool") +@_cdecl("bjs_IdentityCacheBenchmark_setupPool") +public func _bjs_IdentityCacheBenchmark_setupPool(_ _self: UnsafeMutableRawPointer, _ count: Int32) -> Void { + #if arch(wasm32) + IdentityCacheBenchmark.bridgeJSLiftParameter(_self).setupPool(_: Int.bridgeJSLiftParameter(count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityCacheBenchmark_getPoolRepeated") +@_cdecl("bjs_IdentityCacheBenchmark_getPoolRepeated") +public func _bjs_IdentityCacheBenchmark_getPoolRepeated(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = IdentityCacheBenchmark.bridgeJSLiftParameter(_self).getPoolRepeated() + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityCacheBenchmark_deinit") +@_cdecl("bjs_IdentityCacheBenchmark_deinit") +public func _bjs_IdentityCacheBenchmark_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension IdentityCacheBenchmark: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_IdentityCacheBenchmark_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_IdentityCacheBenchmark_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "Benchmarks", name: "bjs_IdentityCacheBenchmark_wrap") +fileprivate func _bjs_IdentityCacheBenchmark_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_IdentityCacheBenchmark_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_IdentityCacheBenchmark_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_IdentityCacheBenchmark_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_SimpleClassIdentity_init") +@_cdecl("bjs_SimpleClassIdentity_init") +public func _bjs_SimpleClassIdentity_init(_ nameBytes: Int32, _ nameLength: Int32, _ count: Int32, _ flag: Int32, _ rate: Float32, _ precise: Float64) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = SimpleClassIdentity(name: String.bridgeJSLiftParameter(nameBytes, nameLength), count: Int.bridgeJSLiftParameter(count), flag: Bool.bridgeJSLiftParameter(flag), rate: Float.bridgeJSLiftParameter(rate), precise: Double.bridgeJSLiftParameter(precise)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_name_get") +@_cdecl("bjs_SimpleClassIdentity_name_get") +public func _bjs_SimpleClassIdentity_name_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SimpleClassIdentity.bridgeJSLiftParameter(_self).name + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_name_set") +@_cdecl("bjs_SimpleClassIdentity_name_set") +public func _bjs_SimpleClassIdentity_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + SimpleClassIdentity.bridgeJSLiftParameter(_self).name = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_count_get") +@_cdecl("bjs_SimpleClassIdentity_count_get") +public func _bjs_SimpleClassIdentity_count_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = SimpleClassIdentity.bridgeJSLiftParameter(_self).count + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_count_set") +@_cdecl("bjs_SimpleClassIdentity_count_set") +public func _bjs_SimpleClassIdentity_count_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + SimpleClassIdentity.bridgeJSLiftParameter(_self).count = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_flag_get") +@_cdecl("bjs_SimpleClassIdentity_flag_get") +public func _bjs_SimpleClassIdentity_flag_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = SimpleClassIdentity.bridgeJSLiftParameter(_self).flag + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_flag_set") +@_cdecl("bjs_SimpleClassIdentity_flag_set") +public func _bjs_SimpleClassIdentity_flag_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + SimpleClassIdentity.bridgeJSLiftParameter(_self).flag = Bool.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_rate_get") +@_cdecl("bjs_SimpleClassIdentity_rate_get") +public func _bjs_SimpleClassIdentity_rate_get(_ _self: UnsafeMutableRawPointer) -> Float32 { + #if arch(wasm32) + let ret = SimpleClassIdentity.bridgeJSLiftParameter(_self).rate + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_rate_set") +@_cdecl("bjs_SimpleClassIdentity_rate_set") +public func _bjs_SimpleClassIdentity_rate_set(_ _self: UnsafeMutableRawPointer, _ value: Float32) -> Void { + #if arch(wasm32) + SimpleClassIdentity.bridgeJSLiftParameter(_self).rate = Float.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_precise_get") +@_cdecl("bjs_SimpleClassIdentity_precise_get") +public func _bjs_SimpleClassIdentity_precise_get(_ _self: UnsafeMutableRawPointer) -> Float64 { + #if arch(wasm32) + let ret = SimpleClassIdentity.bridgeJSLiftParameter(_self).precise + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_precise_set") +@_cdecl("bjs_SimpleClassIdentity_precise_set") +public func _bjs_SimpleClassIdentity_precise_set(_ _self: UnsafeMutableRawPointer, _ value: Float64) -> Void { + #if arch(wasm32) + SimpleClassIdentity.bridgeJSLiftParameter(_self).precise = Double.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SimpleClassIdentity_deinit") +@_cdecl("bjs_SimpleClassIdentity_deinit") +public func _bjs_SimpleClassIdentity_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension SimpleClassIdentity: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_SimpleClassIdentity_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_SimpleClassIdentity_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "Benchmarks", name: "bjs_SimpleClassIdentity_wrap") +fileprivate func _bjs_SimpleClassIdentity_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_SimpleClassIdentity_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_SimpleClassIdentity_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_SimpleClassIdentity_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_ClassRoundtripIdentity_init") +@_cdecl("bjs_ClassRoundtripIdentity_init") +public func _bjs_ClassRoundtripIdentity_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ClassRoundtripIdentity() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassRoundtripIdentity_roundtripSimpleClassIdentity") +@_cdecl("bjs_ClassRoundtripIdentity_roundtripSimpleClassIdentity") +public func _bjs_ClassRoundtripIdentity_roundtripSimpleClassIdentity(_ _self: UnsafeMutableRawPointer, _ obj: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ClassRoundtripIdentity.bridgeJSLiftParameter(_self).roundtripSimpleClassIdentity(_: SimpleClassIdentity.bridgeJSLiftParameter(obj)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassRoundtripIdentity_makeSimpleClassIdentity") +@_cdecl("bjs_ClassRoundtripIdentity_makeSimpleClassIdentity") +public func _bjs_ClassRoundtripIdentity_makeSimpleClassIdentity(_ _self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ClassRoundtripIdentity.bridgeJSLiftParameter(_self).makeSimpleClassIdentity() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassRoundtripIdentity_takeSimpleClassIdentity") +@_cdecl("bjs_ClassRoundtripIdentity_takeSimpleClassIdentity") +public func _bjs_ClassRoundtripIdentity_takeSimpleClassIdentity(_ _self: UnsafeMutableRawPointer, _ obj: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + ClassRoundtripIdentity.bridgeJSLiftParameter(_self).takeSimpleClassIdentity(_: SimpleClassIdentity.bridgeJSLiftParameter(obj)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ClassRoundtripIdentity_deinit") +@_cdecl("bjs_ClassRoundtripIdentity_deinit") +public func _bjs_ClassRoundtripIdentity_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension ClassRoundtripIdentity: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_ClassRoundtripIdentity_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ClassRoundtripIdentity_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "Benchmarks", name: "bjs_ClassRoundtripIdentity_wrap") +fileprivate func _bjs_ClassRoundtripIdentity_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_ClassRoundtripIdentity_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_ClassRoundtripIdentity_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_ClassRoundtripIdentity_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_IdentityCacheBenchmarkIdentity_init") +@_cdecl("bjs_IdentityCacheBenchmarkIdentity_init") +public func _bjs_IdentityCacheBenchmarkIdentity_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = IdentityCacheBenchmarkIdentity() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityCacheBenchmarkIdentity_setupPool") +@_cdecl("bjs_IdentityCacheBenchmarkIdentity_setupPool") +public func _bjs_IdentityCacheBenchmarkIdentity_setupPool(_ _self: UnsafeMutableRawPointer, _ count: Int32) -> Void { + #if arch(wasm32) + IdentityCacheBenchmarkIdentity.bridgeJSLiftParameter(_self).setupPool(_: Int.bridgeJSLiftParameter(count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityCacheBenchmarkIdentity_getPoolRepeated") +@_cdecl("bjs_IdentityCacheBenchmarkIdentity_getPoolRepeated") +public func _bjs_IdentityCacheBenchmarkIdentity_getPoolRepeated(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = IdentityCacheBenchmarkIdentity.bridgeJSLiftParameter(_self).getPoolRepeated() + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityCacheBenchmarkIdentity_deinit") +@_cdecl("bjs_IdentityCacheBenchmarkIdentity_deinit") +public func _bjs_IdentityCacheBenchmarkIdentity_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension IdentityCacheBenchmarkIdentity: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_IdentityCacheBenchmarkIdentity_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_IdentityCacheBenchmarkIdentity_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "Benchmarks", name: "bjs_IdentityCacheBenchmarkIdentity_wrap") +fileprivate func _bjs_IdentityCacheBenchmarkIdentity_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_IdentityCacheBenchmarkIdentity_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_IdentityCacheBenchmarkIdentity_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_IdentityCacheBenchmarkIdentity_wrap_extern(pointer) +} + @_expose(wasm, "bjs_ArrayRoundtrip_init") @_cdecl("bjs_ArrayRoundtrip_init") public func _bjs_ArrayRoundtrip_init() -> UnsafeMutableRawPointer { diff --git a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json index b2c33ac01..0bddddfb6 100644 --- a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json +++ b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json @@ -1270,6 +1270,506 @@ ], "swiftCallName" : "ClassRoundtrip" }, + { + "constructor" : { + "abiName" : "bjs_ClassArrayRoundtrip_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + { + "abiName" : "bjs_ClassArrayRoundtrip_setupPool", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setupPool", + "parameters" : [ + { + "label" : "_", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_ClassArrayRoundtrip_getPool", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getPool", + "parameters" : [ + + ], + "returnType" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "SimpleClass" + } + } + } + } + }, + { + "abiName" : "bjs_ClassArrayRoundtrip_makeClassArray", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeClassArray", + "parameters" : [ + + ], + "returnType" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "SimpleClass" + } + } + } + } + }, + { + "abiName" : "bjs_ClassArrayRoundtrip_takeClassArray", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "takeClassArray", + "parameters" : [ + { + "label" : "_", + "name" : "values", + "type" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "SimpleClass" + } + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_ClassArrayRoundtrip_roundtripClassArray", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripClassArray", + "parameters" : [ + { + "label" : "_", + "name" : "values", + "type" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "SimpleClass" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "SimpleClass" + } + } + } + } + } + ], + "name" : "ClassArrayRoundtrip", + "properties" : [ + + ], + "swiftCallName" : "ClassArrayRoundtrip" + }, + { + "constructor" : { + "abiName" : "bjs_IdentityCacheBenchmark_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + { + "abiName" : "bjs_IdentityCacheBenchmark_setupPool", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setupPool", + "parameters" : [ + { + "label" : "_", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_IdentityCacheBenchmark_getPoolRepeated", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getPoolRepeated", + "parameters" : [ + + ], + "returnType" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "SimpleClass" + } + } + } + } + } + ], + "name" : "IdentityCacheBenchmark", + "properties" : [ + + ], + "swiftCallName" : "IdentityCacheBenchmark" + }, + { + "constructor" : { + "abiName" : "bjs_SimpleClassIdentity_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + }, + { + "label" : "count", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "label" : "flag", + "name" : "flag", + "type" : { + "bool" : { + + } + } + }, + { + "label" : "rate", + "name" : "rate", + "type" : { + "float" : { + + } + } + }, + { + "label" : "precise", + "name" : "precise", + "type" : { + "double" : { + + } + } + } + ] + }, + "identityMode" : true, + "methods" : [ + + ], + "name" : "SimpleClassIdentity", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "flag", + "type" : { + "bool" : { + + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "rate", + "type" : { + "float" : { + + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "precise", + "type" : { + "double" : { + + } + } + } + ], + "swiftCallName" : "SimpleClassIdentity" + }, + { + "constructor" : { + "abiName" : "bjs_ClassRoundtripIdentity_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "identityMode" : true, + "methods" : [ + { + "abiName" : "bjs_ClassRoundtripIdentity_roundtripSimpleClassIdentity", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripSimpleClassIdentity", + "parameters" : [ + { + "label" : "_", + "name" : "obj", + "type" : { + "swiftHeapObject" : { + "_0" : "SimpleClassIdentity" + } + } + } + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "SimpleClassIdentity" + } + } + }, + { + "abiName" : "bjs_ClassRoundtripIdentity_makeSimpleClassIdentity", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeSimpleClassIdentity", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "SimpleClassIdentity" + } + } + }, + { + "abiName" : "bjs_ClassRoundtripIdentity_takeSimpleClassIdentity", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "takeSimpleClassIdentity", + "parameters" : [ + { + "label" : "_", + "name" : "obj", + "type" : { + "swiftHeapObject" : { + "_0" : "SimpleClassIdentity" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + } + ], + "name" : "ClassRoundtripIdentity", + "properties" : [ + + ], + "swiftCallName" : "ClassRoundtripIdentity" + }, + { + "constructor" : { + "abiName" : "bjs_IdentityCacheBenchmarkIdentity_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "identityMode" : true, + "methods" : [ + { + "abiName" : "bjs_IdentityCacheBenchmarkIdentity_setupPool", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setupPool", + "parameters" : [ + { + "label" : "_", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_IdentityCacheBenchmarkIdentity_getPoolRepeated", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getPoolRepeated", + "parameters" : [ + + ], + "returnType" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "SimpleClassIdentity" + } + } + } + } + } + ], + "name" : "IdentityCacheBenchmarkIdentity", + "properties" : [ + + ], + "swiftCallName" : "IdentityCacheBenchmarkIdentity" + }, { "constructor" : { "abiName" : "bjs_ArrayRoundtrip_init", diff --git a/Benchmarks/run.js b/Benchmarks/run.js index 5a1ae61e6..444a33be0 100644 --- a/Benchmarks/run.js +++ b/Benchmarks/run.js @@ -282,7 +282,7 @@ async function singleRun(results, nameFilter, iterations) { return; } // Warmup to reduce JIT/IC noise. - body(); + body() if (typeof globalThis.gc === "function") { globalThis.gc(); } @@ -869,6 +869,96 @@ async function singleRun(results, nameFilter, iterations) { arrayRoundtrip.roundtripOptionalArray(null) } }) + + // Identity mode benchmarks - compare classes with and without @JS(identityMode: true) + + // Non-identity baseline (mode = "none") + const classRoundtripNone = new exports.ClassRoundtrip() + const baseObjNone = new exports.SimpleClass('Hello', 42, true, 0.5, 3.14159) + + benchmarkRunner("Identity/none/passBothWaysRoundtrip", () => { + let current = baseObjNone + for (let i = 0; i < iterations; i++) { + current = classRoundtripNone.roundtripSimpleClass(current) + } + }) + + benchmarkRunner("Identity/none/swiftCreatesObject", () => { + for (let i = 0; i < iterations; i++) { + classRoundtripNone.makeSimpleClass() + } + }) + + benchmarkRunner("Identity/none/swiftConsumesSameObject", () => { + for (let i = 0; i < iterations; i++) { + classRoundtripNone.takeSimpleClass(baseObjNone) + } + }) + + benchmarkRunner("Identity/none/churnObjects", () => { + for (let i = 0; i < iterations; i++) { + const obj = new exports.SimpleClass(`temp ${i}`, i, true, 0.5, 3.14159) + classRoundtripNone.roundtripSimpleClass(obj) + obj.release() + } + }) + + const identityCacheNone = new exports.IdentityCacheBenchmark() + identityCacheNone.setupPool(100) + identityCacheNone.getPoolRepeated() // warm the cache + benchmarkRunner("Identity/none/getPoolRepeated_100", () => { + for (let i = 0; i < Math.floor(iterations / 100); i++) { + identityCacheNone.getPoolRepeated() + } + }) + identityCacheNone.release() + + baseObjNone.release() + classRoundtripNone.release() + + // Identity mode (mode = "pointer") + const classRoundtripId = new exports.ClassRoundtripIdentity() + const baseObjId = new exports.SimpleClassIdentity('Hello', 42, true, 0.5, 3.14159) + + benchmarkRunner("Identity/pointer/passBothWaysRoundtrip", () => { + let current = baseObjId + for (let i = 0; i < iterations; i++) { + current = classRoundtripId.roundtripSimpleClassIdentity(current) + } + }) + + benchmarkRunner("Identity/pointer/swiftCreatesObject", () => { + for (let i = 0; i < iterations; i++) { + classRoundtripId.makeSimpleClassIdentity() + } + }) + + benchmarkRunner("Identity/pointer/swiftConsumesSameObject", () => { + for (let i = 0; i < iterations; i++) { + classRoundtripId.takeSimpleClassIdentity(baseObjId) + } + }) + + benchmarkRunner("Identity/pointer/churnObjects", () => { + for (let i = 0; i < iterations; i++) { + const obj = new exports.SimpleClassIdentity(`temp ${i}`, i, true, 0.5, 3.14159) + classRoundtripId.roundtripSimpleClassIdentity(obj) + obj.release() + } + }) + + const identityCacheId = new exports.IdentityCacheBenchmarkIdentity() + identityCacheId.setupPool(100) + identityCacheId.getPoolRepeated() // warm the cache + benchmarkRunner("Identity/pointer/getPoolRepeated_100", () => { + for (let i = 0; i < Math.floor(iterations / 100); i++) { + identityCacheId.getPoolRepeated() + } + }) + identityCacheId.release() + + baseObjId.release() + classRoundtripId.release() } /** @@ -984,7 +1074,7 @@ async function main() { 'min-runs': { type: 'string', default: '5' }, 'max-runs': { type: 'string', default: '50' }, 'target-cv': { type: 'string', default: '5' }, - filter: { type: 'string' } + filter: { type: 'string' }, } }); @@ -1017,7 +1107,7 @@ async function main() { console.log(`Results will be saved to: ${args.values.output}`); } - await runUntilStable(results, options, width, nameFilter, filterArg, iterations); + await runUntilStable(results, options, width, nameFilter, filterArg, iterations) } else { // Fixed number of runs mode const runs = parseInt(args.values.runs, 10); @@ -1039,7 +1129,7 @@ async function main() { console.log("\nOverall Progress:"); for (let i = 0; i < runs; i++) { updateProgress(i, runs, "Benchmark Runs:", width); - await singleRun(results, nameFilter, iterations); + await singleRun(results, nameFilter, iterations) if (i === 0 && Object.keys(results).length === 0) { process.stdout.write("\n"); console.error(`No benchmarks matched filter: ${filterArg}`); diff --git a/Package.swift b/Package.swift index 820524177..3d0f1e943 100644 --- a/Package.swift +++ b/Package.swift @@ -217,5 +217,17 @@ let package = Package( ], linkerSettings: testingLinkerFlags ), + .testTarget( + name: "BridgeJSIdentityTests", + dependencies: ["JavaScriptKit", "JavaScriptEventLoop"], + exclude: [ + "bridge-js.config.json", + "Generated/JavaScript", + ], + swiftSettings: [ + .enableExperimentalFeature("Extern") + ], + linkerSettings: testingLinkerFlags + ), ] ) diff --git a/Package@swift-6.1.swift b/Package@swift-6.1.swift index 60adb7a5f..fe98ec529 100644 --- a/Package@swift-6.1.swift +++ b/Package@swift-6.1.swift @@ -206,5 +206,17 @@ let package = Package( ], linkerSettings: testingLinkerFlags ), + .testTarget( + name: "BridgeJSIdentityTests", + dependencies: ["JavaScriptKit", "JavaScriptEventLoop"], + exclude: [ + "bridge-js.config.json", + "Generated/JavaScript", + ], + swiftSettings: [ + .enableExperimentalFeature("Extern") + ], + linkerSettings: testingLinkerFlags + ), ] ) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift index 06fb422a9..37040d7a6 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift @@ -342,20 +342,32 @@ public struct BridgeJSConfig: Codable { /// Default: `false` public var exposeToGlobal: Bool - public init(tools: [String: String]? = nil, exposeToGlobal: Bool = false) { + /// The identity mode to use for exported Swift heap objects. + /// + /// When `"pointer"`, Swift heap objects are tracked by pointer identity, + /// enabling identity-based caching. When `"none"` or `nil`, no identity + /// tracking is performed. + /// + /// Default: `nil` (treated as `"none"`) + public var identityMode: String? + + public init(tools: [String: String]? = nil, exposeToGlobal: Bool = false, identityMode: String? = nil) { self.tools = tools self.exposeToGlobal = exposeToGlobal + self.identityMode = identityMode } enum CodingKeys: String, CodingKey { case tools case exposeToGlobal + case identityMode } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) tools = try container.decodeIfPresent([String: String].self, forKey: .tools) exposeToGlobal = try container.decodeIfPresent(Bool.self, forKey: .exposeToGlobal) ?? false + identityMode = try container.decodeIfPresent(String.self, forKey: .identityMode) } /// Load the configuration file from the SwiftPM package target directory. @@ -398,7 +410,8 @@ public struct BridgeJSConfig: Codable { func merging(overrides: BridgeJSConfig) -> BridgeJSConfig { return BridgeJSConfig( tools: (tools ?? [:]).merging(overrides.tools ?? [:], uniquingKeysWith: { $1 }), - exposeToGlobal: overrides.exposeToGlobal + exposeToGlobal: overrides.exposeToGlobal, + identityMode: overrides.identityMode ?? identityMode ) } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 7b7c6ca30..3d8f417e3 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -16,14 +16,16 @@ public final class SwiftToSkeleton { public let progress: ProgressReporting public let moduleName: String public let exposeToGlobal: Bool + public let identityMode: String? private var sourceFiles: [(sourceFile: SourceFileSyntax, inputFilePath: String)] = [] let typeDeclResolver: TypeDeclResolver - public init(progress: ProgressReporting, moduleName: String, exposeToGlobal: Bool) { + public init(progress: ProgressReporting, moduleName: String, exposeToGlobal: Bool, identityMode: String? = nil) { self.progress = progress self.moduleName = moduleName self.exposeToGlobal = exposeToGlobal + self.identityMode = identityMode self.typeDeclResolver = TypeDeclResolver() // Index known types provided by JavaScriptKit @@ -42,7 +44,13 @@ public final class SwiftToSkeleton { public func finalize() throws -> BridgeJSSkeleton { var perSourceErrors: [(inputFilePath: String, errors: [DiagnosticError])] = [] var importedFiles: [ImportedFileSkeleton] = [] - var exported = ExportedSkeleton(functions: [], classes: [], enums: [], exposeToGlobal: exposeToGlobal) + var exported = ExportedSkeleton( + functions: [], + classes: [], + enums: [], + exposeToGlobal: exposeToGlobal, + identityMode: identityMode + ) var exportCollectors: [ExportSwiftAPICollector] = [] for (sourceFile, inputFilePath) in sourceFiles { @@ -1189,6 +1197,14 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return nil } + private func extractIdentityMode(from jsAttribute: AttributeSyntax) -> Bool? { + guard let arguments = jsAttribute.arguments?.as(LabeledExprListSyntax.self), + let identityArg = arguments.first(where: { $0.label?.text == "identityMode" }) + else { return nil } + let text = identityArg.expression.trimmedDescription + return text == "true" + } + override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren } @@ -1376,6 +1392,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { for: node, message: "Class visibility must be at least internal" ) + let classIdentityMode = extractIdentityMode(from: jsAttribute) let exportedClass = ExportedClass( name: name, swiftCallName: swiftCallName, @@ -1383,7 +1400,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { constructor: nil, methods: [], properties: [], - namespace: namespaceResult.namespace + namespace: namespaceResult.namespace, + identityMode: classIdentityMode ) let uniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 60b34ff16..64a0d2394 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -25,6 +25,21 @@ public struct BridgeJSLink { self.sharedMemory = sharedMemory } + /// The identity mode from the config file, resolved from skeletons. + var configIdentityMode: String { + skeletons.compactMap(\.exported).compactMap(\.identityMode).first ?? "none" + } + + /// 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 + if let classOverride = klass.identityMode { + return classOverride + } + // Fall back to config default + return configIdentityMode == "pointer" + } + mutating func addSkeletonFile(data: Data) throws { do { let unified = try JSONDecoder().decode(BridgeJSSkeleton.self, from: data) @@ -85,31 +100,52 @@ public struct BridgeJSLink { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; + static __wrap(pointer, deinit, prototype, identityCache) { + const makeFresh = (identityMap) => { + const obj = Object.create(prototype); + const state = { pointer, deinit, hasReleased: false, identityMap }; """ if enableLifetimeTracking { - output += " TRACKING.wrap(pointer, deinit, prototype, state);\n" + output += " TRACKING.wrap(pointer, deinit, prototype, state);\n" } output += """ - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + 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() { """ if enableLifetimeTracking { - output += " TRACKING.release(this);\n" + output += " TRACKING.release(this);\n" } output += """ const state = this.__swiftHeapObjectState; @@ -118,6 +154,7 @@ public struct BridgeJSLink { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } @@ -1965,13 +2002,24 @@ extension BridgeJSLink { dtsExportEntryPrinter.write("\(klass.name): {") jsPrinter.write("class \(klass.name) extends SwiftHeapObject {") - // Always add __construct and constructor methods for all classes + // Per-class identity mode: determine at codegen time whether this class uses identity caching + let useIdentity = shouldUseIdentityCache(for: klass) jsPrinter.indent { + if useIdentity { + jsPrinter.write("static __identityCache = new Map();") + jsPrinter.nextLine() + } jsPrinter.write("static __construct(ptr) {") jsPrinter.indent { - jsPrinter.write( - "return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_\(klass.abiName)_deinit, \(klass.name).prototype);" - ) + if useIdentity { + jsPrinter.write( + "return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_\(klass.abiName)_deinit, \(klass.name).prototype, \(klass.name).__identityCache);" + ) + } else { + jsPrinter.write( + "return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_\(klass.abiName)_deinit, \(klass.name).prototype, null);" + ) + } } jsPrinter.write("}") jsPrinter.nextLine() @@ -1991,10 +2039,11 @@ extension BridgeJSLink { jsPrinter.indent { jsPrinter.write("constructor(\(constructorParamList)) {") let returnExpr = thunkBuilder.callConstructor(abiName: constructor.abiName) + let constructCall = "\(klass.name).__construct(\(returnExpr))" jsPrinter.indent { thunkBuilder.renderFunctionBody( into: jsPrinter, - returnExpr: "\(klass.name).__construct(\(returnExpr))" + returnExpr: constructCall ) } jsPrinter.write("}") diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index c5672c79c..03e6d676a 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -784,6 +784,7 @@ public struct ExportedClass: Codable, NamespacedExportedType { public var methods: [ExportedFunction] public var properties: [ExportedProperty] public var namespace: [String]? + public var identityMode: Bool? // nil = use config default, true/false = override public init( name: String, @@ -792,7 +793,8 @@ public struct ExportedClass: Codable, NamespacedExportedType { constructor: ExportedConstructor? = nil, methods: [ExportedFunction], properties: [ExportedProperty] = [], - namespace: [String]? = nil + namespace: [String]? = nil, + identityMode: Bool? = nil ) { self.name = name self.swiftCallName = swiftCallName @@ -801,6 +803,7 @@ public struct ExportedClass: Codable, NamespacedExportedType { self.methods = methods self.properties = properties self.namespace = namespace + self.identityMode = identityMode } } @@ -890,13 +893,20 @@ public struct ExportedSkeleton: Codable { /// through the exports object. public var exposeToGlobal: Bool + /// The identity mode for exported Swift heap objects. + /// + /// When `"pointer"`, Swift heap objects are tracked by pointer identity. + /// When `"none"` or `nil`, no identity tracking is performed. + public var identityMode: String? + public init( functions: [ExportedFunction], classes: [ExportedClass], enums: [ExportedEnum], structs: [ExportedStruct] = [], protocols: [ExportedProtocol] = [], - exposeToGlobal: Bool + exposeToGlobal: Bool, + identityMode: String? = nil ) { self.functions = functions self.classes = classes @@ -904,6 +914,7 @@ public struct ExportedSkeleton: Codable { self.structs = structs self.protocols = protocols self.exposeToGlobal = exposeToGlobal + self.identityMode = identityMode } public mutating func append(_ other: ExportedSkeleton) { @@ -913,6 +924,7 @@ public struct ExportedSkeleton: Codable { self.structs.append(contentsOf: other.structs) self.protocols.append(contentsOf: other.protocols) assert(self.exposeToGlobal == other.exposeToGlobal) + assert(self.identityMode == other.identityMode) } public var isEmpty: Bool { diff --git a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift index a71aaee44..3e3f27ea1 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift @@ -165,7 +165,8 @@ import BridgeJSUtilities let swiftToSkeleton = SwiftToSkeleton( progress: progress, moduleName: moduleName, - exposeToGlobal: config.exposeToGlobal + exposeToGlobal: config.exposeToGlobal, + identityMode: config.identityMode ) for inputFile in inputFiles.sorted() { try withSpan("Parsing \(inputFile)") { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index 711b04512..64c9ae535 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -105,4 +105,53 @@ import Testing ) try snapshot(bridgeJSLink: bridgeJSLink, name: "MixedModules") } + + @Test + func perClassIdentityModeFromAnnotation() throws { + let url = Self.inputsDirectory.appendingPathComponent("IdentityModeClass.swift") + let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + identityMode: nil // no config default + ) + swiftAPI.addSourceFile(sourceFile, inputFilePath: "IdentityModeClass.swift") + let outputSkeleton = try swiftAPI.finalize() + + // Verify skeleton has per-class identity mode (not captured by snapshots) + let cachedClass = outputSkeleton.exported!.classes.first { $0.name == "CachedModel" } + let uncachedClass = outputSkeleton.exported!.classes.first { $0.name == "UncachedModel" } + let explicitlyUncachedClass = outputSkeleton.exported!.classes.first { $0.name == "ExplicitlyUncachedModel" } + #expect(cachedClass?.identityMode == true) + #expect(uncachedClass?.identityMode == nil) + #expect(explicitlyUncachedClass?.identityMode == false) + + // Verify generated JS via snapshot + let bridgeJSLink = BridgeJSLink(skeletons: [outputSkeleton], sharedMemory: false) + try snapshot(bridgeJSLink: bridgeJSLink, name: "IdentityModeClass.PerClass") + } + + @Test + func perClassIdentityModeWithConfigOverride() throws { + let url = Self.inputsDirectory.appendingPathComponent("IdentityModeClass.swift") + let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + identityMode: "pointer" // config says pointer for all classes + ) + swiftAPI.addSourceFile(sourceFile, inputFilePath: "IdentityModeClass.swift") + let outputSkeleton = try swiftAPI.finalize() + + // When config says "pointer", classes without annotation get identity mode from config. + // But @JS(identityMode: false) should still override to "without identity". + let explicitlyUncachedClass = outputSkeleton.exported!.classes.first { $0.name == "ExplicitlyUncachedModel" } + #expect(explicitlyUncachedClass?.identityMode == false) + + // Verify generated JS via snapshot + let bridgeJSLink = BridgeJSLink(skeletons: [outputSkeleton], sharedMemory: false) + try snapshot(bridgeJSLink: bridgeJSLink, name: "IdentityModeClass.ConfigPointer") + } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/IdentityModeClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/IdentityModeClass.swift new file mode 100644 index 000000000..4d50b6c76 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/IdentityModeClass.swift @@ -0,0 +1,28 @@ +import JavaScriptKit + +@JS(identityMode: true) +class CachedModel { + @JS var name: String + + @JS init(name: String) { + self.name = name + } +} + +@JS +class UncachedModel { + @JS var value: Int + + @JS init(value: Int) { + self.value = value + } +} + +@JS(identityMode: false) +class ExplicitlyUncachedModel { + @JS var count: Int + + @JS init(count: Int) { + self.count = count + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json new file mode 100644 index 000000000..d7a9064dc --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json @@ -0,0 +1,148 @@ +{ + "exported" : { + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_CachedModel_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "identityMode" : true, + "methods" : [ + + ], + "name" : "CachedModel", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "CachedModel" + }, + { + "constructor" : { + "abiName" : "bjs_UncachedModel_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "UncachedModel", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "UncachedModel" + }, + { + "constructor" : { + "abiName" : "bjs_ExplicitlyUncachedModel_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "count", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "identityMode" : false, + "methods" : [ + + ], + "name" : "ExplicitlyUncachedModel", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "ExplicitlyUncachedModel" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.swift new file mode 100644 index 000000000..a79b91d56 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.swift @@ -0,0 +1,188 @@ +@_expose(wasm, "bjs_CachedModel_init") +@_cdecl("bjs_CachedModel_init") +public func _bjs_CachedModel_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = CachedModel(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_CachedModel_name_get") +@_cdecl("bjs_CachedModel_name_get") +public func _bjs_CachedModel_name_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = CachedModel.bridgeJSLiftParameter(_self).name + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_CachedModel_name_set") +@_cdecl("bjs_CachedModel_name_set") +public func _bjs_CachedModel_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + CachedModel.bridgeJSLiftParameter(_self).name = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_CachedModel_deinit") +@_cdecl("bjs_CachedModel_deinit") +public func _bjs_CachedModel_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension CachedModel: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_CachedModel_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_CachedModel_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_CachedModel_wrap") +fileprivate func _bjs_CachedModel_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_CachedModel_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_CachedModel_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_CachedModel_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_UncachedModel_init") +@_cdecl("bjs_UncachedModel_init") +public func _bjs_UncachedModel_init(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = UncachedModel(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_UncachedModel_value_get") +@_cdecl("bjs_UncachedModel_value_get") +public func _bjs_UncachedModel_value_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = UncachedModel.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_UncachedModel_value_set") +@_cdecl("bjs_UncachedModel_value_set") +public func _bjs_UncachedModel_value_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + UncachedModel.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_UncachedModel_deinit") +@_cdecl("bjs_UncachedModel_deinit") +public func _bjs_UncachedModel_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension UncachedModel: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_UncachedModel_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_UncachedModel_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_UncachedModel_wrap") +fileprivate func _bjs_UncachedModel_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_UncachedModel_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_UncachedModel_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_UncachedModel_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_ExplicitlyUncachedModel_init") +@_cdecl("bjs_ExplicitlyUncachedModel_init") +public func _bjs_ExplicitlyUncachedModel_init(_ count: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ExplicitlyUncachedModel(count: Int.bridgeJSLiftParameter(count)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ExplicitlyUncachedModel_count_get") +@_cdecl("bjs_ExplicitlyUncachedModel_count_get") +public func _bjs_ExplicitlyUncachedModel_count_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = ExplicitlyUncachedModel.bridgeJSLiftParameter(_self).count + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ExplicitlyUncachedModel_count_set") +@_cdecl("bjs_ExplicitlyUncachedModel_count_set") +public func _bjs_ExplicitlyUncachedModel_count_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + ExplicitlyUncachedModel.bridgeJSLiftParameter(_self).count = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ExplicitlyUncachedModel_deinit") +@_cdecl("bjs_ExplicitlyUncachedModel_deinit") +public func _bjs_ExplicitlyUncachedModel_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension ExplicitlyUncachedModel: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_ExplicitlyUncachedModel_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ExplicitlyUncachedModel_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_ExplicitlyUncachedModel_wrap") +fileprivate func _bjs_ExplicitlyUncachedModel_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_ExplicitlyUncachedModel_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_ExplicitlyUncachedModel_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_ExplicitlyUncachedModel_wrap_extern(pointer) +} \ 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 85e9c749a..8359220c9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -348,18 +348,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -369,18 +390,19 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Item extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Item_deinit, Item.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Item_deinit, Item.prototype, null); } } class MultiArrayContainer extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MultiArrayContainer_deinit, MultiArrayContainer.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MultiArrayContainer_deinit, MultiArrayContainer.prototype, null); } constructor(nums, strs) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index 004320e4b..cafd250b0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -279,18 +279,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -300,12 +321,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class DefaultGreeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_DefaultGreeter_deinit, DefaultGreeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_DefaultGreeter_deinit, DefaultGreeter.prototype, null); } constructor(name) { @@ -328,7 +350,7 @@ export async function createInstantiator(options, swift) { } class EmptyGreeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_EmptyGreeter_deinit, EmptyGreeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_EmptyGreeter_deinit, EmptyGreeter.prototype, null); } constructor() { @@ -338,7 +360,7 @@ export async function createInstantiator(options, swift) { } class ConstructorDefaults extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_ConstructorDefaults_deinit, ConstructorDefaults.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_ConstructorDefaults_deinit, ConstructorDefaults.prototype, null); } constructor(name = "Default", count = 42, enabled = true, status = StatusValues.Active, tag = null) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index b6cf2c253..920017972 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -288,18 +288,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -309,12 +330,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Box extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Box_deinit, Box.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Box_deinit, Box.prototype, null); } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index eb474d3b0..3d2230c6c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -955,18 +955,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -976,12 +997,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class User extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_User_deinit, User.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_User_deinit, User.prototype, null); } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index 948039cf9..10fe31f64 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -271,18 +271,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -292,12 +313,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Converter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converter_deinit, Converter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converter_deinit, Converter.prototype, null); } constructor() { @@ -320,7 +342,7 @@ export async function createInstantiator(options, swift) { } class HTTPServer extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_API_HTTPServer_deinit, HTTPServer.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_API_HTTPServer_deinit, HTTPServer.prototype, null); } constructor() { @@ -333,7 +355,7 @@ export async function createInstantiator(options, swift) { } class TestServer extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_APIV2_Internal_TestServer_deinit, TestServer.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_APIV2_Internal_TestServer_deinit, TestServer.prototype, null); } constructor() { @@ -346,7 +368,7 @@ export async function createInstantiator(options, swift) { } class Converter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Formatting_Converter_deinit, Converter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Formatting_Converter_deinit, Converter.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index 5201350b2..a6aeee4b0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -252,18 +252,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -273,12 +294,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Converter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converter_deinit, Converter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converter_deinit, Converter.prototype, null); } constructor() { @@ -301,7 +323,7 @@ export async function createInstantiator(options, swift) { } class HTTPServer extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_API_HTTPServer_deinit, HTTPServer.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_API_HTTPServer_deinit, HTTPServer.prototype, null); } constructor() { @@ -314,7 +336,7 @@ export async function createInstantiator(options, swift) { } class TestServer extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_APIV2_Internal_TestServer_deinit, TestServer.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Networking_APIV2_Internal_TestServer_deinit, TestServer.prototype, null); } constructor() { @@ -327,7 +349,7 @@ export async function createInstantiator(options, swift) { } class Converter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Formatting_Converter_deinit, Converter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Formatting_Converter_deinit, Converter.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts new file mode 100644 index 000000000..e5e2a3a84 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.d.ts @@ -0,0 +1,42 @@ +// 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`. + +/// 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 CachedModel extends SwiftHeapObject { + name: string; +} +export interface UncachedModel extends SwiftHeapObject { + value: number; +} +export interface ExplicitlyUncachedModel extends SwiftHeapObject { + count: number; +} +export type Exports = { + CachedModel: { + new(name: string): CachedModel; + } + UncachedModel: { + new(value: number): UncachedModel; + } + ExplicitlyUncachedModel: { + new(count: number): ExplicitlyUncachedModel; + } +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js new file mode 100644 index 000000000..c2490c0ea --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js @@ -0,0 +1,342 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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(); + } + 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_CachedModel_wrap"] = function(pointer) { + const obj = _exports['CachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_ExplicitlyUncachedModel_wrap"] = function(pointer) { + const obj = _exports['ExplicitlyUncachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_UncachedModel_wrap"] = function(pointer) { + const obj = _exports['UncachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + }, + 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) + } + }, + /** @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) { + 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 CachedModel extends SwiftHeapObject { + static __identityCache = new Map(); + + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_CachedModel_deinit, CachedModel.prototype, CachedModel.__identityCache); + } + + constructor(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const ret = instance.exports.bjs_CachedModel_init(nameId, nameBytes.length); + return CachedModel.__construct(ret); + } + get name() { + instance.exports.bjs_CachedModel_name_get(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + set name(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_CachedModel_name_set(this.pointer, valueId, valueBytes.length); + } + } + class UncachedModel extends SwiftHeapObject { + static __identityCache = new Map(); + + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_UncachedModel_deinit, UncachedModel.prototype, UncachedModel.__identityCache); + } + + constructor(value) { + const ret = instance.exports.bjs_UncachedModel_init(value); + return UncachedModel.__construct(ret); + } + get value() { + const ret = instance.exports.bjs_UncachedModel_value_get(this.pointer); + return ret; + } + set value(value) { + instance.exports.bjs_UncachedModel_value_set(this.pointer, value); + } + } + class ExplicitlyUncachedModel extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_ExplicitlyUncachedModel_deinit, ExplicitlyUncachedModel.prototype, null); + } + + constructor(count) { + const ret = instance.exports.bjs_ExplicitlyUncachedModel_init(count); + return ExplicitlyUncachedModel.__construct(ret); + } + get count() { + const ret = instance.exports.bjs_ExplicitlyUncachedModel_count_get(this.pointer); + return ret; + } + set count(value) { + instance.exports.bjs_ExplicitlyUncachedModel_count_set(this.pointer, value); + } + } + const exports = { + CachedModel, + UncachedModel, + ExplicitlyUncachedModel, + }; + _exports = exports; + return 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 new file mode 100644 index 000000000..e5e2a3a84 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.d.ts @@ -0,0 +1,42 @@ +// 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`. + +/// 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 CachedModel extends SwiftHeapObject { + name: string; +} +export interface UncachedModel extends SwiftHeapObject { + value: number; +} +export interface ExplicitlyUncachedModel extends SwiftHeapObject { + count: number; +} +export type Exports = { + CachedModel: { + new(name: string): CachedModel; + } + UncachedModel: { + new(value: number): UncachedModel; + } + ExplicitlyUncachedModel: { + new(count: number): ExplicitlyUncachedModel; + } +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js new file mode 100644 index 000000000..d970c5d77 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js @@ -0,0 +1,340 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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(); + } + 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_CachedModel_wrap"] = function(pointer) { + const obj = _exports['CachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_ExplicitlyUncachedModel_wrap"] = function(pointer) { + const obj = _exports['ExplicitlyUncachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_UncachedModel_wrap"] = function(pointer) { + const obj = _exports['UncachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + }, + 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) + } + }, + /** @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) { + 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 CachedModel extends SwiftHeapObject { + static __identityCache = new Map(); + + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_CachedModel_deinit, CachedModel.prototype, CachedModel.__identityCache); + } + + constructor(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const ret = instance.exports.bjs_CachedModel_init(nameId, nameBytes.length); + return CachedModel.__construct(ret); + } + get name() { + instance.exports.bjs_CachedModel_name_get(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + set name(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_CachedModel_name_set(this.pointer, valueId, valueBytes.length); + } + } + class UncachedModel extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_UncachedModel_deinit, UncachedModel.prototype, null); + } + + constructor(value) { + const ret = instance.exports.bjs_UncachedModel_init(value); + return UncachedModel.__construct(ret); + } + get value() { + const ret = instance.exports.bjs_UncachedModel_value_get(this.pointer); + return ret; + } + set value(value) { + instance.exports.bjs_UncachedModel_value_set(this.pointer, value); + } + } + class ExplicitlyUncachedModel extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_ExplicitlyUncachedModel_deinit, ExplicitlyUncachedModel.prototype, null); + } + + constructor(count) { + const ret = instance.exports.bjs_ExplicitlyUncachedModel_init(count); + return ExplicitlyUncachedModel.__construct(ret); + } + get count() { + const ret = instance.exports.bjs_ExplicitlyUncachedModel_count_get(this.pointer); + return ret; + } + set count(value) { + instance.exports.bjs_ExplicitlyUncachedModel_count_set(this.pointer, value); + } + } + const exports = { + CachedModel, + UncachedModel, + ExplicitlyUncachedModel, + }; + _exports = exports; + return 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 new file mode 100644 index 000000000..e5e2a3a84 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.d.ts @@ -0,0 +1,42 @@ +// 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`. + +/// 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 CachedModel extends SwiftHeapObject { + name: string; +} +export interface UncachedModel extends SwiftHeapObject { + value: number; +} +export interface ExplicitlyUncachedModel extends SwiftHeapObject { + count: number; +} +export type Exports = { + CachedModel: { + new(name: string): CachedModel; + } + UncachedModel: { + new(value: number): UncachedModel; + } + ExplicitlyUncachedModel: { + new(count: number): ExplicitlyUncachedModel; + } +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js new file mode 100644 index 000000000..d970c5d77 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js @@ -0,0 +1,340 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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(); + } + 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_CachedModel_wrap"] = function(pointer) { + const obj = _exports['CachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_ExplicitlyUncachedModel_wrap"] = function(pointer) { + const obj = _exports['ExplicitlyUncachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_UncachedModel_wrap"] = function(pointer) { + const obj = _exports['UncachedModel'].__construct(pointer); + return swift.memory.retain(obj); + }; + }, + 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) + } + }, + /** @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) { + 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 CachedModel extends SwiftHeapObject { + static __identityCache = new Map(); + + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_CachedModel_deinit, CachedModel.prototype, CachedModel.__identityCache); + } + + constructor(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const ret = instance.exports.bjs_CachedModel_init(nameId, nameBytes.length); + return CachedModel.__construct(ret); + } + get name() { + instance.exports.bjs_CachedModel_name_get(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + set name(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_CachedModel_name_set(this.pointer, valueId, valueBytes.length); + } + } + class UncachedModel extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_UncachedModel_deinit, UncachedModel.prototype, null); + } + + constructor(value) { + const ret = instance.exports.bjs_UncachedModel_init(value); + return UncachedModel.__construct(ret); + } + get value() { + const ret = instance.exports.bjs_UncachedModel_value_get(this.pointer); + return ret; + } + set value(value) { + instance.exports.bjs_UncachedModel_value_set(this.pointer, value); + } + } + class ExplicitlyUncachedModel extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_ExplicitlyUncachedModel_deinit, ExplicitlyUncachedModel.prototype, null); + } + + constructor(count) { + const ret = instance.exports.bjs_ExplicitlyUncachedModel_init(count); + return ExplicitlyUncachedModel.__construct(ret); + } + get count() { + const ret = instance.exports.bjs_ExplicitlyUncachedModel_count_get(this.pointer); + return ret; + } + set count(value) { + instance.exports.bjs_ExplicitlyUncachedModel_count_set(this.pointer, value); + } + } + const exports = { + CachedModel, + UncachedModel, + ExplicitlyUncachedModel, + }; + _exports = exports; + return 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 08675da6a..0258b63b6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -342,18 +342,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -363,12 +384,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class JSValueHolder extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_JSValueHolder_deinit, JSValueHolder.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_JSValueHolder_deinit, JSValueHolder.prototype, null); } constructor(value, optionalValue) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index f4fe4dd61..195eef468 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -215,18 +215,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -236,12 +257,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class GlobalClass extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_GlobalAPI_GlobalClass_deinit, GlobalClass.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_GlobalAPI_GlobalClass_deinit, GlobalClass.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index 4ce318f40..ca54493f6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -223,18 +223,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -244,12 +265,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class GlobalClass extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_GlobalAPI_GlobalClass_deinit, GlobalClass.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_GlobalAPI_GlobalClass_deinit, GlobalClass.prototype, null); } constructor() { @@ -265,7 +287,7 @@ export async function createInstantiator(options, swift) { } class PrivateClass extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PrivateAPI_PrivateClass_deinit, PrivateClass.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PrivateAPI_PrivateClass_deinit, PrivateClass.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index 025a6fc8a..3551caab2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -215,18 +215,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -236,12 +257,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class PrivateClass extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PrivateAPI_PrivateClass_deinit, PrivateClass.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PrivateAPI_PrivateClass_deinit, PrivateClass.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index f4596dba7..a63df44be 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -227,18 +227,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -248,12 +269,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Greeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_Greeter_deinit, Greeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_Greeter_deinit, Greeter.prototype, null); } constructor(name) { @@ -281,7 +303,7 @@ export async function createInstantiator(options, swift) { } class Converter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converters_Converter_deinit, Converter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converters_Converter_deinit, Converter.prototype, null); } constructor() { @@ -297,7 +319,7 @@ export async function createInstantiator(options, swift) { } class UUID extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_UUID_deinit, UUID.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_UUID_deinit, UUID.prototype, null); } uuidString() { @@ -309,7 +331,7 @@ export async function createInstantiator(options, swift) { } class Container extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Collections_Container_deinit, Container.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Collections_Container_deinit, Container.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 92ce69cbb..32a325bda 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -227,18 +227,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -248,12 +269,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Greeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_Greeter_deinit, Greeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_Greeter_deinit, Greeter.prototype, null); } constructor(name) { @@ -281,7 +303,7 @@ export async function createInstantiator(options, swift) { } class Converter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converters_Converter_deinit, Converter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Utils_Converters_Converter_deinit, Converter.prototype, null); } constructor() { @@ -297,7 +319,7 @@ export async function createInstantiator(options, swift) { } class UUID extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_UUID_deinit, UUID.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs___Swift_Foundation_UUID_deinit, UUID.prototype, null); } uuidString() { @@ -309,7 +331,7 @@ export async function createInstantiator(options, swift) { } class Container extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Collections_Container_deinit, Container.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Collections_Container_deinit, Container.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 37408a42d..5971c2fa8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -471,18 +471,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -492,12 +513,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Greeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Greeter_deinit, Greeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Greeter_deinit, Greeter.prototype, null); } constructor(name) { @@ -558,7 +580,7 @@ export async function createInstantiator(options, swift) { } class OptionalPropertyHolder extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_OptionalPropertyHolder_deinit, OptionalPropertyHolder.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_OptionalPropertyHolder_deinit, OptionalPropertyHolder.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index 658702a39..7f840708e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -215,18 +215,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -236,12 +257,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class PropertyHolder extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PropertyHolder_deinit, PropertyHolder.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PropertyHolder_deinit, PropertyHolder.prototype, null); } constructor(intValue, floatValue, doubleValue, boolValue, stringValue, jsObject) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index f82e41703..9fb9b172b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -575,18 +575,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -596,12 +617,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Helper extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Helper_deinit, Helper.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Helper_deinit, Helper.prototype, null); } constructor(value) { @@ -621,7 +643,7 @@ export async function createInstantiator(options, swift) { } class MyViewController extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MyViewController_deinit, MyViewController.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MyViewController_deinit, MyViewController.prototype, null); } constructor(delegate) { @@ -682,7 +704,7 @@ export async function createInstantiator(options, swift) { } class DelegateManager extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_DelegateManager_deinit, DelegateManager.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_DelegateManager_deinit, DelegateManager.prototype, null); } constructor(delegates) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js index 13070a3cc..aefdb5679 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -361,18 +361,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -382,12 +403,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Widget extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Widget_deinit, Widget.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Widget_deinit, Widget.prototype, null); } constructor(name) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 42e25545e..ef685b8a4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -259,18 +259,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -280,12 +301,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class MathUtils extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MathUtils_deinit, MathUtils.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MathUtils_deinit, MathUtils.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 4cf9615fb..1fd066076 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -259,18 +259,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -280,12 +301,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class MathUtils extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MathUtils_deinit, MathUtils.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MathUtils_deinit, MathUtils.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 9928804eb..5800fcb56 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -220,18 +220,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -241,12 +262,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class PropertyClass extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PropertyClass_deinit, PropertyClass.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PropertyClass_deinit, PropertyClass.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index f82ac20df..b81255810 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -220,18 +220,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -241,12 +262,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class PropertyClass extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PropertyClass_deinit, PropertyClass.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PropertyClass_deinit, PropertyClass.prototype, null); } constructor() { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index cf9faa707..9ee57d692 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -243,18 +243,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -264,12 +285,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Greeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Greeter_deinit, Greeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Greeter_deinit, Greeter.prototype, null); } constructor(name) { @@ -325,13 +347,13 @@ export async function createInstantiator(options, swift) { } class PublicGreeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PublicGreeter_deinit, PublicGreeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PublicGreeter_deinit, PublicGreeter.prototype, null); } } class PackageGreeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PackageGreeter_deinit, PackageGreeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_PackageGreeter_deinit, PackageGreeter.prototype, null); } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 7e90c9415..03a5504e4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -902,18 +902,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -923,12 +944,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Person extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Person_deinit, Person.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Person_deinit, Person.prototype, null); } constructor(name) { @@ -940,7 +962,7 @@ export async function createInstantiator(options, swift) { } class TestProcessor extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_TestProcessor_deinit, TestProcessor.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_TestProcessor_deinit, TestProcessor.prototype, null); } constructor(transform) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index a60615686..abfb24d48 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -484,18 +484,39 @@ export async function createInstantiator(options, swift) { 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) { - const obj = Object.create(prototype); - const state = { pointer, deinit, hasReleased: false }; - obj.pointer = pointer; - obj.__swiftHeapObjectState = state; - swiftHeapObjectFinalizationRegistry.register(obj, state, state); - return obj; + static __wrap(pointer, deinit, prototype, identityCache) { + 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() { @@ -505,12 +526,13 @@ export async function createInstantiator(options, swift) { } state.hasReleased = true; swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); state.deinit(state.pointer); } } class Greeter extends SwiftHeapObject { static __construct(ptr) { - return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Greeter_deinit, Greeter.prototype); + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Greeter_deinit, Greeter.prototype, null); } constructor(name) { diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md index 604017aad..0bd69aa5b 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md @@ -73,6 +73,36 @@ const greeter = new exports.MyModule.Greeter("World"); // globalThis.MyModule is undefined ``` +### `identityMode` + +Controls whether exported Swift class instances use pointer-based identity mapping. + +When set to `"pointer"`, every class in the target uses identity caching — the same Swift heap pointer always returns the same JavaScript wrapper object. This makes `===` identity checks work across boundary crossings. + +```json +{ + "identityMode": "pointer" +} +``` + +**With `identityMode: "pointer"`:** + +```javascript +const a = exports.getModel(); +const b = exports.getModel(); // same Swift object +console.log(a === b); // true +``` + +**Without (default):** + +```javascript +const a = exports.getModel(); +const b = exports.getModel(); // same Swift object +console.log(a === b); // false — different JS wrapper each time +``` + +For finer control, use the `@JS(identityMode:)` parameter on individual classes instead of the project-wide config. See for details. + ### `tools` Specify custom paths for external executables. This is particularly useful when working in environments like Xcode where the system PATH may not be inherited, or when you need to use a specific version of tools for your project. diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md index a16c81286..8a1b7dff5 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Class.md @@ -135,6 +135,46 @@ Classes use **reference semantics** when crossing the Swift/JavaScript boundary: This differs from structs, which use copy semantics and transfer data by value. +## Identity Mode + +By default, each boundary crossing creates a new JavaScript wrapper for the same Swift object. This means `===` identity checks fail even when the underlying Swift object is the same: + +```javascript +const a = exports.getModel(); +const b = exports.getModel(); // same Swift object +console.log(a === b); // false — different wrappers +``` + +For classes where wrapper identity matters, enable identity mode with the `identityMode` parameter: + +```swift +@JS(identityMode: true) +class Model { + @JS var name: String + @JS init(name: String) { self.name = name } +} +``` + +With identity mode, BridgeJS maintains a per-class `WeakRef`-based cache keyed by the Swift heap pointer. The same pointer always returns the same JavaScript wrapper: + +```javascript +const a = exports.getModel(); +const b = exports.getModel(); // same Swift object +console.log(a === b); // true — same wrapper +``` + +Identity mode is opt-in per class. Non-annotated classes have zero overhead. To enable it for all classes in a target, use `bridge-js.config.json` instead: + +```json +{ "identityMode": "pointer" } +``` + +Per-class `@JS(identityMode: true/false)` overrides the config setting. + +### Tradeoffs + +Identity mode improves performance for reuse-heavy workloads (same objects crossing repeatedly) but adds overhead for create-heavy workloads (many short-lived objects). The cache infrastructure (`Map`, `WeakRef`, `FinalizationRegistry`) has a per-object cost that is only worthwhile when objects are returned multiple times. + ## Supported Features | Swift Feature | Status | diff --git a/Sources/JavaScriptKit/Macros.swift b/Sources/JavaScriptKit/Macros.swift index 67b3488bf..3189cdeab 100644 --- a/Sources/JavaScriptKit/Macros.swift +++ b/Sources/JavaScriptKit/Macros.swift @@ -113,7 +113,8 @@ public enum JSImportFrom: String { /// /// - Important: This feature is still experimental. No API stability is guaranteed, and the API may change in future releases. @attached(peer) -public macro JS(namespace: String? = nil, enumStyle: JSEnumStyle = .const) = Builtin.ExternalMacro +public macro JS(namespace: String? = nil, enumStyle: JSEnumStyle = .const, identityMode: Bool = false) = + Builtin.ExternalMacro /// A macro that generates a Swift getter that reads a value from JavaScript. /// diff --git a/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift b/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift new file mode 100644 index 000000000..e25ebeb4c --- /dev/null +++ b/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift @@ -0,0 +1,353 @@ +// bridge-js: skip +// 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`. + +@_spi(BridgeJS) import JavaScriptKit + +@_expose(wasm, "bjs_getSharedSubject") +@_cdecl("bjs_getSharedSubject") +public func _bjs_getSharedSubject() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = getSharedSubject() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_resetSharedSubject") +@_cdecl("bjs_resetSharedSubject") +public func _bjs_resetSharedSubject() -> Void { + #if arch(wasm32) + resetSharedSubject() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getRetainLeakSubject") +@_cdecl("bjs_getRetainLeakSubject") +public func _bjs_getRetainLeakSubject() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = getRetainLeakSubject() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_resetRetainLeakSubject") +@_cdecl("bjs_resetRetainLeakSubject") +public func _bjs_resetRetainLeakSubject() -> Void { + #if arch(wasm32) + resetRetainLeakSubject() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getRetainLeakDeinits") +@_cdecl("bjs_getRetainLeakDeinits") +public func _bjs_getRetainLeakDeinits() -> Int32 { + #if arch(wasm32) + let ret = getRetainLeakDeinits() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_resetRetainLeakDeinits") +@_cdecl("bjs_resetRetainLeakDeinits") +public func _bjs_resetRetainLeakDeinits() -> Void { + #if arch(wasm32) + resetRetainLeakDeinits() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_setupArrayPool") +@_cdecl("bjs_setupArrayPool") +public func _bjs_setupArrayPool(_ count: Int32) -> Void { + #if arch(wasm32) + setupArrayPool(_: Int.bridgeJSLiftParameter(count)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getArrayPool") +@_cdecl("bjs_getArrayPool") +public func _bjs_getArrayPool() -> Void { + #if arch(wasm32) + let ret = getArrayPool() + ret.bridgeJSStackPush() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getArrayPoolElement") +@_cdecl("bjs_getArrayPoolElement") +public func _bjs_getArrayPoolElement(_ index: Int32) -> Void { + #if arch(wasm32) + let ret = getArrayPoolElement(_: Int.bridgeJSLiftParameter(index)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_getArrayPoolDeinits") +@_cdecl("bjs_getArrayPoolDeinits") +public func _bjs_getArrayPoolDeinits() -> Int32 { + #if arch(wasm32) + let ret = getArrayPoolDeinits() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_resetArrayPoolDeinits") +@_cdecl("bjs_resetArrayPoolDeinits") +public func _bjs_resetArrayPoolDeinits() -> Void { + #if arch(wasm32) + resetArrayPoolDeinits() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_clearArrayPool") +@_cdecl("bjs_clearArrayPool") +public func _bjs_clearArrayPool() -> Void { + #if arch(wasm32) + clearArrayPool() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityTestSubject_init") +@_cdecl("bjs_IdentityTestSubject_init") +public func _bjs_IdentityTestSubject_init(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = IdentityTestSubject(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityTestSubject_value_get") +@_cdecl("bjs_IdentityTestSubject_value_get") +public func _bjs_IdentityTestSubject_value_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = IdentityTestSubject.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityTestSubject_value_set") +@_cdecl("bjs_IdentityTestSubject_value_set") +public func _bjs_IdentityTestSubject_value_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + IdentityTestSubject.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityTestSubject_currentValue_get") +@_cdecl("bjs_IdentityTestSubject_currentValue_get") +public func _bjs_IdentityTestSubject_currentValue_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = IdentityTestSubject.bridgeJSLiftParameter(_self).currentValue + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_IdentityTestSubject_deinit") +@_cdecl("bjs_IdentityTestSubject_deinit") +public func _bjs_IdentityTestSubject_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension IdentityTestSubject: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_IdentityTestSubject_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_IdentityTestSubject_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSIdentityTests", name: "bjs_IdentityTestSubject_wrap") +fileprivate func _bjs_IdentityTestSubject_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_IdentityTestSubject_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_IdentityTestSubject_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_IdentityTestSubject_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_RetainLeakSubject_init") +@_cdecl("bjs_RetainLeakSubject_init") +public func _bjs_RetainLeakSubject_init(_ tag: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = RetainLeakSubject(tag: Int.bridgeJSLiftParameter(tag)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RetainLeakSubject_tag_get") +@_cdecl("bjs_RetainLeakSubject_tag_get") +public func _bjs_RetainLeakSubject_tag_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = RetainLeakSubject.bridgeJSLiftParameter(_self).tag + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RetainLeakSubject_tag_set") +@_cdecl("bjs_RetainLeakSubject_tag_set") +public func _bjs_RetainLeakSubject_tag_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + RetainLeakSubject.bridgeJSLiftParameter(_self).tag = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RetainLeakSubject_deinit") +@_cdecl("bjs_RetainLeakSubject_deinit") +public func _bjs_RetainLeakSubject_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension RetainLeakSubject: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_RetainLeakSubject_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_RetainLeakSubject_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSIdentityTests", name: "bjs_RetainLeakSubject_wrap") +fileprivate func _bjs_RetainLeakSubject_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_RetainLeakSubject_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_RetainLeakSubject_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_RetainLeakSubject_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_ArrayIdentityElement_init") +@_cdecl("bjs_ArrayIdentityElement_init") +public func _bjs_ArrayIdentityElement_init(_ tag: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = ArrayIdentityElement(tag: Int.bridgeJSLiftParameter(tag)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ArrayIdentityElement_tag_get") +@_cdecl("bjs_ArrayIdentityElement_tag_get") +public func _bjs_ArrayIdentityElement_tag_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = ArrayIdentityElement.bridgeJSLiftParameter(_self).tag + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ArrayIdentityElement_tag_set") +@_cdecl("bjs_ArrayIdentityElement_tag_set") +public func _bjs_ArrayIdentityElement_tag_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + ArrayIdentityElement.bridgeJSLiftParameter(_self).tag = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_ArrayIdentityElement_deinit") +@_cdecl("bjs_ArrayIdentityElement_deinit") +public func _bjs_ArrayIdentityElement_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension ArrayIdentityElement: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_ArrayIdentityElement_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_ArrayIdentityElement_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSIdentityTests", name: "bjs_ArrayIdentityElement_wrap") +fileprivate func _bjs_ArrayIdentityElement_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_ArrayIdentityElement_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_ArrayIdentityElement_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_ArrayIdentityElement_wrap_extern(pointer) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSIdentityTests", name: "bjs_IdentityModeTestImports_runJsIdentityModeTests_static") +fileprivate func bjs_IdentityModeTestImports_runJsIdentityModeTests_static_extern() -> Void +#else +fileprivate func bjs_IdentityModeTestImports_runJsIdentityModeTests_static_extern() -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_IdentityModeTestImports_runJsIdentityModeTests_static() -> Void { + return bjs_IdentityModeTestImports_runJsIdentityModeTests_static_extern() +} + +func _$IdentityModeTestImports_runJsIdentityModeTests() throws(JSException) -> Void { + bjs_IdentityModeTestImports_runJsIdentityModeTests_static() + if let error = _swift_js_take_exception() { + throw error + } +} \ No newline at end of file diff --git a/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json new file mode 100644 index 000000000..d30ca00f8 --- /dev/null +++ b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json @@ -0,0 +1,447 @@ +{ + "exported" : { + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_IdentityTestSubject_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "IdentityTestSubject", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "currentValue", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "IdentityTestSubject" + }, + { + "constructor" : { + "abiName" : "bjs_RetainLeakSubject_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "tag", + "name" : "tag", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "RetainLeakSubject", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "tag", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "RetainLeakSubject" + }, + { + "constructor" : { + "abiName" : "bjs_ArrayIdentityElement_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "tag", + "name" : "tag", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "ArrayIdentityElement", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "tag", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "ArrayIdentityElement" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_getSharedSubject", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getSharedSubject", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "IdentityTestSubject" + } + } + }, + { + "abiName" : "bjs_resetSharedSubject", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "resetSharedSubject", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_getRetainLeakSubject", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getRetainLeakSubject", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "RetainLeakSubject" + } + } + }, + { + "abiName" : "bjs_resetRetainLeakSubject", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "resetRetainLeakSubject", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_getRetainLeakDeinits", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getRetainLeakDeinits", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "abiName" : "bjs_resetRetainLeakDeinits", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "resetRetainLeakDeinits", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_setupArrayPool", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setupArrayPool", + "parameters" : [ + { + "label" : "_", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_getArrayPool", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getArrayPool", + "parameters" : [ + + ], + "returnType" : { + "array" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "ArrayIdentityElement" + } + } + } + } + }, + { + "abiName" : "bjs_getArrayPoolElement", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getArrayPoolElement", + "parameters" : [ + { + "label" : "_", + "name" : "index", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "ArrayIdentityElement" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_getArrayPoolDeinits", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getArrayPoolDeinits", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "abiName" : "bjs_resetArrayPoolDeinits", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "resetArrayPoolDeinits", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_clearArrayPool", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "clearArrayPool", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ], + "identityMode" : "pointer", + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "imported" : { + "children" : [ + { + "functions" : [ + + ], + "types" : [ + { + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "IdentityModeTestImports", + "setters" : [ + + ], + "staticMethods" : [ + { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "runJsIdentityModeTests", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ] + } + ] + } + ] + }, + "moduleName" : "BridgeJSIdentityTests" +} \ No newline at end of file diff --git a/Tests/BridgeJSIdentityTests/IdentityModeTests.swift b/Tests/BridgeJSIdentityTests/IdentityModeTests.swift new file mode 100644 index 000000000..795b0679b --- /dev/null +++ b/Tests/BridgeJSIdentityTests/IdentityModeTests.swift @@ -0,0 +1,113 @@ +import XCTest +import JavaScriptKit + +@JSClass struct IdentityModeTestImports { + @JSFunction static func runJsIdentityModeTests() throws(JSException) +} + +final class IdentityModeTests: XCTestCase { + func testRunJsIdentityModeTests() throws { + try IdentityModeTestImports.runJsIdentityModeTests() + } +} + +@JS class IdentityTestSubject { + @JS var value: Int + + @JS init(value: Int) { + self.value = value + } + + @JS var currentValue: Int { value } +} + +nonisolated(unsafe) private var _sharedSubject: IdentityTestSubject? + +@JS func getSharedSubject() -> IdentityTestSubject { + if _sharedSubject == nil { + _sharedSubject = IdentityTestSubject(value: 42) + } + return _sharedSubject! +} + +@JS func resetSharedSubject() { + _sharedSubject = nil +} + +@JS class RetainLeakSubject { + nonisolated(unsafe) static var deinits: Int = 0 + + @JS var tag: Int + + @JS init(tag: Int) { + self.tag = tag + } + + deinit { + Self.deinits += 1 + } +} + +nonisolated(unsafe) private var _retainLeakSubject: RetainLeakSubject? + +@JS func getRetainLeakSubject() -> RetainLeakSubject { + if _retainLeakSubject == nil { + _retainLeakSubject = RetainLeakSubject(tag: 1) + } + return _retainLeakSubject! +} + +@JS func resetRetainLeakSubject() { + _retainLeakSubject = nil +} + +@JS func getRetainLeakDeinits() -> Int { + RetainLeakSubject.deinits +} + +@JS func resetRetainLeakDeinits() { + RetainLeakSubject.deinits = 0 +} + +// MARK: - Array identity tests + +@JS class ArrayIdentityElement { + nonisolated(unsafe) static var deinits: Int = 0 + + @JS var tag: Int + + @JS init(tag: Int) { + self.tag = tag + } + + deinit { + Self.deinits += 1 + } +} + +nonisolated(unsafe) private var _arrayPool: [ArrayIdentityElement] = [] + +@JS func setupArrayPool(_ count: Int) { + _arrayPool = (0.. [ArrayIdentityElement] { + return _arrayPool +} + +@JS func getArrayPoolElement(_ index: Int) -> ArrayIdentityElement? { + guard index >= 0, index < _arrayPool.count else { return nil } + return _arrayPool[index] +} + +@JS func getArrayPoolDeinits() -> Int { + ArrayIdentityElement.deinits +} + +@JS func resetArrayPoolDeinits() { + ArrayIdentityElement.deinits = 0 +} + +@JS func clearArrayPool() { + _arrayPool = [] +} diff --git a/Tests/BridgeJSIdentityTests/JavaScript/IdentityModeTests.mjs b/Tests/BridgeJSIdentityTests/JavaScript/IdentityModeTests.mjs new file mode 100644 index 000000000..b2ae2187d --- /dev/null +++ b/Tests/BridgeJSIdentityTests/JavaScript/IdentityModeTests.mjs @@ -0,0 +1,200 @@ +// @ts-check + +import assert from "node:assert"; + +/** + * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["IdentityModeTestImports"]} + */ +export function getImports(importsContext) { + return { + runJsIdentityModeTests: () => { + const exports = importsContext.getExports(); + if (!exports) { + throw new Error("No exports!?"); + } + runIdentityModeTests(exports); + }, + }; +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function runIdentityModeTests(exports) { + testWrapperIdentity(exports); + testCacheInvalidationOnRelease(exports); + testDifferentClassesDontCollide(exports); + testRetainLeakOnCacheHit(exports); + testArrayElementIdentity(exports); + testArrayElementMatchesSingleGetter(exports); + testArrayRetainLeak(exports); +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function testWrapperIdentity(exports) { + exports.resetSharedSubject(); + const a = exports.getSharedSubject(); + const b = exports.getSharedSubject(); + + assert.strictEqual( + a, + b, + "Same Swift object should return identical JS wrapper", + ); + assert.equal(a.currentValue, 42); + + a.release(); + exports.resetSharedSubject(); +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function testCacheInvalidationOnRelease(exports) { + exports.resetSharedSubject(); + const first = exports.getSharedSubject(); + first.release(); + + exports.resetSharedSubject(); + const second = exports.getSharedSubject(); + + assert.notStrictEqual( + first, + second, + "After release + reset, should get a different wrapper", + ); + assert.equal(second.currentValue, 42); + + second.release(); + exports.resetSharedSubject(); +} + +/** + * Verifies that repeated boundary crossings of the same Swift object don't leak + * retain counts. Each cache hit triggers passRetained on the Swift side. Without + * the balancing deinit(pointer) call on cache hit, each crossing leaks +1 retain + * and the object is never deallocated. + * + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function testRetainLeakOnCacheHit(exports) { + exports.resetRetainLeakDeinits(); + exports.resetRetainLeakSubject(); + + const wrappers = []; + for (let i = 0; i < 10; i++) { + wrappers.push(exports.getRetainLeakSubject()); + } + + for (let i = 1; i < wrappers.length; i++) { + assert.strictEqual( + wrappers[0], + wrappers[i], + "All should be the same cached wrapper", + ); + } + + wrappers[0].release(); + exports.resetRetainLeakSubject(); + + assert.strictEqual( + exports.getRetainLeakDeinits(), + 1, + "Object should be deallocated after release + reset. " + + "If deinits == 0, retain leak from unbalanced passRetained on cache hits.", + ); +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function testArrayElementIdentity(exports) { + exports.setupArrayPool(10); + const arr1 = exports.getArrayPool(); + const arr2 = exports.getArrayPool(); + + assert.equal(arr1.length, 10); + assert.equal(arr2.length, 10); + + for (let i = 0; i < 10; i++) { + assert.strictEqual( + arr1[i], + arr2[i], + `Array element at index ${i} should be === across calls`, + ); + assert.equal(arr1[i].tag, i); + } + + for (const elem of arr1) { + elem.release(); + } + exports.clearArrayPool(); +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function testArrayElementMatchesSingleGetter(exports) { + exports.setupArrayPool(5); + const arr = exports.getArrayPool(); + const single = exports.getArrayPoolElement(2); + + assert.strictEqual( + arr[2], + single, + "Array element and single getter should return the same wrapper", + ); + assert.equal(single.tag, 2); + + for (const elem of arr) { + elem.release(); + } + exports.clearArrayPool(); +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function testArrayRetainLeak(exports) { + exports.resetArrayPoolDeinits(); + exports.setupArrayPool(5); + + for (let round = 0; round < 10; round++) { + exports.getArrayPool(); + } + + const arr = exports.getArrayPool(); + for (const elem of arr) { + elem.release(); + } + + exports.clearArrayPool(); + + assert.strictEqual( + exports.getArrayPoolDeinits(), + 5, + "All 5 pool objects should be deallocated after release + clear. " + + "If deinits < 5, retain leak from unbalanced passRetained in array returns.", + ); +} + +/** + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports + */ +function testDifferentClassesDontCollide(exports) { + const subject1 = new exports.IdentityTestSubject(1); + const subject2 = new exports.IdentityTestSubject(2); + + assert.notStrictEqual( + subject1, + subject2, + "Different instances should not be ===", + ); + assert.equal(subject1.currentValue, 1); + assert.equal(subject2.currentValue, 2); + + subject1.release(); + subject2.release(); +} diff --git a/Tests/BridgeJSIdentityTests/bridge-js.config.json b/Tests/BridgeJSIdentityTests/bridge-js.config.json new file mode 100644 index 000000000..29884404e --- /dev/null +++ b/Tests/BridgeJSIdentityTests/bridge-js.config.json @@ -0,0 +1,3 @@ +{ + "identityMode": "pointer" +} diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 0af033226..10c73ec2f 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -14,6 +14,7 @@ import { getImports as getDefaultArgumentImports } from './BridgeJSRuntimeTests/ import { getImports as getJSClassSupportImports, JSClassWithArrayMembers } from './BridgeJSRuntimeTests/JavaScript/JSClassSupportTests.mjs'; import { getImports as getIntegerTypesSupportImports } from './BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs'; import { getImports as getAsyncImportImports, runAsyncWorksTests } from './BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs'; +import { getImports as getIdentityModeTestImports } from './BridgeJSIdentityTests/JavaScript/IdentityModeTests.mjs'; /** @type {import('../.build/plugins/PackageToJS/outputs/PackageTests/test.d.ts').SetupOptionsFn} */ export async function setupOptions(options, context) { @@ -155,6 +156,7 @@ export async function setupOptions(options, context) { DefaultArgumentImports: getDefaultArgumentImports(importsContext), JSClassSupportImports: getJSClassSupportImports(importsContext), IntegerTypesSupportImports: getIntegerTypesSupportImports(importsContext), + IdentityModeTestImports: getIdentityModeTestImports(importsContext), }; }, addToCoreImports(importObject, importsContext) { diff --git a/Utilities/bridge-js-generate.sh b/Utilities/bridge-js-generate.sh index 22182d24b..77bdd0833 100755 --- a/Utilities/bridge-js-generate.sh +++ b/Utilities/bridge-js-generate.sh @@ -6,5 +6,6 @@ swift build --package-path ./Plugins/BridgeJS --product BridgeJSTool ./Plugins/BridgeJS/.build/debug/BridgeJSTool generate --project ./tsconfig.json --module-name BridgeJSRuntimeTests --target-dir ./Tests/BridgeJSRuntimeTests --output-dir ./Tests/BridgeJSRuntimeTests/Generated ./Plugins/BridgeJS/.build/debug/BridgeJSTool generate --project ./tsconfig.json --module-name BridgeJSGlobalTests --target-dir ./Tests/BridgeJSGlobalTests --output-dir ./Tests/BridgeJSGlobalTests/Generated +./Plugins/BridgeJS/.build/debug/BridgeJSTool generate --project ./tsconfig.json --module-name BridgeJSIdentityTests --target-dir ./Tests/BridgeJSIdentityTests --output-dir ./Tests/BridgeJSIdentityTests/Generated ./Plugins/BridgeJS/.build/debug/BridgeJSTool generate --project ./tsconfig.json --module-name Benchmarks --target-dir ./Benchmarks/Sources --output-dir ./Benchmarks/Sources/Generated ./Plugins/BridgeJS/.build/debug/BridgeJSTool generate --project ./tsconfig.json --module-name PlayBridgeJS --target-dir ./Examples/PlayBridgeJS/Sources/PlayBridgeJS --output-dir ./Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated From 1f8710b18dc235893b4b333b25e78d159ca9e499 Mon Sep 17 00:00:00 2001 From: 0xpablo Date: Fri, 24 Apr 2026 17:09:16 +0200 Subject: [PATCH 37/68] Adopt Foundation Essentials in compat target (#725) --- Sources/JavaScriptFoundationCompat/Data+JSValue.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/JavaScriptFoundationCompat/Data+JSValue.swift b/Sources/JavaScriptFoundationCompat/Data+JSValue.swift index ac8e773b4..6e74ba266 100644 --- a/Sources/JavaScriptFoundationCompat/Data+JSValue.swift +++ b/Sources/JavaScriptFoundationCompat/Data+JSValue.swift @@ -1,4 +1,8 @@ +#if canImport(FoundationEssentials) +import FoundationEssentials +#else import Foundation +#endif import JavaScriptKit /// Data <-> Uint8Array conversion. The conversion is lossless and copies the bytes at most once per conversion From 8d279a03d854c71d51b9121aff07629bc9f112ff Mon Sep 17 00:00:00 2001 From: Matthew Ayers Date: Sun, 26 Apr 2026 05:30:43 -0400 Subject: [PATCH 38/68] Add Utilities/setup-dev.sh for one-command contributor setup (#726) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wraps the manual steps already documented in CONTRIBUTING.md: - Verifies required tools (swiftly, swift, jq, npm, make, curl). - If a .swift-version file is present, installs the pinned toolchain via swiftly. - Resolves and installs a matching Wasm SDK from swift-sdk-index (idempotent — skipped if already installed). - Runs `make bootstrap` to install JS deps. - Prints SWIFT_SDK_ID for use with `make unittest`. The script runs under bash via shebang; the export instructions it prints work unchanged in zsh and bash. The repo does not track .swift-version; contributors who want it ignored locally can add it to .git/info/exclude. The original manual instructions are kept in CONTRIBUTING.md as a fallback. --- CONTRIBUTING.md | 39 +++++++++++--- Utilities/setup-dev.sh | 112 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 8 deletions(-) create mode 100755 Utilities/setup-dev.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d984555e6..8cb96dec9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,14 +12,37 @@ Thank you for considering contributing to JavaScriptKit! We welcome contribution - Relevant error messages or logs ### Setting Up the Development Environment -1. Clone the repository: - ```bash - git clone https://github.com/swiftwasm/JavaScriptKit.git - cd JavaScriptKit - ``` -2. Install **OSS** Swift toolchain via `swiftly` -3. Install Swift SDK for Wasm corresponding to the Swift version: +Clone the repository: + +```bash +git clone https://github.com/swiftwasm/JavaScriptKit.git +cd JavaScriptKit +``` + +#### Quick start (recommended) + +If you already have an **OSS** Swift toolchain installed via [`swiftly`](https://www.swift.org/install/macos/swiftly), run: + +```bash +./Utilities/setup-dev.sh +``` + +The script verifies prerequisites, installs a matching Wasm Swift SDK from +[swift-sdk-index](https://github.com/swiftwasm/swift-sdk-index), runs `make bootstrap`, +and prints the `SWIFT_SDK_ID` to use with `make unittest`. Re-running it is +idempotent. + +If a `.swift-version` file is present in the repo root, the script will install +that toolchain via `swiftly` automatically. Create one to pin your local dev +toolchain to an indexed release (e.g. `echo 6.3.0 > .swift-version`). The repo +does not track `.swift-version`; if you'd like git to ignore it locally, add it +to `.git/info/exclude`. + +#### Manual setup + +1. Install an **OSS** Swift toolchain via `swiftly`. +2. Install the Swift SDK for Wasm corresponding to the Swift version: ```bash ( set -eo pipefail; \ @@ -35,7 +58,7 @@ Thank you for considering contributing to JavaScriptKit! We welcome contribution jq -r '.["swift-sdks"]["wasm32-unknown-wasip1"]["id"]' ) ``` -4. Install dependencies: +3. Install dependencies: ```bash make bootstrap ``` diff --git a/Utilities/setup-dev.sh b/Utilities/setup-dev.sh new file mode 100755 index 000000000..261e5ebf6 --- /dev/null +++ b/Utilities/setup-dev.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +# +# Set up a local development environment for JavaScriptKit. +# +# Steps: +# 1. Verify required tools are available (swiftly, swift, jq, npm, make, curl). +# 2. If .swift-version is present, ensure that toolchain is installed via swiftly. +# 3. Resolve a matching Wasm SDK from https://github.com/swiftwasm/swift-sdk-index +# and install it (idempotent — skipped if already installed). +# 4. Run `make bootstrap` to install JS dependencies. +# 5. Print the SWIFT_SDK_ID so it can be exported for `make unittest`. +# +# The script runs under bash via the shebang. The final `export` instructions +# it prints work unchanged in both bash and zsh. + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$REPO_ROOT" + +INDEX_BASE="https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1" + +if [[ -t 1 ]]; then + C_BLUE=$'\033[1;34m'; C_YELLOW=$'\033[1;33m'; C_RED=$'\033[1;31m'; C_RESET=$'\033[0m' +else + C_BLUE=''; C_YELLOW=''; C_RED=''; C_RESET='' +fi + +log() { printf '%s==>%s %s\n' "$C_BLUE" "$C_RESET" "$*"; } +warn() { printf '%swarn:%s %s\n' "$C_YELLOW" "$C_RESET" "$*" >&2; } +fail() { printf '%serror:%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; exit 1; } + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1${2:+ ($2)}" +} + +log "Checking required tools..." +require_cmd curl +require_cmd jq "install via 'brew install jq' or your package manager" +require_cmd npm "install Node.js from https://nodejs.org" +require_cmd make +require_cmd swiftly "install from https://www.swift.org/install/macos/swiftly" +require_cmd swift "install a Swift toolchain via swiftly" +require_cmd swiftc + +# 1. Honor a .swift-version pin if the repo has one. +if [[ -f .swift-version ]]; then + pinned="$(tr -d '[:space:]' < .swift-version)" + if [[ -n "$pinned" ]]; then + log "Repo pins Swift $pinned via .swift-version" + if ! swiftly list 2>/dev/null | grep -qF "$pinned"; then + log "Installing Swift $pinned via swiftly..." + swiftly install "$pinned" + fi + fi +fi + +SWIFT_VERSION_KEY="$(swiftc --version | head -n1)" +log "Active Swift: $SWIFT_VERSION_KEY" + +# 2. Resolve a matching Wasm SDK. +log "Resolving Wasm SDK from swift-sdk-index..." +TAG_BY_VERSION="$(curl -fsSL "$INDEX_BASE/tag-by-version.json")" +TAG="$(jq -r --arg v "$SWIFT_VERSION_KEY" '.[$v] // [] | .[-1] // empty' <<<"$TAG_BY_VERSION")" + +if [[ -z "$TAG" ]]; then + cat >&2 <'. + + - Use an OSS development snapshot from https://www.swift.org/install/ + +See https://github.com/swiftwasm/swift-sdk-index for details. +EOF + exit 1 +fi + +log "Resolved tag: $TAG" +BUILD_JSON="$(curl -fsSL "$INDEX_BASE/builds/$TAG.json")" +SDK_URL="$(jq -r '."swift-sdks"."wasm32-unknown-wasip1".url' <<<"$BUILD_JSON")" +SDK_CHECKSUM="$(jq -r '."swift-sdks"."wasm32-unknown-wasip1".checksum' <<<"$BUILD_JSON")" +SDK_ID="$(jq -r '."swift-sdks"."wasm32-unknown-wasip1".id' <<<"$BUILD_JSON")" + +if swift sdk list 2>/dev/null | grep -qx "$SDK_ID"; then + log "Wasm SDK already installed: $SDK_ID" +else + log "Installing Wasm SDK: $SDK_ID" + swift sdk install "$SDK_URL" --checksum "$SDK_CHECKSUM" +fi + +# 3. JS dependencies. +log "Installing JS dependencies (make bootstrap)..." +make bootstrap + +cat < Date: Wed, 29 Apr 2026 00:52:11 +0200 Subject: [PATCH 39/68] test: Add GC lifecycle test for identity-cached wrappers (#731) --- .../Generated/BridgeJS.swift | 19 +++++++++ .../Generated/JavaScript/BridgeJS.json | 16 ++++++++ .../IdentityModeTests.swift | 40 +++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift b/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift index e25ebeb4c..ffab42367 100644 --- a/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift @@ -333,6 +333,25 @@ fileprivate func _bjs_ArrayIdentityElement_wrap_extern(_ pointer: UnsafeMutableR return _bjs_ArrayIdentityElement_wrap_extern(pointer) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSIdentityTests", name: "bjs_gc") +fileprivate func bjs_gc_extern() -> Void +#else +fileprivate func bjs_gc_extern() -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_gc() -> Void { + return bjs_gc_extern() +} + +func _$gc() throws(JSException) -> Void { + bjs_gc() + if let error = _swift_js_take_exception() { + throw error + } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSIdentityTests", name: "bjs_IdentityModeTestImports_runJsIdentityModeTests_static") fileprivate func bjs_IdentityModeTestImports_runJsIdentityModeTests_static_extern() -> Void diff --git a/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json index d30ca00f8..fc1504c37 100644 --- a/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json @@ -406,7 +406,23 @@ "children" : [ { "functions" : [ + { + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "from" : "global", + "name" : "gc", + "parameters" : [ + + ], + "returnType" : { + "void" : { + } + } + } ], "types" : [ { diff --git a/Tests/BridgeJSIdentityTests/IdentityModeTests.swift b/Tests/BridgeJSIdentityTests/IdentityModeTests.swift index 795b0679b..0aa036163 100644 --- a/Tests/BridgeJSIdentityTests/IdentityModeTests.swift +++ b/Tests/BridgeJSIdentityTests/IdentityModeTests.swift @@ -1,6 +1,8 @@ import XCTest import JavaScriptKit +@JSFunction(from: .global) func gc() throws(JSException) -> Void + @JSClass struct IdentityModeTestImports { @JSFunction static func runJsIdentityModeTests() throws(JSException) } @@ -9,6 +11,44 @@ final class IdentityModeTests: XCTestCase { func testRunJsIdentityModeTests() throws { try IdentityModeTestImports.runJsIdentityModeTests() } + + /// Verifies that identity-cached wrappers are properly reclaimed by GC. + /// + /// Creates an identity-mode object, crosses it multiple times (filling the + /// identity cache), drops all references, triggers GC + event loop ticks, + /// and verifies the Swift object is deallocated. This proves that the + /// WeakRef-based identity cache does not prevent garbage collection. + func testIdentityCachedWrapperIsReclaimedByGC() async throws { + RetainLeakSubject.deinits = 0 + + // Create object and cross it multiple times to fill identity cache + _retainLeakSubject = RetainLeakSubject(tag: 99) + weak var weakSubject = _retainLeakSubject + + // Cross to JS 5 times (populates identity cache with WeakRef) + for _ in 0..<5 { + _ = getRetainLeakSubject() + } + + // Drop Swift-side strong reference + _retainLeakSubject = nil + + // JS wrapper should still be alive via the identity cache's WeakRef, + // but WeakRef doesn't prevent GC. Trigger GC + event loop ticks to + // let FinalizationRegistry fire and call deinit. + for _ in 0..<100 { + try gc() + try await Task.sleep(for: .milliseconds(0)) + if weakSubject == nil { + break + } + } + + // The identity-cached wrapper should have been collected, + // FinalizationRegistry should have fired, deinit should have run. + XCTAssertNil(weakSubject, "Identity-cached object should be deallocated after GC") + XCTAssertEqual(RetainLeakSubject.deinits, 1, "Deinit should fire exactly once") + } } @JS class IdentityTestSubject { From 09b3f4eede93735a73a2ed54baa4b7868c1b0127 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Thu, 30 Apr 2026 16:50:17 +1000 Subject: [PATCH 40/68] BridgeJS: Use `@JS` types from other modules in the same package (#730) * BridgeJS: Use `@JS` types from other modules in the same package * BridgeJS: Improve diagnostics with multi-module AOT * BridgeJS: Fix an issue where the skeleton was being treated as a resource * Fix typo * Documentation improvements --- .../Generated/JavaScript/BridgeJS.json | 5 +- Examples/MultiModule/Package.swift | 38 ++ Examples/MultiModule/README.md | 17 + .../MultiModule/Sources/Core/Vector3D.swift | 17 + .../Sources/Core/bridge-js.config.json | 1 + .../Sources/MultiModule/bridge-js.config.json | 1 + .../Sources/MultiModule/main.swift | 6 + Examples/MultiModule/index.html | 12 + Examples/MultiModule/index.js | 10 + .../Generated/JavaScript/BridgeJS.json | 5 +- .../Sources/PlayBridgeJS/main.swift | 7 +- .../BridgeJSBuildPlugin.swift | 64 +++ .../BridgeJSPluginUtilities | 1 + .../BridgeJSCommandPlugin.swift | 85 ++- .../BridgeJSCore/ExternalModuleIndex.swift | 93 ++++ .../BridgeJSCore/SwiftToSkeleton.swift | 182 ++++--- .../BridgeJSCore/TypeDeclResolver.swift | 2 +- .../BridgeJSPluginUtilities/PluginPaths.swift | 74 +++ .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 9 +- .../Sources/BridgeJSTool/BridgeJSTool.swift | 92 +++- .../BridgeJSToolInternal.swift | 3 +- .../Sources/BridgeJSUtilities/Utilities.swift | 8 +- .../BridgeJSCodegenTests.swift | 56 +- .../BridgeJSToolTests/BridgeJSLinkTests.swift | 30 +- .../CrossModuleResolutionTests.swift | 491 ++++++++++++++++++ .../BridgeJSCodegenTests/ArrayTypes.json | 5 +- .../BridgeJSCodegenTests/Async.json | 5 +- .../BridgeJSCodegenTests/AsyncImport.json | 5 +- .../AsyncStaticImport.json | 5 +- .../CrossFileExtension.json | 5 +- .../CrossFileFunctionTypes.ReverseOrder.json | 5 +- .../CrossFileFunctionTypes.json | 5 +- .../CrossFileSkipsEmptySkeletons.json | 5 +- .../CrossFileTypeResolution.ReverseOrder.json | 5 +- .../CrossFileTypeResolution.json | 5 +- .../DefaultParameters.json | 5 +- .../BridgeJSCodegenTests/DictionaryTypes.json | 5 +- .../EnumAssociatedValue.json | 5 +- .../BridgeJSCodegenTests/EnumCase.json | 5 +- .../EnumNamespace.Global.json | 5 +- .../BridgeJSCodegenTests/EnumNamespace.json | 5 +- .../BridgeJSCodegenTests/EnumRawType.json | 5 +- .../FixedWidthIntegers.json | 5 +- .../BridgeJSCodegenTests/GlobalGetter.json | 5 +- .../GlobalThisImports.json | 5 +- .../IdentityModeClass.json | 5 +- .../BridgeJSCodegenTests/ImportArray.json | 5 +- .../ImportedTypeInExportedInterface.json | 5 +- .../InvalidPropertyNames.json | 5 +- .../BridgeJSCodegenTests/JSClass.json | 5 +- .../JSClassStaticFunctions.json | 5 +- .../BridgeJSCodegenTests/JSValue.json | 5 +- .../BridgeJSCodegenTests/MixedGlobal.json | 5 +- .../BridgeJSCodegenTests/MixedPrivate.json | 5 +- .../Namespaces.Global.json | 5 +- .../BridgeJSCodegenTests/Namespaces.json | 5 +- .../BridgeJSCodegenTests/Optionals.json | 5 +- .../PrimitiveParameters.json | 5 +- .../BridgeJSCodegenTests/PrimitiveReturn.json | 5 +- .../BridgeJSCodegenTests/PropertyTypes.json | 5 +- .../BridgeJSCodegenTests/Protocol.json | 5 +- .../ProtocolInClosure.json | 5 +- .../StaticFunctions.Global.json | 5 +- .../BridgeJSCodegenTests/StaticFunctions.json | 5 +- .../StaticProperties.Global.json | 5 +- .../StaticProperties.json | 5 +- .../BridgeJSCodegenTests/StringParameter.json | 5 +- .../BridgeJSCodegenTests/StringReturn.json | 5 +- .../BridgeJSCodegenTests/SwiftClass.json | 5 +- .../BridgeJSCodegenTests/SwiftClosure.json | 5 +- .../SwiftClosureImports.json | 5 +- .../BridgeJSCodegenTests/SwiftStruct.json | 5 +- .../SwiftStructImports.json | 5 +- .../BridgeJSCodegenTests/Throws.json | 5 +- .../BridgeJSCodegenTests/UnsafePointer.json | 5 +- .../VoidParameterVoidReturn.json | 5 +- .../Sources/BridgeJSPluginUtilities | 1 + .../Sources/PackageToJSPlugin.swift | 16 +- .../BridgeJS/BridgeJS-Configuration.md | 2 + .../Articles/BridgeJS/Setting-up-BridgeJS.md | 4 + .../Articles/BridgeJS/Unsupported-Features.md | 20 +- .../Generated/JavaScript/BridgeJS.json | 5 +- .../Generated/JavaScript/BridgeJS.json | 5 +- .../Generated/JavaScript/BridgeJS.json | 5 +- 84 files changed, 1449 insertions(+), 173 deletions(-) create mode 100644 Examples/MultiModule/Package.swift create mode 100644 Examples/MultiModule/README.md create mode 100644 Examples/MultiModule/Sources/Core/Vector3D.swift create mode 100644 Examples/MultiModule/Sources/Core/bridge-js.config.json create mode 100644 Examples/MultiModule/Sources/MultiModule/bridge-js.config.json create mode 100644 Examples/MultiModule/Sources/MultiModule/main.swift create mode 100644 Examples/MultiModule/index.html create mode 100644 Examples/MultiModule/index.js create mode 120000 Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSPluginUtilities create mode 100644 Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift create mode 100644 Plugins/BridgeJS/Sources/BridgeJSPluginUtilities/PluginPaths.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/CrossModuleResolutionTests.swift create mode 120000 Plugins/PackageToJS/Sources/BridgeJSPluginUtilities diff --git a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json index 0bddddfb6..8e9c1cd6b 100644 --- a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json +++ b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json @@ -3415,5 +3415,8 @@ } ] }, - "moduleName" : "Benchmarks" + "moduleName" : "Benchmarks", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Examples/MultiModule/Package.swift b/Examples/MultiModule/Package.swift new file mode 100644 index 000000000..870e2a5e8 --- /dev/null +++ b/Examples/MultiModule/Package.swift @@ -0,0 +1,38 @@ +// swift-tools-version:6.0 + +import PackageDescription + +let package = Package( + name: "MultiModule", + platforms: [ + .macOS(.v14) + ], + dependencies: [.package(name: "JavaScriptKit", path: "../../")], + targets: [ + .target( + name: "Core", + dependencies: [ + "JavaScriptKit" + ], + swiftSettings: [ + .enableExperimentalFeature("Extern") + ], + plugins: [ + .plugin(name: "BridgeJS", package: "JavaScriptKit") + ] + ), + .executableTarget( + name: "MultiModule", + dependencies: [ + "Core", + "JavaScriptKit", + ], + swiftSettings: [ + .enableExperimentalFeature("Extern") + ], + plugins: [ + .plugin(name: "BridgeJS", package: "JavaScriptKit") + ] + ), + ] +) diff --git a/Examples/MultiModule/README.md b/Examples/MultiModule/README.md new file mode 100644 index 000000000..741394d6f --- /dev/null +++ b/Examples/MultiModule/README.md @@ -0,0 +1,17 @@ +# MultiModule Example + +This example demonstrates using `@JS` types defined in one module (`Core`) from another module (`App`) within the same Swift package. + +## Building and Running + +1. Build the project: + ```sh + swift package --swift-sdk $SWIFT_SDK_ID js --use-cdn + ``` + +2. Serve the files: + ```sh + npx serve + ``` + +Then open your browser to `http://localhost:3000`. diff --git a/Examples/MultiModule/Sources/Core/Vector3D.swift b/Examples/MultiModule/Sources/Core/Vector3D.swift new file mode 100644 index 000000000..988892bcc --- /dev/null +++ b/Examples/MultiModule/Sources/Core/Vector3D.swift @@ -0,0 +1,17 @@ +import JavaScriptKit + +@JS public struct Vector3D { + public let x: Double + public let y: Double + public let z: Double + + @JS public init(x: Double, y: Double, z: Double) { + self.x = x + self.y = y + self.z = z + } + + @JS public func magnitude() -> Double { + (x * x + y * y + z * z).squareRoot() + } +} diff --git a/Examples/MultiModule/Sources/Core/bridge-js.config.json b/Examples/MultiModule/Sources/Core/bridge-js.config.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/Examples/MultiModule/Sources/Core/bridge-js.config.json @@ -0,0 +1 @@ +{} diff --git a/Examples/MultiModule/Sources/MultiModule/bridge-js.config.json b/Examples/MultiModule/Sources/MultiModule/bridge-js.config.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/Examples/MultiModule/Sources/MultiModule/bridge-js.config.json @@ -0,0 +1 @@ +{} diff --git a/Examples/MultiModule/Sources/MultiModule/main.swift b/Examples/MultiModule/Sources/MultiModule/main.swift new file mode 100644 index 000000000..dd238c00d --- /dev/null +++ b/Examples/MultiModule/Sources/MultiModule/main.swift @@ -0,0 +1,6 @@ +import Core +import JavaScriptKit + +@JS public func currentVelocity() -> Vector3D { + Vector3D(x: 0.1, y: 0.2, z: 0.3) +} diff --git a/Examples/MultiModule/index.html b/Examples/MultiModule/index.html new file mode 100644 index 000000000..d9066820f --- /dev/null +++ b/Examples/MultiModule/index.html @@ -0,0 +1,12 @@ + + + + + MultiModule Example + + + + + + + diff --git a/Examples/MultiModule/index.js b/Examples/MultiModule/index.js new file mode 100644 index 000000000..83e79f16d --- /dev/null +++ b/Examples/MultiModule/index.js @@ -0,0 +1,10 @@ +import { init } from "./.build/plugins/PackageToJS/outputs/Package/index.js"; +const { exports } = await init({}); + +const velocity = exports.currentVelocity(); + +const output = document.createElement("pre"); +output.innerText = + `currentVelocity() = (${velocity.x}, ${velocity.y}, ${velocity.z})\n` + + `magnitude = ${velocity.magnitude()}`; +document.body.appendChild(output); diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json index 1a21916ee..89ce6ae3a 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json @@ -300,5 +300,8 @@ } ] }, - "moduleName" : "PlayBridgeJS" + "moduleName" : "PlayBridgeJS", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/main.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/main.swift index ec9eda774..a30eb3b06 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/main.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/main.swift @@ -45,7 +45,12 @@ import class Foundation.JSONDecoder func _update(swiftSource: String, dtsSource: String) throws -> PlayBridgeJSOutput { let moduleName = "Playground" - let swiftToSkeleton = SwiftToSkeleton(progress: .silent, moduleName: moduleName, exposeToGlobal: false) + let swiftToSkeleton = SwiftToSkeleton( + progress: .silent, + moduleName: moduleName, + exposeToGlobal: false, + externalModuleIndex: .empty + ) swiftToSkeleton.addSourceFile(Parser.parse(source: swiftSource), inputFilePath: "Playground.swift") let ts2swift = try createTS2Swift() diff --git a/Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift b/Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift index 3cb6dc860..b78f5f9a6 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift @@ -63,6 +63,19 @@ struct BridgeJSBuildPlugin: BuildToolPlugin { ]) } + for skeleton in dependencySkeletons(context: context, target: target) { + arguments.append(contentsOf: [ + "--dependency-skeleton", + "\(skeleton.moduleName)=\(skeleton.skeletonURL.path)", + ]) + // We have to use the Swift file, not the skeleton, as the input file, + // since we can’t make the skeleton file an output file without it being + // treated as a resource by the build system (and thus included in the + // resource bundle). We need to use something as the inputFile to maintain + // correct ordering. + inputFiles.append(skeleton.bridgeJSSwiftURL) + } + let allSwiftFiles = inputSwiftFiles + pluginGeneratedSwiftFiles arguments.append(contentsOf: allSwiftFiles.map(\.path)) @@ -74,5 +87,56 @@ struct BridgeJSBuildPlugin: BuildToolPlugin { outputFiles: [outputSwiftPath] ) } + + private struct DependencySkeleton { + let moduleName: String + let skeletonURL: URL + let bridgeJSSwiftURL: URL + } + + /// We only read skeletons from dependencies with a `bridge-js.config.json` file. + /// For the build system to correctly order the plugins, we need to set the skeleton + /// files as input. However, I don’t think we have enough information here to determine + /// whether the plugin which generates this is applied to the dependency, so we use + /// the presence of `bridge-js.config.json` instead. + private func dependencySkeletons( + context: PluginContext, + target: SwiftSourceModuleTarget + ) -> [DependencySkeleton] { + let localTargets: [SwiftSourceModuleTarget] = target.recursiveTargetDependencies + .compactMap { dependency in + guard + let swiftTarget = dependency as? SwiftSourceModuleTarget, + context.package.targets.contains(where: { $0.id == swiftTarget.id }), + FileManager.default.fileExists(atPath: pathToConfigFile(target: swiftTarget).path) + else { + return nil + } + return swiftTarget + } + + var skeletons: [DependencySkeleton] = [] + var seenTargetNames = Set() + for swiftTarget in localTargets where seenTargetNames.insert(swiftTarget.name).inserted { + let skeletonURL = BridgeJSPluginPaths.skeletonURL( + targetName: swiftTarget.name, + packageID: context.package.id, + buildPluginWorkDirectoryURL: context.pluginWorkDirectoryURL + ) + let bridgeJSSwiftURL = BridgeJSPluginPaths.bridgeJSSwiftURL( + targetName: swiftTarget.name, + packageID: context.package.id, + buildPluginWorkDirectoryURL: context.pluginWorkDirectoryURL + ) + skeletons.append( + DependencySkeleton( + moduleName: swiftTarget.name, + skeletonURL: skeletonURL, + bridgeJSSwiftURL: bridgeJSSwiftURL + ) + ) + } + return skeletons + } } #endif diff --git a/Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSPluginUtilities b/Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSPluginUtilities new file mode 120000 index 000000000..2daaa446e --- /dev/null +++ b/Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSPluginUtilities @@ -0,0 +1 @@ +../BridgeJSPluginUtilities \ No newline at end of file diff --git a/Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift b/Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift index 23fbae567..24b96f53d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift @@ -74,28 +74,62 @@ struct BridgeJSCommandPlugin: CommandPlugin { } extension BridgeJSCommandPlugin.Context { - func runOnTargets( - remainingArguments: [String], - where predicate: (SwiftSourceModuleTarget) -> Bool - ) throws { + private func collectBridgeJSTargets() -> [String: SwiftSourceModuleTarget] { + var bridgeJSTargets: [String: SwiftSourceModuleTarget] = [:] for target in context.package.targets { - guard let target = target as? SwiftSourceModuleTarget else { + guard + let swiftTarget = target as? SwiftSourceModuleTarget, + FileManager.default.fileExists( + atPath: swiftTarget.directoryURL.appending(path: "bridge-js.config.json").path + ) + else { continue } - let configFilePath = target.directoryURL.appending(path: "bridge-js.config.json") - if !FileManager.default.fileExists(atPath: configFilePath.path) { - printVerbose("No bridge-js.config.json found for \(target.name), skipping...") - continue + bridgeJSTargets[swiftTarget.name] = swiftTarget + } + return bridgeJSTargets + } + + private func targetsInDependencyOrder( + _ bridgeJSTargets: [String: SwiftSourceModuleTarget] + ) -> [SwiftSourceModuleTarget] { + var visitedTargetNames = Set() + var orderedTargets: [SwiftSourceModuleTarget] = [] + func visit(_ target: SwiftSourceModuleTarget) { + if !visitedTargetNames.insert(target.name).inserted { + return } - guard predicate(target) else { - continue + for dependency in target.recursiveTargetDependencies { + if let dependencyTarget = bridgeJSTargets[dependency.name] { + visit(dependencyTarget) + } } - try runSingleTarget(target: target, remainingArguments: remainingArguments) + orderedTargets.append(target) + } + for target in bridgeJSTargets.values.sorted(by: { $0.name < $1.name }) { + visit(target) + } + return orderedTargets + } + + func runOnTargets( + remainingArguments: [String], + where predicate: (SwiftSourceModuleTarget) -> Bool + ) throws { + let allBridgeJSTargets = collectBridgeJSTargets() + let requestedTargets = allBridgeJSTargets.filter { predicate($1) } + for target in targetsInDependencyOrder(requestedTargets) { + try runSingleTarget( + target: target, + bridgeJSTargets: allBridgeJSTargets, + remainingArguments: remainingArguments + ) } } private func runSingleTarget( target: SwiftSourceModuleTarget, + bridgeJSTargets: [String: SwiftSourceModuleTarget], remainingArguments: [String] ) throws { printStderr("Generating bridge code for \(target.name)...") @@ -126,6 +160,25 @@ extension BridgeJSCommandPlugin.Context { ]) } + for dependency in target.recursiveTargetDependencies { + guard let dependencyTarget = bridgeJSTargets[dependency.name] else { continue } + let dependencySkeletonPath = dependencyTarget.directoryURL + .appending(path: "Generated/JavaScript/BridgeJS.json") + guard FileManager.default.fileExists(atPath: dependencySkeletonPath.path) else { + throw BridgeJSCommandPluginError( + """ + Dependency '\(dependencyTarget.name)' is configured for BridgeJS, but its AOT skeleton has not been generated yet. \ + Run `swift package bridge-js --target \(dependencyTarget.name)` to generate it first, \ + or run without `--target` to process in dependency order. + """ + ) + } + generateArguments.append(contentsOf: [ + "--dependency-skeleton", + "\(dependencyTarget.name)=\(dependencySkeletonPath.path)", + ]) + } + generateArguments.append( contentsOf: target.sourceFiles.filter { !$0.url.path.hasPrefix(generatedDirectory.path + "/") @@ -162,6 +215,14 @@ private func printStderr(_ message: String) { fputs(message + "\n", stderr) } +struct BridgeJSCommandPluginError: Error, CustomStringConvertible { + let description: String + + init(_ message: String) { + self.description = message + } +} + extension SwiftSourceModuleTarget { func hasDependency(named name: String) -> Bool { return dependencies.contains(where: { diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift new file mode 100644 index 000000000..91fd4388a --- /dev/null +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExternalModuleIndex.swift @@ -0,0 +1,93 @@ +#if canImport(BridgeJSSkeleton) +import BridgeJSSkeleton +#endif + +/// Index of `@JS` types from dependencies. +public struct ExternalModuleIndex { + public struct ExternalType: Equatable { + public let moduleName: String + public let bridgeType: BridgeType + } + + public enum LookupResult: Equatable { + case unique(ExternalType) + case ambiguous(candidates: [ExternalType]) + } + + public static var empty: ExternalModuleIndex { + ExternalModuleIndex(dependencies: []) + } + + private let byModuleAndPath: [String: [String: ExternalType]] + private let byPath: [String: [ExternalType]] + + public var moduleNames: Set { Set(byModuleAndPath.keys) } + + public init(dependencies: [(moduleName: String, skeleton: BridgeJSSkeleton)]) { + var entriesByModule: [String: [String: ExternalType]] = [:] + var entriesByDotPath: [String: [ExternalType]] = [:] + + for (moduleName, skeleton) in dependencies { + guard let exported = skeleton.exported else { continue } + var moduleEntries = entriesByModule[moduleName] ?? [:] + + func register(dotPath: String, bridgeType: BridgeType) { + let externalType = ExternalType(moduleName: moduleName, bridgeType: bridgeType) + if moduleEntries[dotPath] == nil { + moduleEntries[dotPath] = externalType + entriesByDotPath[dotPath, default: []].append(externalType) + } + } + + for klass in exported.classes { + register(dotPath: klass.swiftCallName, bridgeType: .swiftHeapObject(klass.swiftCallName)) + } + for structDef in exported.structs { + register(dotPath: structDef.swiftCallName, bridgeType: .swiftStruct(structDef.swiftCallName)) + } + for enumDef in exported.enums { + let bridgeType: BridgeType + switch enumDef.enumType { + case .simple: + bridgeType = .caseEnum(enumDef.swiftCallName) + case .rawValue: + guard let rawType = enumDef.rawType else { continue } + bridgeType = .rawValueEnum(enumDef.swiftCallName, rawType) + case .associatedValue: + bridgeType = .associatedValueEnum(enumDef.swiftCallName) + case .namespace: + bridgeType = .namespaceEnum(enumDef.swiftCallName) + } + register(dotPath: enumDef.swiftCallName, bridgeType: bridgeType) + } + for proto in exported.protocols { + register(dotPath: proto.name, bridgeType: .swiftProtocol(proto.name)) + } + + entriesByModule[moduleName] = moduleEntries + } + + self.byModuleAndPath = entriesByModule + self.byPath = entriesByDotPath + } + + public var isEmpty: Bool { byModuleAndPath.isEmpty } + + public func isKnownModule(_ name: String) -> Bool { + byModuleAndPath[name] != nil + } + + public func lookup(dotPath: String) -> LookupResult? { + guard let matches = byPath[dotPath], !matches.isEmpty else { return nil } + if matches.count == 1 { + return .unique(matches[0]) + } + return .ambiguous(candidates: matches) + } + + public func lookup(dotPath: String, module moduleName: String) -> LookupResult? { + guard let moduleEntries = byModuleAndPath[moduleName] else { return nil } + guard let externalType = moduleEntries[dotPath] else { return nil } + return .unique(externalType) + } +} diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 3d8f417e3..42ba2fbaa 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -18,15 +18,25 @@ public final class SwiftToSkeleton { public let exposeToGlobal: Bool public let identityMode: String? - private var sourceFiles: [(sourceFile: SourceFileSyntax, inputFilePath: String)] = [] let typeDeclResolver: TypeDeclResolver + let externalModuleIndex: ExternalModuleIndex - public init(progress: ProgressReporting, moduleName: String, exposeToGlobal: Bool, identityMode: String? = nil) { + private var sourceFiles: [(sourceFile: SourceFileSyntax, inputFilePath: String)] = [] + private var usedExternalModules = Set() + + public init( + progress: ProgressReporting, + moduleName: String, + exposeToGlobal: Bool, + externalModuleIndex: ExternalModuleIndex, + identityMode: String? = nil + ) { self.progress = progress self.moduleName = moduleName self.exposeToGlobal = exposeToGlobal self.identityMode = identityMode self.typeDeclResolver = TypeDeclResolver() + self.externalModuleIndex = externalModuleIndex // Index known types provided by JavaScriptKit self.typeDeclResolver.addSourceFile( @@ -110,7 +120,12 @@ public final class SwiftToSkeleton { }() let exportedSkeleton: ExportedSkeleton? = exported.isEmpty ? nil : exported - return BridgeJSSkeleton(moduleName: moduleName, exported: exportedSkeleton, imported: importedSkeleton) + return BridgeJSSkeleton( + moduleName: moduleName, + exported: exportedSkeleton, + imported: importedSkeleton, + usedExternalModules: usedExternalModules.sorted() + ) } func lookupType(for type: TypeSyntax, errors: inout [DiagnosticError]) -> BridgeType? { @@ -303,79 +318,130 @@ public final class SwiftToSkeleton { return primitiveType } - guard let typeDecl = typeDeclResolver.resolve(type) else { - errors.append( - DiagnosticError( - node: type, - message: "Unsupported type '\(type.trimmedDescription)'.", - hint: "Only primitive types and types defined in the same module are allowed" - ) - ) - return nil - } - - if typeDecl.is(ProtocolDeclSyntax.self) { - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) - return .swiftProtocol(swiftCallName) - } + if let typeDecl = typeDeclResolver.resolve(type) { + if typeDecl.is(ProtocolDeclSyntax.self) { + let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) + return .swiftProtocol(swiftCallName) + } - if let enumDecl = typeDecl.as(EnumDeclSyntax.self) { - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: enumDecl, itemName: enumDecl.name.text) - let rawTypeString = enumDecl.inheritanceClause?.inheritedTypes.first { inheritedType in - let typeName = inheritedType.type.trimmedDescription - return ExportSwiftConstants.supportedRawTypes.contains(typeName) - }?.type.trimmedDescription + if let enumDecl = typeDecl.as(EnumDeclSyntax.self) { + let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: enumDecl, itemName: enumDecl.name.text) + let rawTypeString = enumDecl.inheritanceClause?.inheritedTypes.first { inheritedType in + let typeName = inheritedType.type.trimmedDescription + return ExportSwiftConstants.supportedRawTypes.contains(typeName) + }?.type.trimmedDescription - if let rawType = SwiftEnumRawType(rawTypeString) { - return .rawValueEnum(swiftCallName, rawType) - } else { - let hasAnyCases = enumDecl.memberBlock.members.contains { member in - member.decl.is(EnumCaseDeclSyntax.self) - } - if !hasAnyCases { - return .namespaceEnum(swiftCallName) - } - let hasAssociatedValues = - enumDecl.memberBlock.members.contains { member in - guard let caseDecl = member.decl.as(EnumCaseDeclSyntax.self) else { return false } - return caseDecl.elements.contains { element in - if let params = element.parameterClause?.parameters { - return !params.isEmpty + if let rawType = SwiftEnumRawType(rawTypeString) { + return .rawValueEnum(swiftCallName, rawType) + } else { + let hasAnyCases = enumDecl.memberBlock.members.contains { member in + member.decl.is(EnumCaseDeclSyntax.self) + } + if !hasAnyCases { + return .namespaceEnum(swiftCallName) + } + let hasAssociatedValues = + enumDecl.memberBlock.members.contains { member in + guard let caseDecl = member.decl.as(EnumCaseDeclSyntax.self) else { return false } + return caseDecl.elements.contains { element in + if let params = element.parameterClause?.parameters { + return !params.isEmpty + } + return false } - return false } + if hasAssociatedValues { + return .associatedValueEnum(swiftCallName) + } else { + return .caseEnum(swiftCallName) } - if hasAssociatedValues { - return .associatedValueEnum(swiftCallName) - } else { - return .caseEnum(swiftCallName) } } - } - if let structDecl = typeDecl.as(StructDeclSyntax.self) { - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: structDecl, itemName: structDecl.name.text) - if structDecl.attributes.hasAttribute(name: "JSClass") { + if let structDecl = typeDecl.as(StructDeclSyntax.self) { + let swiftCallName = SwiftToSkeleton.computeSwiftCallName( + for: structDecl, + itemName: structDecl.name.text + ) + if structDecl.attributes.hasAttribute(name: "JSClass") { + return .jsObject(swiftCallName) + } + return .swiftStruct(swiftCallName) + } + + guard typeDecl.is(ClassDeclSyntax.self) || typeDecl.is(ActorDeclSyntax.self) else { + return nil + } + let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) + + // A type annotated with @JSClass is a JavaScript object wrapper (imported), + // even if it is declared as a Swift class. + if let classDecl = typeDecl.as(ClassDeclSyntax.self), classDecl.attributes.hasAttribute(name: "JSClass") { + return .jsObject(swiftCallName) + } + if let actorDecl = typeDecl.as(ActorDeclSyntax.self), actorDecl.attributes.hasAttribute(name: "JSClass") { return .jsObject(swiftCallName) } - return .swiftStruct(swiftCallName) + + return .swiftHeapObject(swiftCallName) + } + + if let externalType = resolveExternal(for: type, errors: &errors) { + return externalType } - guard typeDecl.is(ClassDeclSyntax.self) || typeDecl.is(ActorDeclSyntax.self) else { + errors.append( + DiagnosticError( + node: type, + message: "Unsupported type '\(type.trimmedDescription)'.", + hint: + "Only primitive types, types defined in the same module, and " + + "`@JS` types from dependency targets that apply the BridgeJS plugin are allowed" + ) + ) + return nil + } + + private func resolveExternal(for type: TypeSyntax, errors: inout [DiagnosticError]) -> BridgeType? { + guard + !externalModuleIndex.isEmpty, + var components = typeDeclResolver.qualifiedComponents(from: type) + else { return nil } - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) - // A type annotated with @JSClass is a JavaScript object wrapper (imported), - // even if it is declared as a Swift class. - if let classDecl = typeDecl.as(ClassDeclSyntax.self), classDecl.attributes.hasAttribute(name: "JSClass") { - return .jsObject(swiftCallName) + var scopedModule: String? = nil + if components.count >= 2, externalModuleIndex.isKnownModule(components[0]) { + scopedModule = components[0] + components.removeFirst() } - if let actorDecl = typeDecl.as(ActorDeclSyntax.self), actorDecl.attributes.hasAttribute(name: "JSClass") { - return .jsObject(swiftCallName) + + let dotPath = components.joined(separator: ".") + let lookupResult: ExternalModuleIndex.LookupResult? + if let moduleName = scopedModule { + lookupResult = externalModuleIndex.lookup(dotPath: dotPath, module: moduleName) + } else { + lookupResult = externalModuleIndex.lookup(dotPath: dotPath) } - return .swiftHeapObject(swiftCallName) + guard let lookupResult else { return nil } + switch lookupResult { + case .unique(let externalType): + usedExternalModules.insert(externalType.moduleName) + return externalType.bridgeType + case .ambiguous(let candidates): + let moduleNames = candidates.map(\.moduleName).sorted().joined(separator: ", ") + errors.append( + DiagnosticError( + node: type, + message: "ambiguous use of '\(type.trimmedDescription)'", + hint: + "'\(dotPath)' is exported by multiple dependency modules: \(moduleNames). " + + "Qualify with a module name (e.g. '.\(dotPath)') to disambiguate." + ) + ) + return nil + } } fileprivate static func parseUnsafePointerType(_ type: TypeSyntax) -> UnsafePointerType? { diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift index 975c0c9dc..ec04421aa 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift @@ -161,7 +161,7 @@ class TypeDeclResolver { return nil } - private func qualifiedComponents(from type: TypeSyntax) -> QualifiedName? { + func qualifiedComponents(from type: TypeSyntax) -> QualifiedName? { if let m = type.as(MemberTypeSyntax.self) { guard let base = qualifiedComponents(from: TypeSyntax(m.baseType)) else { return nil } return base + [m.name.text] diff --git a/Plugins/BridgeJS/Sources/BridgeJSPluginUtilities/PluginPaths.swift b/Plugins/BridgeJS/Sources/BridgeJSPluginUtilities/PluginPaths.swift new file mode 100644 index 000000000..f95d1adaa --- /dev/null +++ b/Plugins/BridgeJS/Sources/BridgeJSPluginUtilities/PluginPaths.swift @@ -0,0 +1,74 @@ +#if canImport(PackagePlugin) +import struct Foundation.URL + +enum BridgeJSPluginPaths { + static func skeletonURL( + targetName: String, + packageID: String, + buildPluginWorkDirectoryURL workDirectoryURL: URL + ) -> URL { + let pluginsOutputsRootURL = + workDirectoryURL + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + return bridgeJSDirectoryURL( + targetName: targetName, + packageID: packageID, + pluginsOutputsRootURL: pluginsOutputsRootURL + ) + .appending(path: "JavaScript/BridgeJS.json") + } + + static func skeletonURL( + targetName: String, + packageID: String, + commandPluginWorkDirectoryURL workDirectoryURL: URL + ) -> URL { + // workDirectoryURL: ".build/plugins/PackageToJS/outputs/" + // .build/plugins/outputs/[package]/[target]/destination/BridgeJS/JavaScript/BridgeJS.json + let pluginsOutputsRootURL = + workDirectoryURL + .deletingLastPathComponent() + .deletingLastPathComponent() + .appending(path: "outputs") + return bridgeJSDirectoryURL( + targetName: targetName, + packageID: packageID, + pluginsOutputsRootURL: pluginsOutputsRootURL + ) + .appending(path: "JavaScript/BridgeJS.json") + } + + static func bridgeJSSwiftURL( + targetName: String, + packageID: String, + buildPluginWorkDirectoryURL workDirectoryURL: URL + ) -> URL { + let pluginsOutputsRootURL = + workDirectoryURL + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + return bridgeJSDirectoryURL( + targetName: targetName, + packageID: packageID, + pluginsOutputsRootURL: pluginsOutputsRootURL + ) + .appending(path: "BridgeJS.swift") + } + + private static func bridgeJSDirectoryURL( + targetName: String, + packageID: String, + pluginsOutputsRootURL: URL + ) -> URL { + pluginsOutputsRootURL + .appending(path: packageID) + .appending(path: targetName) + .appending(path: "destination/BridgeJS") + } +} +#endif diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 03e6d676a..baf6debd9 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -1239,11 +1239,18 @@ public struct BridgeJSSkeleton: Codable { public let moduleName: String public let exported: ExportedSkeleton? public let imported: ImportedModuleSkeleton? + public let usedExternalModules: [String] - public init(moduleName: String, exported: ExportedSkeleton? = nil, imported: ImportedModuleSkeleton? = nil) { + public init( + moduleName: String, + exported: ExportedSkeleton? = nil, + imported: ImportedModuleSkeleton? = nil, + usedExternalModules: [String] = [] + ) { self.moduleName = moduleName self.exported = exported self.imported = imported + self.usedExternalModules = usedExternalModules } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift index 3e3f27ea1..005af04a8 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift @@ -112,10 +112,18 @@ import BridgeJSUtilities help: "The path to the TypeScript project configuration file (required for .d.ts files)", required: false ), + "dependency-skeleton": OptionRule( + help: "Path to a dependency module's BridgeJS.json, as '='. Repeatable.", + required: false, + repeatable: true + ), ] ) - let (positionalArguments, _, doubleDashOptions) = try parser.parse( - arguments: Array(arguments.dropFirst()) + let parsedArguments = try parser.parse(arguments: Array(arguments.dropFirst())) + let positionalArguments = parsedArguments.positionalArguments + let doubleDashOptions = parsedArguments.doubleDashOptions + let dependencySkeletons = try loadDependencySkeletons( + parsedArguments.repeatedDoubleDashOptions["dependency-skeleton", default: []] ) let progress = ProgressReporting(verbose: doubleDashOptions["verbose"] == "true") let moduleName = doubleDashOptions["module-name"]! @@ -162,10 +170,12 @@ import BridgeJSUtilities inputFiles.append(macrosPath) } } + let externalModuleIndex = ExternalModuleIndex(dependencies: dependencySkeletons) let swiftToSkeleton = SwiftToSkeleton( progress: progress, moduleName: moduleName, exposeToGlobal: config.exposeToGlobal, + externalModuleIndex: externalModuleIndex, identityMode: config.identityMode ) for inputFile in inputFiles.sorted() { @@ -224,7 +234,10 @@ import BridgeJSUtilities // Combine and write unified Swift output let outputSwiftURL = outputDirectory.appending(path: "BridgeJS.swift") let combinedSwift = [closureSupport, exportResult, importResult].compactMap { $0 } - let outputSwift = combineGeneratedSwift(combinedSwift) + let outputSwift = combineGeneratedSwift( + combinedSwift, + importingExternalModules: skeleton.usedExternalModules + ) let shouldWrite = doubleDashOptions["always-write"] == "true" || !outputSwift.isEmpty if shouldWrite { try withSpan("Writing output Swift") { @@ -237,7 +250,14 @@ import BridgeJSUtilities } } - // Write unified skeleton + // Write unified skeleton. + // Note that for the build system to sequence the BridgeJSBuildPlugin correctly, + // the skeleton-to-Swift-output mapping must be injective, i.e. any change to + // the skeleton must produce a change in the Swift output. This is because we + // can’t use the BridgeJS.json file as an outputFile, since it would then be + // treated as a resource and thus included in the generated bundle. The + // invariant currently holds, but if this ever changes the BridgeJS.swift file + // could include a hash of the skeleton to maintain it. let outputSkeletonURL = outputDirectory.appending(path: "JavaScript/BridgeJS.json") try withSpan("Writing output skeleton") { try FileManager.default.createDirectory( @@ -302,14 +322,45 @@ private func writeIfChanged(_ data: Data, to url: URL) throws { try data.write(to: url) } -private func combineGeneratedSwift(_ pieces: [String]) -> String { +private func loadDependencySkeletons( + _ rawArguments: [String] +) throws -> [(moduleName: String, skeleton: BridgeJSSkeleton)] { + var loadedSkeletons: [(moduleName: String, skeleton: BridgeJSSkeleton)] = [] + let decoder = JSONDecoder() + for rawArgument in rawArguments { + guard let equalIndex = rawArgument.firstIndex(of: "="), equalIndex != rawArgument.startIndex else { + throw BridgeJSToolError( + "--dependency-skeleton expects '='; got invalid value '\(rawArgument)'" + ) + } + let moduleName = String(rawArgument[.. String { let trimmedPieces = pieces .map { $0.trimmingCharacters(in: .newlines) } .filter { !$0.isEmpty } guard !trimmedPieces.isEmpty else { return "" } - return ([BridgeJSGeneratedFile.swiftPreamble] + trimmedPieces).joined(separator: "\n\n") + let imports = BridgeJSGeneratedFile.swiftImports(["JavaScriptKit"] + externalModules) + return ([BridgeJSGeneratedFile.swiftHeader, imports] + trimmedPieces).joined(separator: "\n\n") } private func recursivelyCollectSwiftFiles(from directory: URL) -> [URL] { @@ -365,6 +416,7 @@ extension Profiling { struct OptionRule { var help: String var required: Bool = false + var repeatable: Bool = false } struct ArgumentParser { @@ -377,11 +429,12 @@ struct ArgumentParser { self.doubleDashOptions = doubleDashOptions } - typealias ParsedArguments = ( - positionalArguments: [String], - singleDashOptions: [String: String], - doubleDashOptions: [String: String] - ) + struct ParsedArguments { + var positionalArguments: [String] + var singleDashOptions: [String: String] + var doubleDashOptions: [String: String] + var repeatedDoubleDashOptions: [String: [String]] + } func help() -> String { var help = "Usage: \(CommandLine.arguments.first ?? "bridge-js-tool") [options] \n\n" @@ -404,6 +457,7 @@ struct ArgumentParser { var positionalArguments: [String] = [] var singleDashOptions: [String: String] = [:] var doubleDashOptions: [String: String] = [:] + var repeatedDoubleDashOptions: [String: [String]] = [:] var arguments = arguments.makeIterator() @@ -412,7 +466,12 @@ struct ArgumentParser { if arg.starts(with: "--") { let key = String(arg.dropFirst(2)) let value = arguments.next() - doubleDashOptions[key] = value + if self.doubleDashOptions[key]?.repeatable ?? false { + guard let value else { continue } + repeatedDoubleDashOptions[key, default: []].append(value) + } else { + doubleDashOptions[key] = value + } } else { let key = String(arg.dropFirst(1)) let value = arguments.next() @@ -424,11 +483,16 @@ struct ArgumentParser { } for (key, rule) in self.doubleDashOptions { - if rule.required, doubleDashOptions[key] == nil { + if rule.required, doubleDashOptions[key] == nil, repeatedDoubleDashOptions[key] == nil { throw BridgeJSToolError("Option --\(key) is required") } } - return (positionalArguments, singleDashOptions, doubleDashOptions) + return ParsedArguments( + positionalArguments: positionalArguments, + singleDashOptions: singleDashOptions, + doubleDashOptions: doubleDashOptions, + repeatedDoubleDashOptions: repeatedDoubleDashOptions + ) } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift index 8a6a6b7b4..f4de24093 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift @@ -48,7 +48,8 @@ import ArgumentParser let swiftToSkeleton = SwiftToSkeleton( progress: ProgressReporting(verbose: false), moduleName: "InternalModule", - exposeToGlobal: false + exposeToGlobal: false, + externalModuleIndex: .empty ) for inputFile in inputFiles.sorted() { let content = try String(decoding: readData(from: inputFile), as: UTF8.self) diff --git a/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift b/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift index 68c07f225..8a4171718 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift @@ -13,7 +13,7 @@ public enum BridgeJSGeneratedFile { content.starts(with: skipLine + "\n") } - public static var swiftPreamble: String { + public static var swiftHeader: String { // The generated Swift file itself should not be processed by BridgeJS again. """ \(skipLine) @@ -22,10 +22,12 @@ public enum BridgeJSGeneratedFile { // // To update this file, just rebuild your project or run // `swift package bridge-js`. - - @_spi(BridgeJS) import JavaScriptKit """ } + + public static func swiftImports(_ moduleNames: [String]) -> String { + moduleNames.map { "@_spi(BridgeJS) import \($0)" }.joined(separator: "\n") + } } /// A printer for code fragments. diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index dd0ce5d03..8b8e8b8a2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -77,7 +77,12 @@ import Testing let url = Self.inputsDirectory.appendingPathComponent(input) let name = url.deletingPathExtension().lastPathComponent let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) swiftAPI.addSourceFile(sourceFile, inputFilePath: input) let skeleton = try swiftAPI.finalize() try snapshotCodegen(skeleton: skeleton, name: name) @@ -93,7 +98,12 @@ import Testing let url = Self.inputsDirectory.appendingPathComponent(input) let name = url.deletingPathExtension().lastPathComponent let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: true) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: true, + externalModuleIndex: .empty + ) swiftAPI.addSourceFile(sourceFile, inputFilePath: input) let skeleton = try swiftAPI.finalize() try snapshotCodegen(skeleton: skeleton, name: name + ".Global") @@ -101,7 +111,12 @@ import Testing @Test func codegenCrossFileTypeResolution() throws { - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) let classBURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileClassB.swift") swiftAPI.addSourceFile( Parser.parse(source: try String(contentsOf: classBURL, encoding: .utf8)), @@ -118,7 +133,12 @@ import Testing @Test func codegenCrossFileTypeResolutionReverseOrder() throws { - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) let classAURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileClassA.swift") swiftAPI.addSourceFile( Parser.parse(source: try String(contentsOf: classAURL, encoding: .utf8)), @@ -135,7 +155,12 @@ import Testing @Test func codegenCrossFileFunctionTypes() throws { - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) let functionBURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileFunctionB.swift") swiftAPI.addSourceFile( Parser.parse(source: try String(contentsOf: functionBURL, encoding: .utf8)), @@ -152,7 +177,12 @@ import Testing @Test func codegenCrossFileFunctionTypesReverseOrder() throws { - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) let functionAURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileFunctionA.swift") swiftAPI.addSourceFile( Parser.parse(source: try String(contentsOf: functionAURL, encoding: .utf8)), @@ -169,7 +199,12 @@ import Testing @Test func codegenCrossFileExtension() throws { - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) let classURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtensionClass.swift") swiftAPI.addSourceFile( Parser.parse(source: try String(contentsOf: classURL, encoding: .utf8)), @@ -186,7 +221,12 @@ import Testing @Test func codegenSkipsEmptySkeletons() throws { - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) let importedURL = Self.multifileInputsDirectory.appendingPathComponent("ImportedFunctions.swift") swiftAPI.addSourceFile( Parser.parse(source: try String(contentsOf: importedURL, encoding: .utf8)), diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift index 64c9ae535..2f3f46fdb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSLinkTests.swift @@ -49,7 +49,12 @@ import Testing 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) + 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) @@ -69,7 +74,12 @@ import Testing func snapshotExportWithGlobal(inputFile: String) throws { let url = Self.inputsDirectory.appendingPathComponent(inputFile) let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8)) - let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: true) + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: true, + externalModuleIndex: .empty + ) swiftAPI.addSourceFile(sourceFile, inputFilePath: inputFile) let name = url.deletingPathExtension().lastPathComponent let outputSkeleton = try swiftAPI.finalize() @@ -86,13 +96,23 @@ import Testing func snapshotMixedModuleExposure() throws { let globalURL = Self.inputsDirectory.appendingPathComponent("MixedGlobal.swift") let globalSourceFile = Parser.parse(source: try String(contentsOf: globalURL, encoding: .utf8)) - let globalAPI = SwiftToSkeleton(progress: .silent, moduleName: "GlobalModule", exposeToGlobal: true) + let globalAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "GlobalModule", + exposeToGlobal: true, + externalModuleIndex: .empty + ) globalAPI.addSourceFile(globalSourceFile, inputFilePath: "MixedGlobal.swift") let globalSkeleton = try globalAPI.finalize() let privateURL = Self.inputsDirectory.appendingPathComponent("MixedPrivate.swift") let privateSourceFile = Parser.parse(source: try String(contentsOf: privateURL, encoding: .utf8)) - let privateAPI = SwiftToSkeleton(progress: .silent, moduleName: "PrivateModule", exposeToGlobal: false) + let privateAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "PrivateModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) privateAPI.addSourceFile(privateSourceFile, inputFilePath: "MixedPrivate.swift") let privateSkeleton = try privateAPI.finalize() @@ -114,6 +134,7 @@ import Testing progress: .silent, moduleName: "TestModule", exposeToGlobal: false, + externalModuleIndex: .empty, identityMode: nil // no config default ) swiftAPI.addSourceFile(sourceFile, inputFilePath: "IdentityModeClass.swift") @@ -140,6 +161,7 @@ import Testing progress: .silent, moduleName: "TestModule", exposeToGlobal: false, + externalModuleIndex: .empty, identityMode: "pointer" // config says pointer for all classes ) swiftAPI.addSourceFile(sourceFile, inputFilePath: "IdentityModeClass.swift") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/CrossModuleResolutionTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CrossModuleResolutionTests.swift new file mode 100644 index 000000000..4f12a88fa --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/CrossModuleResolutionTests.swift @@ -0,0 +1,491 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +@Suite struct CrossModuleResolutionTests { + @Test + func resolvesTopLevelExternalStruct() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: """ + @JS public struct Vector3D { + public let x: Double + public let y: Double + public let z: Double + @JS public init(x: Double, y: Double, z: Double) { + self.x = x; self.y = y; self.z = z + } + } + """ + ) + let app = try resolveApp( + source: """ + import Core + @JS public func currentVelocity() -> Vector3D { + Vector3D(x: 0, y: 0, z: 0) + } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + #expect(app.usedExternalModules == ["Core"]) + let function = try #require(app.exported?.functions.first(where: { $0.name == "currentVelocity" })) + #expect(function.returnType == .swiftStruct("Vector3D")) + } + + @Test + func resolvesTopLevelExternalClass() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: """ + @JS public class Emitter { + @JS public init() {} + @JS public func emit() -> String { "" } + } + """ + ) + let app = try resolveApp( + source: """ + import Core + @JS public func makeEmitter() -> Emitter { Emitter() } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + #expect(app.usedExternalModules == ["Core"]) + let function = try #require(app.exported?.functions.first(where: { $0.name == "makeEmitter" })) + #expect(function.returnType == .swiftHeapObject("Emitter")) + } + + @Test + func resolvesNestedExternalStruct() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: """ + @JS public enum Geometry { + @JS public struct BoundingBox { + public let side: Double + @JS public init(side: Double) { self.side = side } + } + } + """ + ) + let app = try resolveApp( + source: """ + import Core + @JS public func unitBox() -> Geometry.BoundingBox { + Geometry.BoundingBox(side: 1) + } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + #expect(app.usedExternalModules == ["Core"]) + let function = try #require(app.exported?.functions.first(where: { $0.name == "unitBox" })) + #expect(function.returnType == .swiftStruct("Geometry.BoundingBox")) + } + + @Test + func resolvesExplicitModuleQualifier() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: """ + @JS public struct Vector3D { + @JS public init() {} + } + """ + ) + let app = try resolveApp( + source: """ + import Core + @JS public func fromCore() -> Core.Vector3D { Core.Vector3D() } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "fromCore" })) + #expect(function.returnType == .swiftStruct("Vector3D")) + } + + @Test + func resolvesExternalTypeInArrayAndOptional() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: """ + @JS public struct Point { + @JS public init() {} + } + """ + ) + let app = try resolveApp( + source: """ + import Core + @JS public func scatter(points: [Point?]) -> Point? { nil } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "scatter" })) + #expect(function.returnType == .nullable(.swiftStruct("Point"), .null)) + #expect(function.parameters.first?.type == .array(.nullable(.swiftStruct("Point"), .null))) + } + + // MARK: - Diagnostics + + @Test + func ambiguousExternalNameProducesDiagnostic() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let graphics = try buildDependencySkeleton( + moduleName: "Graphics", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + + do { + _ = try resolveApp( + source: """ + import Core + import Graphics + @JS public func ambiguous() -> Vector3D { fatalError() } + """, + dependencies: [ + (moduleName: "Core", skeleton: core), + (moduleName: "Graphics", skeleton: graphics), + ] + ) + Issue.record("Expected ambiguity diagnostic, but resolution succeeded") + } catch let error as BridgeJSCoreDiagnosticError { + let combined = error.diagnostics.map(\.diagnostic.message).joined(separator: "\n") + #expect(combined.contains("ambiguous use of 'Vector3D'")) + let combinedHints = error.diagnostics.compactMap(\.diagnostic.hint).joined(separator: "\n") + #expect(combinedHints.contains("Core")) + #expect(combinedHints.contains("Graphics")) + } + } + + @Test + func explicitQualifierResolvesAmbiguity() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let graphics = try buildDependencySkeleton( + moduleName: "Graphics", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let app = try resolveApp( + source: """ + import Core + import Graphics + @JS public func fromCore() -> Core.Vector3D { Core.Vector3D() } + """, + dependencies: [ + (moduleName: "Core", skeleton: core), + (moduleName: "Graphics", skeleton: graphics), + ] + ) + #expect(app.usedExternalModules == ["Core"]) + } + + @Test + func localDeclarationShadowsExternalSameName() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let app = try resolveApp( + source: """ + import Core + @JS public struct Vector3D { + public let id: Int + @JS public init(id: Int) { self.id = id } + } + @JS public func makeLocal() -> Vector3D { Vector3D(id: 42) } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + // Local declaration wins. + #expect(app.usedExternalModules == []) + let exported = try #require(app.exported) + #expect(exported.structs.contains(where: { $0.name == "Vector3D" })) + } + + @Test + func unknownTypeEmitsHintMentioningDependencyTargets() throws { + do { + _ = try resolveApp( + source: """ + @JS public func use() -> MissingType { fatalError() } + """, + dependencies: [] + ) + Issue.record("Expected an unsupported-type diagnostic") + } catch let error as BridgeJSCoreDiagnosticError { + let combinedHints = error.diagnostics.compactMap(\.diagnostic.hint).joined(separator: "\n") + #expect(combinedHints.contains("dependency targets")) + } + } + + // MARK: - Coverage across type categories + + @Test + func resolvesExternalSimpleEnum() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public enum Direction { case north, south }" + ) + let app = try resolveApp( + source: """ + import Core + @JS public func opposite(_ d: Direction) -> Direction { d } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "opposite" })) + #expect(function.returnType == .caseEnum("Direction")) + #expect(function.parameters.first?.type == .caseEnum("Direction")) + } + + @Test + func resolvesExternalRawValueEnum() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public enum HTTPMethod: String { case get, post }" + ) + let app = try resolveApp( + source: """ + import Core + @JS public func describe(_ m: HTTPMethod) -> String { "" } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "describe" })) + #expect(function.parameters.first?.type == .rawValueEnum("HTTPMethod", .string)) + } + + @Test + func resolvesExternalAssociatedValueEnum() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public enum Shape { case point, circle(radius: Double) }" + ) + let app = try resolveApp( + source: """ + import Core + @JS public func area(_ s: Shape) -> Double { 0 } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "area" })) + #expect(function.parameters.first?.type == .associatedValueEnum("Shape")) + } + + @Test + func resolvesExternalNamespaceEnum() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: """ + @JS public enum Utils { + @JS public static func hello() -> String { "hi" } + } + """ + ) + let app = try resolveApp( + source: """ + import Core + @JS public func dummy(_ u: Utils?) -> Utils? { u } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "dummy" })) + #expect(function.returnType == .nullable(.namespaceEnum("Utils"), .null)) + } + + // MARK: - Structural positions + + @Test + func resolvesExternalInDictionaryValuePosition() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let app = try resolveApp( + source: """ + import Core + @JS public func names(_ map: [String: Vector3D]) -> [String] { [] } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "names" })) + #expect(function.parameters.first?.type == .dictionary(.swiftStruct("Vector3D"))) + } + + @Test + func resolvesExternalInStructPropertyType() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let app = try resolveApp( + source: """ + import Core + @JS public struct Particle { + public let position: Vector3D + @JS public init(position: Vector3D) { self.position = position } + } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let particle = try #require(app.exported?.structs.first(where: { $0.name == "Particle" })) + let positionProperty = try #require(particle.properties.first(where: { $0.name == "position" })) + #expect(positionProperty.type == .swiftStruct("Vector3D")) + #expect(app.usedExternalModules == ["Core"]) + } + + // MARK: - Multi-module scenarios + + @Test + func tracksMultipleExternalModulesInSortedOrder() throws { + let alpha = try buildDependencySkeleton( + moduleName: "Alpha", + source: "@JS public struct A { @JS public init() {} }" + ) + let beta = try buildDependencySkeleton( + moduleName: "Beta", + source: "@JS public struct B { @JS public init() {} }" + ) + let app = try resolveApp( + source: """ + import Alpha + import Beta + @JS public func both(_ a: A, _ b: B) -> String { "" } + """, + dependencies: [ + (moduleName: "Beta", skeleton: beta), + (moduleName: "Alpha", skeleton: alpha), + ] + ) + #expect(app.usedExternalModules == ["Alpha", "Beta"]) + } + + @Test + func transitiveDependencyTypesResolve() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let domain = try buildDependencySkeleton( + moduleName: "Domain", + source: """ + @JS public struct Particle { + public let position: Vector3D + @JS public init(position: Vector3D) { self.position = position } + } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + #expect(domain.usedExternalModules == ["Core"]) + // App can still reference Vector3D through Domain’s transitive dependency on Core. + let app = try resolveApp( + source: """ + import Core + import Domain + @JS public func position(of p: Particle) -> Vector3D { p.position } + """, + dependencies: [ + (moduleName: "Core", skeleton: core), + (moduleName: "Domain", skeleton: domain), + ] + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "position" })) + #expect(function.returnType == .swiftStruct("Vector3D")) + #expect(function.parameters.first?.type == .swiftStruct("Particle")) + #expect(app.usedExternalModules == ["Core", "Domain"]) + } + + // MARK: - Skeleton serialisation round-trip + + @Test + func skeletonRoundTripsUsedExternalModules() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + let app = try resolveApp( + source: """ + import Core + @JS public func origin() -> Vector3D { Vector3D() } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys] + let data = try encoder.encode(app) + let decoded = try JSONDecoder().decode(BridgeJSSkeleton.self, from: data) + #expect(decoded.usedExternalModules == app.usedExternalModules) + #expect(decoded.moduleName == app.moduleName) + } + + @Test + func externalModuleIndexSkipsDependenciesWithoutExportedTypes() throws { + let empty = BridgeJSSkeleton(moduleName: "Empty") + let index = ExternalModuleIndex(dependencies: [(moduleName: "Empty", skeleton: empty)]) + #expect(index.isEmpty) + #expect(!index.isKnownModule("Empty")) + #expect(index.lookup(dotPath: "Whatever") == nil) + } + + @Test + func moduleQualifierRejectsUnknownModule() throws { + let core = try buildDependencySkeleton( + moduleName: "Core", + source: "@JS public struct Vector3D { @JS public init() {} }" + ) + do { + _ = try resolveApp( + source: """ + import Core + @JS public func useFoundation() -> Foundation.URL { fatalError() } + """, + dependencies: [(moduleName: "Core", skeleton: core)] + ) + Issue.record("Expected unsupported-type diagnostic for Foundation.URL") + } catch let error as BridgeJSCoreDiagnosticError { + let combinedMessages = error.diagnostics.map(\.diagnostic.message).joined(separator: "\n") + #expect(combinedMessages.contains("Foundation.URL")) + } + } + + // MARK: - Utillites + + private func resolveApp( + source appSource: String, + dependencies: [(moduleName: String, skeleton: BridgeJSSkeleton)] + ) throws -> BridgeJSSkeleton { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "App", + exposeToGlobal: false, + externalModuleIndex: ExternalModuleIndex(dependencies: dependencies) + ) + let sourceFile = Parser.parse(source: appSource) + swiftAPI.addSourceFile(sourceFile, inputFilePath: "App.swift") + return try swiftAPI.finalize() + } + + private func buildDependencySkeleton( + moduleName: String, + source: String, + 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() + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json index d071d8c52..89b64c157 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json @@ -1531,5 +1531,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json index a2b95cc24..27ba89aca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json @@ -189,5 +189,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json index 263578d20..616a0bdbd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json @@ -147,5 +147,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json index 972a532c6..e6f4c2395 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json @@ -63,5 +63,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json index f77d39ad9..4c8d575b0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json @@ -78,5 +78,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.json index 9b056b650..6c589de87 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.ReverseOrder.json @@ -148,5 +148,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.json index d76a1622d..9bec040f1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileFunctionTypes.json @@ -148,5 +148,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json index a0c2c80c6..3bb67f13c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json @@ -29,5 +29,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json index 59fb8484a..edf8177c1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.ReverseOrder.json @@ -61,5 +61,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json index cc10331a4..58bfadab7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileTypeResolution.json @@ -61,5 +61,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json index f8a23c33d..e7874c072 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DefaultParameters.json @@ -1312,5 +1312,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json index e18586e1c..c52f3e82f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json @@ -337,5 +337,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json index b92cee954..873c5c49f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValue.json @@ -1455,5 +1455,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json index ea32ad739..c4095b502 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCase.json @@ -323,5 +323,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json index 46dbe8917..103a67999 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.json @@ -639,5 +639,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json index a57703b09..f9890d36b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.json @@ -639,5 +639,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json index fc4a7ae52..b51940be9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json @@ -1573,5 +1573,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json index 15a20f72e..4b7e5ceb2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json @@ -507,5 +507,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json index f750fc6a5..bafea5d81 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json @@ -57,5 +57,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json index 809a9ad99..5acb585fe 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json @@ -125,5 +125,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json index d7a9064dc..f4a4440c6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/IdentityModeClass.json @@ -144,5 +144,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json index 3f9cb8e32..7ae3363db 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json @@ -74,5 +74,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json index f57e77d21..aa71b40b9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json @@ -198,5 +198,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json index 1ad99f397..6edbc671c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json @@ -267,5 +267,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json index ef8eba9ba..b12f099b6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json @@ -181,5 +181,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json index 18f7cfaac..c0d885b89 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json @@ -160,5 +160,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json index fb8601ae7..05e5b9d3b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json @@ -381,5 +381,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.json index f140fd007..0d30063ee 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedGlobal.json @@ -75,5 +75,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.json index 9e9dc445e..e6bcf2e5c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/MixedPrivate.json @@ -75,5 +75,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json index 080f9f959..4b6b720f1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json @@ -289,5 +289,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json index d471eeaca..3c07b7dcf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json @@ -289,5 +289,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json index 3e6d6c60c..26479bf1d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json @@ -1557,5 +1557,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json index cf76f3878..539f8132a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json @@ -125,5 +125,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json index b0398c161..1cdce90a6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json @@ -150,5 +150,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json index 24e3f44cd..281538dd6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PropertyTypes.json @@ -377,5 +377,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json index b46d1125e..feca4615b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Protocol.json @@ -970,5 +970,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json index 36d6941d3..70273f8b3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ProtocolInClosure.json @@ -282,5 +282,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json index e20af8a3b..800018440 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -483,5 +483,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index ded6f7602..36110488c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -483,5 +483,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json index d14f9b0a3..1cbe44619 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.Global.json @@ -351,5 +351,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json index 35d740dff..8fc0667b0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticProperties.json @@ -351,5 +351,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json index 75462af81..3ffadf65d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json @@ -131,5 +131,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json index 1088a5cab..63ee8e54b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json @@ -60,5 +60,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index ceda64904..f25e1bda7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -275,5 +275,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json index 41662e48b..abca80150 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json @@ -1875,5 +1875,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json index a78b1bf5d..9187f5574 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json @@ -123,5 +123,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 4c1ef582b..bfde01318 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -712,5 +712,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json index ccd3043ac..6c8f9a33f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json @@ -107,5 +107,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.json index 02796479f..942e5fb45 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.json @@ -33,5 +33,8 @@ ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.json index 1eb9e47ec..a382778e9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/UnsafePointer.json @@ -412,5 +412,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json index 7f19c18bf..fd2e4c565 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json @@ -60,5 +60,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Plugins/PackageToJS/Sources/BridgeJSPluginUtilities b/Plugins/PackageToJS/Sources/BridgeJSPluginUtilities new file mode 120000 index 000000000..97aa4a1cc --- /dev/null +++ b/Plugins/PackageToJS/Sources/BridgeJSPluginUtilities @@ -0,0 +1 @@ +../../BridgeJS/Sources/BridgeJSPluginUtilities \ No newline at end of file diff --git a/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift b/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift index 7e335c68e..7686372f9 100644 --- a/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift +++ b/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift @@ -748,15 +748,15 @@ class SkeletonCollector { } } if let target = target as? SwiftSourceModuleTarget { - let directories = [ - target.directoryURL.appending(path: "Generated/JavaScript"), - // context.pluginWorkDirectoryURL: ".build/plugins/PackageToJS/outputs/" - // .build/plugins/outputs/[package]/[target]/destination/BridgeJS/JavaScript/BridgeJS.json - context.pluginWorkDirectoryURL.deletingLastPathComponent().deletingLastPathComponent() - .appending(path: "outputs/\(package.id)/\(target.name)/destination/BridgeJS/JavaScript"), + let candidates = [ + target.directoryURL.appending(path: "Generated/JavaScript").appending(path: skeletonFile), + BridgeJSPluginPaths.skeletonURL( + targetName: target.name, + packageID: package.id, + commandPluginWorkDirectoryURL: context.pluginWorkDirectoryURL + ), ] - for directory in directories { - let skeletonURL = directory.appending(path: skeletonFile) + for skeletonURL in candidates { if FileManager.default.fileExists(atPath: skeletonURL.path) { skeletons.append(skeletonURL) } diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md index 0bd69aa5b..b8856ac30 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/BridgeJS-Configuration.md @@ -12,6 +12,8 @@ The configuration system supports two complementary files: - `bridge-js.config.json` - Base configuration (checked into version control) - `bridge-js.config.local.json` - Local overrides (intended to be ignored by git, for developer-specific settings) +> Note: The presence of a configuration file, even if empty, is required to expose `@JS` types to other modules in the package. See `Examples/MultiModule/` for an example. + ## Configuration Loading ### File Locations diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Setting-up-BridgeJS.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Setting-up-BridgeJS.md index 99a3d5b1c..5b9616105 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Setting-up-BridgeJS.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Setting-up-BridgeJS.md @@ -58,3 +58,7 @@ For package layout and how to consume the output from JavaScript, see . + +## Multiple targets in one package + +A single package can have multiple targets that use `@JS`. Apply the BridgeJS plugin to every target that contains `@JS` declarations. To make a target's `@JS` types visible to other targets in the same package, also add a `bridge-js.config.json` file (`{}` is enough) to that target’s source directory. See `Examples/MultiModule/` for an example. diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md index 7ba25f7ae..83213aca1 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Unsupported-Features.md @@ -8,13 +8,11 @@ BridgeJS generates glue code per Swift target (module). Some patterns that are v ## Type usage crossing module boundary -BridgeJS does **not** support using a type across module boundaries in the following situations. +### Exporting Swift: extending types from another Swift module -### Exporting Swift: types from another Swift module +If you have multiple Swift targets (e.g. a library and an app), you **cannot** extend a type defined in one target with a `@JS` exported API in another target. -If you have multiple Swift targets (e.g. a library and an app), you **cannot** use a type defined in one target in an exported API of another target. - -**Unsupported example:** Module `App` exports a function that takes or returns a type defined in module `Lib`: +**Unsupported example:** Module `App` extends a type defined in module `Lib`: ```swift // In module Lib @@ -24,5 +22,15 @@ If you have multiple Swift targets (e.g. a library and an app), you **cannot** u } // In module App (depends on Lib) - unsupported -@JS public func transform(_ p: LibPoint) -> LibPoint { ... } +extension LibPoint { + @JS public func transformed() -> LibPoint { ... } +} ``` + +### Exporting Swift: non-`@JS` types from another Swift module + +While using `@JS` types from another Swift module is supported, it is not possible to use non-`@JS` types defined in other modules: this will fail at type lookup. + +### Exporting Swift: types from another Swift package + +Types defined in a separate Swift package cannot yet be referenced from `@JS` declarations in your package. diff --git a/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json index f57f91936..5e9626840 100644 --- a/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSGlobalTests/Generated/JavaScript/BridgeJS.json @@ -559,5 +559,8 @@ ] }, - "moduleName" : "BridgeJSGlobalTests" + "moduleName" : "BridgeJSGlobalTests", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json index fc1504c37..7687430a7 100644 --- a/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json @@ -459,5 +459,8 @@ } ] }, - "moduleName" : "BridgeJSIdentityTests" + "moduleName" : "BridgeJSIdentityTests", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index dd4362fc1..e396662b9 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -20481,5 +20481,8 @@ } ] }, - "moduleName" : "BridgeJSRuntimeTests" + "moduleName" : "BridgeJSRuntimeTests", + "usedExternalModules" : [ + + ] } \ No newline at end of file From f483b91988d054f932f915ebce01ae3a7c473bf7 Mon Sep 17 00:00:00 2001 From: Matthew Ayers Date: Thu, 30 Apr 2026 02:51:15 -0400 Subject: [PATCH 41/68] [BridgeJS] Synthesize typed-closure init access from declaration surface (#709) (#727) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [BridgeJS] Synthesize typed-closure init access from declaration surface Resolves swiftwasm/JavaScriptKit#709: a public `@JSClass` exposing a `JSTypedClosure<...>` parameter could not be consumed from another target because the synthesized `extension JSTypedClosure { init(...) }` was always internal, leaving downstream callers no way to construct the closure value without hand-rolling a public wrapper. Imported skeleton entries now record the source access level (`public`/`package`/`internal`); the closure-signature collector takes the maximum across every surface that references a given signature, and `ClosureCodegen` prefixes the synthesized init with the resulting modifier (internal stays bare). This matches the pattern `JSClassMacro` already uses for `init(unsafelyWrapping:)`. * [BridgeJS] Address PR feedback and refresh generated artifacts - Make `accessLevel` decode-tolerant on imported skeleton structs (`ImportedFunctionSkeleton`, `ImportedConstructorSkeleton`, `ImportedGetterSkeleton`, `ImportedSetterSkeleton`, `ImportedTypeSkeleton`) by writing explicit `init(from:)` decoders that fall back to `.internal` when the key is missing. Without this, any pre-existing skeleton JSON without the new field fails decoding — the `build-examples` CI job hit `DecodingError.keyNotFound` for `accessLevel` against externally consumed skeletons. - Extract a private `recordSignature` helper so `visitClosure` and `recordInjectedSignature` share a single merge implementation. - Assert in `withAccessLevel(rawLevel:)` so unknown access strings ("open", "private", future schema additions) surface in debug builds instead of silently inheriting the outer level. - Document the `.internal` seeding assumption on `ClosureSignatureCollectorVisitor.init(moduleName:signatures:)`. - Regenerate the BridgeJS pre-generated artifacts under Benchmarks/, Examples/PlayBridgeJS/, Tests/BridgeJSIdentityTests/, and Tests/BridgeJSRuntimeTests/ via `./Utilities/bridge-js-generate.sh`, per CONTRIBUTING.md. The runtime-tests Swift output now emits `public init` on three `JSTypedClosure` extensions whose signatures surface through public exported types. * [BridgeJS] Refresh identity tests skeleton after merge with main #731 added the GC lifecycle test (with new imported function entries) to main while this branch was open. Re-running the BridgeJS regen against the merged tree fills in the `accessLevel` field on the new entries that were absent at merge time. * ci: retry flaky JSPromiseTests.testPromiseAndTimer --- .../Generated/JavaScript/BridgeJS.json | 3 + .../Generated/JavaScript/BridgeJS.json | 3 + .../Sources/BridgeJSCore/ClosureCodegen.swift | 17 +- .../BridgeJSCore/SwiftToSkeleton.swift | 64 +++- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 356 +++++++++++++++--- .../MacroSwift/SwiftTypedClosureAccess.swift | 26 ++ .../BridgeJSCodegenTests/ArrayTypes.json | 7 + .../BridgeJSCodegenTests/AsyncImport.json | 6 + .../AsyncStaticImport.json | 3 + .../CrossFileSkipsEmptySkeletons.json | 1 + .../BridgeJSCodegenTests/DictionaryTypes.json | 1 + .../BridgeJSCodegenTests/EnumRawType.json | 2 + .../FixedWidthIntegers.json | 8 + .../BridgeJSCodegenTests/GlobalGetter.json | 3 + .../GlobalThisImports.json | 7 + .../BridgeJSCodegenTests/ImportArray.json | 2 + .../ImportedTypeInExportedInterface.json | 2 + .../InvalidPropertyNames.json | 24 ++ .../BridgeJSCodegenTests/JSClass.json | 11 + .../JSClassStaticFunctions.json | 9 + .../BridgeJSCodegenTests/JSValue.json | 2 + .../BridgeJSCodegenTests/Optionals.json | 26 ++ .../PrimitiveParameters.json | 1 + .../BridgeJSCodegenTests/PrimitiveReturn.json | 2 + .../BridgeJSCodegenTests/StringParameter.json | 2 + .../BridgeJSCodegenTests/StringReturn.json | 1 + .../BridgeJSCodegenTests/SwiftClass.json | 2 + .../SwiftClosureImports.json | 2 + .../SwiftStructImports.json | 1 + .../SwiftTypedClosureAccess.json | 285 ++++++++++++++ .../SwiftTypedClosureAccess.swift | 266 +++++++++++++ .../VoidParameterVoidReturn.json | 1 + .../SwiftTypedClosureAccess.d.ts | 33 ++ .../SwiftTypedClosureAccess.js | 329 ++++++++++++++++ .../Generated/JavaScript/BridgeJS.json | 3 + .../Generated/BridgeJS.swift | 6 +- .../Generated/JavaScript/BridgeJS.json | 164 ++++++++ 37 files changed, 1606 insertions(+), 75 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftTypedClosureAccess.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js diff --git a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json index 8e9c1cd6b..7209c62f7 100644 --- a/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json +++ b/Benchmarks/Sources/Generated/JavaScript/BridgeJS.json @@ -3339,6 +3339,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -3355,6 +3356,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -3378,6 +3380,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json index 89ce6ae3a..6f1fc940c 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.json @@ -242,6 +242,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -260,11 +261,13 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index f3ed97ba3..45cfb73f1 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -21,7 +21,10 @@ public struct ClosureCodegen { return "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)" } - func renderClosureHelpers(_ signature: ClosureSignature) throws -> [DeclSyntax] { + func renderClosureHelpers( + _ signature: ClosureSignature, + accessLevel: BridgeJSAccessLevel = .internal + ) throws -> [DeclSyntax] { let mangledName = signature.mangleName let helperName = "_BJS_Closure_\(mangledName)" let swiftClosureType = swiftClosureType(for: signature) @@ -99,9 +102,10 @@ public struct ClosureCodegen { let helperEnumDecl: DeclSyntax = "\(raw: helperEnumDeclPrinter.lines.joined(separator: "\n"))" + let initAccessModifier = accessLevel.modifierKeyword.map { "\($0) " } ?? "" let typedClosureExtension: DeclSyntax = """ extension JSTypedClosure where Signature == \(raw: swiftClosureType) { - init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \(raw: swiftClosureType)) { + \(raw: initAccessModifier)init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \(raw: swiftClosureType)) { self.init( makeClosure: \(raw: externABIName), body: body, @@ -192,12 +196,13 @@ public struct ClosureCodegen { let collector = ClosureSignatureCollectorVisitor(moduleName: skeleton.moduleName) var walker = BridgeSkeletonWalker(visitor: collector) walker.walk(skeleton) - let closureSignatures = walker.visitor.signatures - guard !closureSignatures.isEmpty else { return nil } + let signatureAccessLevels = walker.visitor.signatureAccessLevels + guard !signatureAccessLevels.isEmpty else { return nil } var decls: [DeclSyntax] = [] - for signature in closureSignatures.sorted(by: { $0.mangleName < $1.mangleName }) { - decls.append(contentsOf: try renderClosureHelpers(signature)) + for signature in signatureAccessLevels.keys.sorted(by: { $0.mangleName < $1.mangleName }) { + let accessLevel = signatureAccessLevels[signature] ?? .internal + decls.append(contentsOf: try renderClosureHelpers(signature, accessLevel: accessLevel)) decls.append(try renderClosureInvokeHandler(signature)) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 42ba2fbaa..61306bf2c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -2122,6 +2122,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { let name: String let jsName: String? let from: JSImportFrom? + let accessLevel: BridgeJSAccessLevel var constructor: ImportedConstructorSkeleton? var methods: [ImportedFunctionSkeleton] var staticMethods: [ImportedFunctionSkeleton] @@ -2337,6 +2338,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { name: typeName, jsName: nil, from: nil, + accessLevel: .internal, constructor: nil, methods: [], staticMethods: [], @@ -2345,12 +2347,18 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { ) } - private func enterJSClass(_ typeName: String, jsName: String?, from: JSImportFrom?) { + private func enterJSClass( + _ typeName: String, + jsName: String?, + from: JSImportFrom?, + accessLevel: BridgeJSAccessLevel + ) { stateStack.append(.jsClassBody(name: typeName)) currentType = CurrentType( name: typeName, jsName: jsName, from: from, + accessLevel: accessLevel, constructor: nil, methods: [], staticMethods: [], @@ -2371,7 +2379,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { staticMethods: type.staticMethods, getters: type.getters, setters: type.setters, - documentation: nil + documentation: nil, + accessLevel: type.accessLevel ) ) currentType = nil @@ -2384,7 +2393,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { let attribute = AttributeChecker.firstJSClassAttribute(node.attributes) let jsName = attribute.flatMap(AttributeChecker.extractJSName) let from = attribute.flatMap(AttributeChecker.extractJSImportFrom) - enterJSClass(node.name.text, jsName: jsName, from: from) + let accessLevel = Self.bridgeAccessLevel(from: node.modifiers) + enterJSClass(node.name.text, jsName: jsName, from: from, accessLevel: accessLevel) } return .visitChildren } @@ -2400,7 +2410,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { let attribute = AttributeChecker.firstJSClassAttribute(node.attributes) let jsName = attribute.flatMap(AttributeChecker.extractJSName) let from = attribute.flatMap(AttributeChecker.extractJSImportFrom) - enterJSClass(node.name.text, jsName: jsName, from: from) + let accessLevel = Self.bridgeAccessLevel(from: node.modifiers) + enterJSClass(node.name.text, jsName: jsName, from: from, accessLevel: accessLevel) } return .visitChildren } @@ -2565,8 +2576,14 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { else { 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) + parameters: parseParameters(from: initializer.signature.parameterClause), + accessLevel: accessLevel ) } @@ -2599,6 +2616,7 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { } else { returnType = .void } + let accessLevel = Self.bridgeAccessLevel(from: node.modifiers) return ImportedFunctionSkeleton( name: name, jsName: jsName, @@ -2606,7 +2624,8 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { parameters: parameters, returnType: returnType, effects: effects, - documentation: nil + documentation: nil, + accessLevel: accessLevel ) } @@ -2638,13 +2657,15 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { let propertyName = SwiftToSkeleton.normalizeIdentifier(identifier.identifier.text) let jsName = AttributeChecker.extractJSName(from: jsGetter) let from = AttributeChecker.extractJSImportFrom(from: jsGetter) + let accessLevel = Self.bridgeAccessLevel(from: node.modifiers) return ImportedGetterSkeleton( name: propertyName, jsName: jsName, from: from, type: propertyType, documentation: nil, - functionName: nil + functionName: nil, + accessLevel: accessLevel ) } @@ -2667,12 +2688,14 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { return nil } + let accessLevel = Self.bridgeAccessLevel(from: node.modifiers) return ImportedSetterSkeleton( name: propertyName, jsName: validation.jsName, type: validation.valueType, documentation: nil, - functionName: "\(functionBaseName)_set" + functionName: "\(functionBaseName)_set", + accessLevel: accessLevel ) } @@ -2718,6 +2741,31 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { modifier.name.tokenKind == .keyword(.static) || modifier.name.tokenKind == .keyword(.class) } } + + /// Maps Swift's declaration modifiers to a `BridgeJSAccessLevel` for + /// recording on imported skeleton entries. Falls back to `default` when no + /// access modifier is present (typically `.internal`, but the caller may + /// override — e.g. an `init` inheriting from its enclosing `@JSClass`). + /// `private`/`fileprivate` are mapped to the fallback because the macros + /// already reject those access levels for `@JS*` declarations. + fileprivate static func bridgeAccessLevel( + from modifiers: DeclModifierListSyntax, + default fallback: BridgeJSAccessLevel = .internal + ) -> BridgeJSAccessLevel { + for modifier in modifiers { + switch modifier.name.tokenKind { + case .keyword(.public), .keyword(.open): + return .public + case .keyword(.package): + return .package + case .keyword(.internal): + return .internal + default: + continue + } + } + return fallback + } } extension GenericArgumentListSyntax { diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index baf6debd9..055ef2552 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -89,6 +89,38 @@ public enum BridgeContext: Sendable { case exportSwift } +/// Access level applied to bridge-generated declarations. +/// +/// Ordering (`Comparable`) reflects visibility breadth, so taking `max` of two +/// levels yields the more permissive one — used to merge a single closure +/// signature seen across surfaces with different declared access. +public enum BridgeJSAccessLevel: String, Codable, Equatable, Hashable, Sendable, Comparable { + case `internal` + case package + case `public` + + public static func < (lhs: BridgeJSAccessLevel, rhs: BridgeJSAccessLevel) -> Bool { + lhs.order < rhs.order + } + + private var order: Int { + switch self { + case .internal: return 0 + case .package: return 1 + case .public: return 2 + } + } + + /// Returns the modifier keyword to emit, or nil for the default (internal). + public var modifierKeyword: String? { + switch self { + case .internal: return nil + case .package: return "package" + case .public: return "public" + } + } +} + public struct ClosureSignature: Codable, Equatable, Hashable, Sendable { public let parameters: [BridgeType] public let returnType: BridgeType @@ -398,17 +430,34 @@ public struct Parameter: Codable, Equatable, Sendable { // MARK: - BridgeSkeleton Visitor public protocol BridgeSkeletonVisitor { - mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) + /// Called when a closure type is encountered during traversal. + /// + /// `accessLevel` reflects the source access of the enclosing declaration, + /// so visitors can derive an appropriate access level for any + /// bridge-generated helpers tied to this signature (e.g. typed closure + /// inits in `ClosureCodegen`). + mutating func visitClosure( + _ signature: ClosureSignature, + useJSTypedClosure: Bool, + accessLevel: BridgeJSAccessLevel + ) mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) } public extension BridgeSkeletonVisitor { - mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) {} + mutating func visitClosure( + _ signature: ClosureSignature, + useJSTypedClosure: Bool, + accessLevel: BridgeJSAccessLevel + ) {} mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) {} } public struct BridgeSkeletonWalker { public var visitor: Visitor + /// Tracks the access level of the enclosing declaration during traversal. + /// Saved/restored around each declaration that introduces an access boundary. + private var currentAccessLevel: BridgeJSAccessLevel = .internal public init(visitor: Visitor) { self.visitor = visitor @@ -417,7 +466,11 @@ public struct BridgeSkeletonWalker { public mutating func walk(_ type: BridgeType) { switch type { case .closure(let signature, let useJSTypedClosure): - visitor.visitClosure(signature, useJSTypedClosure: useJSTypedClosure) + visitor.visitClosure( + signature, + useJSTypedClosure: useJSTypedClosure, + accessLevel: currentAccessLevel + ) for paramType in signature.parameters { walk(paramType) } @@ -449,14 +502,16 @@ public struct BridgeSkeletonWalker { walk(function) } for klass in skeleton.classes { - if let constructor = klass.constructor { - walk(constructor.parameters) - } - for method in klass.methods { - walk(method) - } - for property in klass.properties { - walk(property.type) + withAccessLevel(klass.explicitAccessControl) { + if let constructor = klass.constructor { + $0.walk(constructor.parameters) + } + for method in klass.methods { + $0.walk(method) + } + for property in klass.properties { + $0.walk(property.type) + } } } for proto in skeleton.protocols { @@ -468,58 +523,66 @@ public struct BridgeSkeletonWalker { } } for structDecl in skeleton.structs { - for property in structDecl.properties { - walk(property.type) - } - if let constructor = structDecl.constructor { - walk(constructor.parameters) - } - for method in structDecl.methods { - walk(method) + withAccessLevel(structDecl.explicitAccessControl) { + for property in structDecl.properties { + $0.walk(property.type) + } + if let constructor = structDecl.constructor { + $0.walk(constructor.parameters) + } + for method in structDecl.methods { + $0.walk(method) + } } } for enumDecl in skeleton.enums { - for enumCase in enumDecl.cases { - for associatedValue in enumCase.associatedValues { - walk(associatedValue.type) + withAccessLevel(enumDecl.explicitAccessControl) { + for enumCase in enumDecl.cases { + for associatedValue in enumCase.associatedValues { + $0.walk(associatedValue.type) + } + } + for method in enumDecl.staticMethods { + $0.walk(method) + } + for property in enumDecl.staticProperties { + $0.walk(property.type) } - } - for method in enumDecl.staticMethods { - walk(method) - } - for property in enumDecl.staticProperties { - walk(property.type) } } } public mutating func walk(_ function: ImportedFunctionSkeleton) { visitor.visitImportedFunction(function) - walk(function.parameters) - walk(function.returnType) + withAccessLevel(function.accessLevel) { + $0.walk(function.parameters) + $0.walk(function.returnType) + } } public mutating func walk(_ skeleton: ImportedModuleSkeleton) { for fileSkeleton in skeleton.children { for getter in fileSkeleton.globalGetters { - walk(getter.type) + withAccessLevel(getter.accessLevel) { $0.walk(getter.type) } } for setter in fileSkeleton.globalSetters { - walk(setter.type) + withAccessLevel(setter.accessLevel) { $0.walk(setter.type) } } for function in fileSkeleton.functions { walk(function) } for type in fileSkeleton.types { - if let constructor = type.constructor { - walk(constructor.parameters) - } - for getter in type.getters { - walk(getter.type) - } - for setter in type.setters { - walk(setter.type) - } - for method in type.methods + type.staticMethods { - walk(method) + withAccessLevel(type.accessLevel) { + if let constructor = type.constructor { + $0.withAccessLevel(constructor.accessLevel) { $0.walk(constructor.parameters) } + } + for getter in type.getters { + $0.withAccessLevel(getter.accessLevel) { $0.walk(getter.type) } + } + for setter in type.setters { + $0.withAccessLevel(setter.accessLevel) { $0.walk(setter.type) } + } + for method in type.methods + type.staticMethods { + $0.walk(method) + } } } } @@ -532,6 +595,40 @@ public struct BridgeSkeletonWalker { walk(imported) } } + + /// Sets `currentAccessLevel` to `level` for the duration of `body`, restoring + /// the prior value afterward. A nil level (e.g. for exported decls without + /// an explicit modifier) inherits the outer level rather than overwriting it. + private mutating func withAccessLevel( + _ level: BridgeJSAccessLevel?, + _ body: (inout BridgeSkeletonWalker) -> Void + ) { + let saved = currentAccessLevel + if let level { + currentAccessLevel = level + } + body(&self) + currentAccessLevel = saved + } + + /// String-typed convenience: maps `"public"`/`"package"`/`"internal"` from + /// `Exported*.explicitAccessControl` to the typed enum. Unknown strings + /// (e.g. `"open"`, `"private"`) hit the assert in debug builds and inherit + /// the outer level in release — the `@JSExport` macros reject those cases + /// upstream, so this is a defensive guard against future schema drift. + private mutating func withAccessLevel( + _ rawLevel: String?, + _ body: (inout BridgeSkeletonWalker) -> Void + ) { + let level: BridgeJSAccessLevel? + if let rawLevel { + level = BridgeJSAccessLevel(rawValue: rawLevel) + assert(level != nil, "Unexpected access level string: \(rawLevel)") + } else { + level = nil + } + withAccessLevel(level, body) + } } public struct Effects: Codable, Equatable, Sendable { @@ -951,6 +1048,10 @@ public struct ImportedFunctionSkeleton: Codable { public let returnType: BridgeType public let effects: Effects public let documentation: String? + /// Source access level of the originating Swift declaration. Used to + /// 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 init( name: String, @@ -959,7 +1060,8 @@ public struct ImportedFunctionSkeleton: Codable { parameters: [Parameter], returnType: BridgeType, effects: Effects = Effects(isAsync: false, isThrows: true), - documentation: String? = nil + documentation: String? = nil, + accessLevel: BridgeJSAccessLevel = .internal ) { self.name = name self.jsName = jsName @@ -968,6 +1070,23 @@ public struct ImportedFunctionSkeleton: Codable { self.returnType = returnType self.effects = effects self.documentation = documentation + self.accessLevel = accessLevel + } + + private enum CodingKeys: String, CodingKey { + case name, jsName, from, parameters, returnType, effects, documentation, accessLevel + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.name = try container.decode(String.self, forKey: .name) + self.jsName = try container.decodeIfPresent(String.self, forKey: .jsName) + self.from = try container.decodeIfPresent(JSImportFrom.self, forKey: .from) + self.parameters = try container.decode([Parameter].self, forKey: .parameters) + self.returnType = try container.decode(BridgeType.self, forKey: .returnType) + 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 } public func abiName(context: ImportedTypeSkeleton?) -> String { @@ -985,9 +1104,23 @@ public struct ImportedFunctionSkeleton: Codable { public struct ImportedConstructorSkeleton: Codable { public let parameters: [Parameter] + /// Source access level of the originating Swift `init`. Inherits from the + /// enclosing `@JSClass` type when not annotated explicitly. + public let accessLevel: BridgeJSAccessLevel - public init(parameters: [Parameter]) { + public init(parameters: [Parameter], accessLevel: BridgeJSAccessLevel = .internal) { self.parameters = parameters + self.accessLevel = accessLevel + } + + private enum CodingKeys: String, CodingKey { + case parameters, accessLevel + } + + 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 } public func abiName(context: ImportedTypeSkeleton) -> String { @@ -1008,6 +1141,8 @@ public struct ImportedGetterSkeleton: Codable { public let documentation: String? /// Name of the getter function if it's a separate function (from @JSGetter) public let functionName: String? + /// Source access level of the originating Swift declaration. + public let accessLevel: BridgeJSAccessLevel public init( name: String, @@ -1015,7 +1150,8 @@ public struct ImportedGetterSkeleton: Codable { from: JSImportFrom? = nil, type: BridgeType, documentation: String? = nil, - functionName: String? = nil + functionName: String? = nil, + accessLevel: BridgeJSAccessLevel = .internal ) { self.name = name self.jsName = jsName @@ -1023,6 +1159,22 @@ public struct ImportedGetterSkeleton: Codable { self.type = type self.documentation = documentation self.functionName = functionName + self.accessLevel = accessLevel + } + + private enum CodingKeys: String, CodingKey { + case name, jsName, from, type, documentation, functionName, accessLevel + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.name = try container.decode(String.self, forKey: .name) + self.jsName = try container.decodeIfPresent(String.self, forKey: .jsName) + self.from = try container.decodeIfPresent(JSImportFrom.self, forKey: .from) + self.type = try container.decode(BridgeType.self, forKey: .type) + self.documentation = try container.decodeIfPresent(String.self, forKey: .documentation) + self.functionName = try container.decodeIfPresent(String.self, forKey: .functionName) + self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal } public func abiName(context: ImportedTypeSkeleton?) -> String { @@ -1049,19 +1201,37 @@ public struct ImportedSetterSkeleton: Codable { public let documentation: String? /// Name of the setter function if it's a separate function (from @JSSetter) public let functionName: String? + /// Source access level of the originating Swift declaration. + public let accessLevel: BridgeJSAccessLevel public init( name: String, jsName: String? = nil, type: BridgeType, documentation: String? = nil, - functionName: String? = nil + functionName: String? = nil, + accessLevel: BridgeJSAccessLevel = .internal ) { self.name = name self.jsName = jsName self.type = type self.documentation = documentation self.functionName = functionName + self.accessLevel = accessLevel + } + + private enum CodingKeys: String, CodingKey { + case name, jsName, type, documentation, functionName, accessLevel + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.name = try container.decode(String.self, forKey: .name) + self.jsName = try container.decodeIfPresent(String.self, forKey: .jsName) + self.type = try container.decode(BridgeType.self, forKey: .type) + self.documentation = try container.decodeIfPresent(String.self, forKey: .documentation) + self.functionName = try container.decodeIfPresent(String.self, forKey: .functionName) + self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal } public func abiName(context: ImportedTypeSkeleton?) -> String { @@ -1093,6 +1263,8 @@ public struct ImportedTypeSkeleton: Codable { public let getters: [ImportedGetterSkeleton] public let setters: [ImportedSetterSkeleton] public let documentation: String? + /// Source access level of the originating Swift `@JSClass` declaration. + public let accessLevel: BridgeJSAccessLevel public init( name: String, @@ -1103,7 +1275,8 @@ public struct ImportedTypeSkeleton: Codable { staticMethods: [ImportedFunctionSkeleton] = [], getters: [ImportedGetterSkeleton] = [], setters: [ImportedSetterSkeleton] = [], - documentation: String? = nil + documentation: String? = nil, + accessLevel: BridgeJSAccessLevel = .internal ) { self.name = name self.jsName = jsName @@ -1114,6 +1287,25 @@ public struct ImportedTypeSkeleton: Codable { self.getters = getters self.setters = setters self.documentation = documentation + self.accessLevel = accessLevel + } + + private enum CodingKeys: String, CodingKey { + case name, jsName, from, constructor, methods, staticMethods, getters, setters, documentation, accessLevel + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.name = try container.decode(String.self, forKey: .name) + self.jsName = try container.decodeIfPresent(String.self, forKey: .jsName) + self.from = try container.decodeIfPresent(JSImportFrom.self, forKey: .from) + self.constructor = try container.decodeIfPresent(ImportedConstructorSkeleton.self, forKey: .constructor) + self.methods = try container.decode([ImportedFunctionSkeleton].self, forKey: .methods) + self.staticMethods = try container.decode([ImportedFunctionSkeleton].self, forKey: .staticMethods) + self.getters = try container.decode([ImportedGetterSkeleton].self, forKey: .getters) + self.setters = try container.decode([ImportedSetterSkeleton].self, forKey: .setters) + self.documentation = try container.decodeIfPresent(String.self, forKey: .documentation) + self.accessLevel = try container.decodeIfPresent(BridgeJSAccessLevel.self, forKey: .accessLevel) ?? .internal } } @@ -1180,16 +1372,50 @@ public struct ImportedModuleSkeleton: Codable { // MARK: - Closure signature collection visitor public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { - public var signatures: Set = [] + /// Each unique closure signature mapped to the most-permissive access level + /// observed across all surfaces that reference it. The codegen reads this + /// to choose the access modifier for the synthesized typed-closure init. + public private(set) var signatureAccessLevels: [ClosureSignature: BridgeJSAccessLevel] = [:] + /// Convenience view for callers (e.g. `BridgeJSLink`) that only need the + /// set of unique signatures, without access metadata. + public var signatures: Set { Set(signatureAccessLevels.keys) } let moduleName: String + /// Convenience for callers that only need to seed signatures without + /// access metadata (e.g. exported-side walking, where closure init access + /// is irrelevant because the synthesized init isn't surfaced to consumers). + /// All seeded signatures default to `.internal`; if a seeded signature is + /// later observed with a more permissive access level, the merge in + /// `recordSignature` upgrades it. public init(moduleName: String, signatures: Set = []) { self.moduleName = moduleName - self.signatures = signatures + for signature in signatures { + signatureAccessLevels[signature] = .internal + } + } + + public mutating func visitClosure( + _ signature: ClosureSignature, + useJSTypedClosure: Bool, + accessLevel: BridgeJSAccessLevel + ) { + recordSignature(signature, accessLevel: accessLevel) } - public mutating func visitClosure(_ signature: ClosureSignature, useJSTypedClosure: Bool) { - signatures.insert(signature) + /// Insert `signature` at `accessLevel`, or upgrade the existing level to + /// the more permissive of the two. Centralizing the merge here keeps + /// `visitClosure` and `recordInjectedSignature` in lockstep — if the + /// merge policy ever needs to change (e.g. adding a diagnostic for + /// conflicting levels), there's only one place to update. + private mutating func recordSignature( + _ signature: ClosureSignature, + accessLevel: BridgeJSAccessLevel + ) { + if let existing = signatureAccessLevels[signature] { + signatureAccessLevels[signature] = max(existing, accessLevel) + } else { + signatureAccessLevels[signature] = accessLevel + } } public mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) { guard function.effects.isAsync else { return } @@ -1202,34 +1428,48 @@ public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { // transferred through the checked continuation without Sendable constraints. // Reject callback - signatures.insert( + recordInjectedSignature( ClosureSignature( parameters: [.jsValue], returnType: .void, moduleName: moduleName, sendingParameters: true - ) + ), + for: function ) // Resolve callback (typed per return type) if function.returnType == .void { - signatures.insert( + recordInjectedSignature( ClosureSignature( parameters: [], returnType: .void, moduleName: moduleName - ) + ), + for: function ) } else { - signatures.insert( + recordInjectedSignature( ClosureSignature( parameters: [function.returnType], returnType: .void, moduleName: moduleName, sendingParameters: true - ) + ), + for: function ) } } + + /// Inject a closure signature derived from an async import (e.g. Promise + /// resolve/reject callbacks). The injected signature inherits the access + /// level of the originating function so its synthesized init matches the + /// visibility of the async API surface. + private mutating func recordInjectedSignature( + _ signature: ClosureSignature, + for function: ImportedFunctionSkeleton + ) { + recordSignature(signature, accessLevel: function.accessLevel) + } } // MARK: - Unified Skeleton diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftTypedClosureAccess.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftTypedClosureAccess.swift new file mode 100644 index 000000000..6487d343b --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftTypedClosureAccess.swift @@ -0,0 +1,26 @@ +// Verifies that `JSTypedClosure` initializers synthesized by BridgeJS adopt the +// access level of the originating `@JSClass`/`@JSFunction` surface, so that +// downstream targets can construct typed closures for public APIs (issue #709). + +@JSClass(jsName: "PublicEvent") public struct JSPublicEvent {} +@JSClass(jsName: "PackageEvent") package struct JSPackageEvent {} +@JSClass(jsName: "InternalEvent") struct JSInternalEvent {} + +@JSClass(jsName: "PublicTarget") public struct JSPublicTarget { + // A public method taking a typed closure must yield a `public` synthesized init, + // since downstream modules may construct the closure value. + @JSFunction public func addPublicListener(_ handler: JSTypedClosure<(JSPublicEvent) -> Void>) throws(JSException) + // Same closure shape on an internal method — the synthesized init merges to public, + // because at most one extension per signature is generated. + @JSFunction func addInternalListener(_ handler: JSTypedClosure<(JSPublicEvent) -> Void>) throws(JSException) +} + +@JSClass(jsName: "PackageTarget") package struct JSPackageTarget { + // A package-level surface yields a `package` synthesized init. + @JSFunction package func addPackageListener(_ handler: JSTypedClosure<(JSPackageEvent) -> Void>) throws(JSException) +} + +@JSClass(jsName: "InternalTarget") struct JSInternalTarget { + // No public/package surface for this signature — the synthesized init stays internal. + @JSFunction func addInternalListener(_ handler: JSTypedClosure<(JSInternalEvent) -> Void>) throws(JSException) +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json index 89b64c157..d4ac7a15f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ArrayTypes.json @@ -1331,6 +1331,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1354,6 +1355,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1385,6 +1387,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1412,6 +1415,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1432,6 +1436,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1463,6 +1468,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1494,6 +1500,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json index 616a0bdbd..7f66bede4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncImport.json @@ -4,6 +4,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -20,6 +21,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -49,6 +51,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -72,6 +75,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -95,6 +99,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -118,6 +123,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json index e6f4c2395..2aea1c115 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncStaticImport.json @@ -7,6 +7,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -19,6 +20,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -42,6 +44,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json index 3bb67f13c..ff90a4cab 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileSkipsEmptySkeletons.json @@ -4,6 +4,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json index c52f3e82f..b1185c644 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/DictionaryTypes.json @@ -300,6 +300,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json index b51940be9..1cf99cd39 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumRawType.json @@ -1526,6 +1526,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1550,6 +1551,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json index 4b7e5ceb2..1186ad27d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/FixedWidthIntegers.json @@ -269,6 +269,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -298,6 +299,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -327,6 +329,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -356,6 +359,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -385,6 +389,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -414,6 +419,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -443,6 +449,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -472,6 +479,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json index bafea5d81..83353291c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalGetter.json @@ -7,6 +7,7 @@ ], "globalGetters" : [ { + "accessLevel" : "internal", "name" : "console", "type" : { "jsObject" : { @@ -17,11 +18,13 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json index 5acb585fe..5f6a08da9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/GlobalThisImports.json @@ -4,6 +4,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -31,6 +32,7 @@ ], "globalGetters" : [ { + "accessLevel" : "internal", "from" : "global", "name" : "console", "type" : { @@ -42,11 +44,13 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -79,7 +83,9 @@ ] }, { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "url", @@ -97,6 +103,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json index 7ae3363db..7bf447ad5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.json @@ -4,6 +4,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -41,6 +42,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json index aa71b40b9..600ae8c89 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.json @@ -175,7 +175,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ ] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json index 6edbc671c..7cc1d81a8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/InvalidPropertyNames.json @@ -4,6 +4,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20,6 +21,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -38,8 +40,10 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ { + "accessLevel" : "internal", "name" : "normalProperty", "type" : { "string" : { @@ -48,6 +52,7 @@ } }, { + "accessLevel" : "internal", "jsName" : "property-with-dashes", "name" : "property_with_dashes", "type" : { @@ -57,6 +62,7 @@ } }, { + "accessLevel" : "internal", "jsName" : "123invalidStart", "name" : "_123invalidStart", "type" : { @@ -66,6 +72,7 @@ } }, { + "accessLevel" : "internal", "jsName" : "property with spaces", "name" : "property_with_spaces", "type" : { @@ -75,6 +82,7 @@ } }, { + "accessLevel" : "internal", "jsName" : "@specialChar", "name" : "_specialChar", "type" : { @@ -84,6 +92,7 @@ } }, { + "accessLevel" : "internal", "name" : "constructor", "type" : { "string" : { @@ -92,6 +101,7 @@ } }, { + "accessLevel" : "internal", "name" : "for", "type" : { "string" : { @@ -100,6 +110,7 @@ } }, { + "accessLevel" : "internal", "name" : "Any", "type" : { "string" : { @@ -110,6 +121,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -126,6 +138,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -145,6 +158,7 @@ "name" : "WeirdNaming", "setters" : [ { + "accessLevel" : "internal", "functionName" : "normalProperty_set", "name" : "normalProperty", "type" : { @@ -154,6 +168,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "property_with_dashes_set", "jsName" : "property-with-dashes", "name" : "property_with_dashes", @@ -164,6 +179,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "_123invalidStart_set", "jsName" : "123invalidStart", "name" : "_123invalidStart", @@ -174,6 +190,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "property_with_spaces_set", "jsName" : "property with spaces", "name" : "property_with_spaces", @@ -184,6 +201,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "_specialChar_set", "jsName" : "@specialChar", "name" : "_specialChar", @@ -194,6 +212,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "constructor_set", "name" : "constructor", "type" : { @@ -203,6 +222,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "for_set", "name" : "for", "type" : { @@ -212,6 +232,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "any_set", "jsName" : "Any", "name" : "any", @@ -227,7 +248,9 @@ ] }, { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ ] @@ -238,6 +261,7 @@ "jsName" : "$Weird", "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json index b12f099b6..2455e5e6d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClass.json @@ -4,6 +4,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -22,7 +23,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "name", @@ -36,6 +39,7 @@ }, "getters" : [ { + "accessLevel" : "internal", "name" : "name", "type" : { "string" : { @@ -44,6 +48,7 @@ } }, { + "accessLevel" : "internal", "name" : "age", "type" : { "double" : { @@ -54,6 +59,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -70,6 +76,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -96,6 +103,7 @@ "name" : "Greeter", "setters" : [ { + "accessLevel" : "internal", "functionName" : "name_set", "name" : "name", "type" : { @@ -110,11 +118,13 @@ ] }, { + "accessLevel" : "internal", "getters" : [ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -146,6 +156,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json index c0d885b89..363e8d875 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSClassStaticFunctions.json @@ -7,11 +7,13 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -34,6 +36,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -57,6 +60,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -73,6 +77,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -89,6 +94,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -108,7 +114,9 @@ ] }, { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "value", @@ -132,6 +140,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json index 05e5b9d3b..f0cd29565 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSValue.json @@ -321,6 +321,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -344,6 +345,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json index 26479bf1d..921983115 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json @@ -1008,7 +1008,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "valueOrNull", @@ -1040,6 +1042,7 @@ }, "getters" : [ { + "accessLevel" : "internal", "name" : "stringOrNull", "type" : { "nullable" : { @@ -1053,6 +1056,7 @@ } }, { + "accessLevel" : "internal", "name" : "stringOrUndefined", "type" : { "nullable" : { @@ -1066,6 +1070,7 @@ } }, { + "accessLevel" : "internal", "name" : "doubleOrNull", "type" : { "nullable" : { @@ -1079,6 +1084,7 @@ } }, { + "accessLevel" : "internal", "name" : "doubleOrUndefined", "type" : { "nullable" : { @@ -1092,6 +1098,7 @@ } }, { + "accessLevel" : "internal", "name" : "boolOrNull", "type" : { "nullable" : { @@ -1105,6 +1112,7 @@ } }, { + "accessLevel" : "internal", "name" : "boolOrUndefined", "type" : { "nullable" : { @@ -1118,6 +1126,7 @@ } }, { + "accessLevel" : "internal", "name" : "intOrNull", "type" : { "nullable" : { @@ -1134,6 +1143,7 @@ } }, { + "accessLevel" : "internal", "name" : "intOrUndefined", "type" : { "nullable" : { @@ -1152,6 +1162,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1185,6 +1196,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1218,6 +1230,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1251,6 +1264,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1284,6 +1298,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1317,6 +1332,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1350,6 +1366,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1389,6 +1406,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1431,6 +1449,7 @@ "name" : "WithOptionalJSClass", "setters" : [ { + "accessLevel" : "internal", "functionName" : "stringOrNull_set", "name" : "stringOrNull", "type" : { @@ -1445,6 +1464,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "stringOrUndefined_set", "name" : "stringOrUndefined", "type" : { @@ -1459,6 +1479,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "doubleOrNull_set", "name" : "doubleOrNull", "type" : { @@ -1473,6 +1494,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "doubleOrUndefined_set", "name" : "doubleOrUndefined", "type" : { @@ -1487,6 +1509,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "boolOrNull_set", "name" : "boolOrNull", "type" : { @@ -1501,6 +1524,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "boolOrUndefined_set", "name" : "boolOrUndefined", "type" : { @@ -1515,6 +1539,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "intOrNull_set", "name" : "intOrNull", "type" : { @@ -1532,6 +1557,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "intOrUndefined_set", "name" : "intOrUndefined", "type" : { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json index 539f8132a..320499ff3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveParameters.json @@ -88,6 +88,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json index 1cdce90a6..414fedbbd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/PrimitiveReturn.json @@ -112,6 +112,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -128,6 +129,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json index 3ffadf65d..d9dc0ec43 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringParameter.json @@ -71,6 +71,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -94,6 +95,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json index 63ee8e54b..e2cf9ffac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StringReturn.json @@ -38,6 +38,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index f25e1bda7..a3ddab63e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -213,6 +213,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -236,6 +237,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json index 9187f5574..a84441bb4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json @@ -4,6 +4,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -66,6 +67,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json index 6c8f9a33f..fc59471bb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json @@ -56,6 +56,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json new file mode 100644 index 000000000..e602989a1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json @@ -0,0 +1,285 @@ +{ + "imported" : { + "children" : [ + { + "functions" : [ + + ], + "types" : [ + { + "accessLevel" : "public", + "getters" : [ + + ], + "jsName" : "PublicEvent", + "methods" : [ + + ], + "name" : "JSPublicEvent", + "setters" : [ + + ], + "staticMethods" : [ + + ] + }, + { + "accessLevel" : "package", + "getters" : [ + + ], + "jsName" : "PackageEvent", + "methods" : [ + + ], + "name" : "JSPackageEvent", + "setters" : [ + + ], + "staticMethods" : [ + + ] + }, + { + "accessLevel" : "internal", + "getters" : [ + + ], + "jsName" : "InternalEvent", + "methods" : [ + + ], + "name" : "JSInternalEvent", + "setters" : [ + + ], + "staticMethods" : [ + + ] + }, + { + "accessLevel" : "public", + "getters" : [ + + ], + "jsName" : "PublicTarget", + "methods" : [ + { + "accessLevel" : "public", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "addPublicListener", + "parameters" : [ + { + "name" : "handler", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule13JSPublicEventC_y", + "moduleName" : "TestModule", + "parameters" : [ + { + "jsObject" : { + "_0" : "JSPublicEvent" + } + } + ], + "returnType" : { + "void" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "addInternalListener", + "parameters" : [ + { + "name" : "handler", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule13JSPublicEventC_y", + "moduleName" : "TestModule", + "parameters" : [ + { + "jsObject" : { + "_0" : "JSPublicEvent" + } + } + ], + "returnType" : { + "void" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "void" : { + + } + } + } + ], + "name" : "JSPublicTarget", + "setters" : [ + + ], + "staticMethods" : [ + + ] + }, + { + "accessLevel" : "package", + "getters" : [ + + ], + "jsName" : "PackageTarget", + "methods" : [ + { + "accessLevel" : "package", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "addPackageListener", + "parameters" : [ + { + "name" : "handler", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule14JSPackageEventC_y", + "moduleName" : "TestModule", + "parameters" : [ + { + "jsObject" : { + "_0" : "JSPackageEvent" + } + } + ], + "returnType" : { + "void" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "void" : { + + } + } + } + ], + "name" : "JSPackageTarget", + "setters" : [ + + ], + "staticMethods" : [ + + ] + }, + { + "accessLevel" : "internal", + "getters" : [ + + ], + "jsName" : "InternalTarget", + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "addInternalListener", + "parameters" : [ + { + "name" : "handler", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule15JSInternalEventC_y", + "moduleName" : "TestModule", + "parameters" : [ + { + "jsObject" : { + "_0" : "JSInternalEvent" + } + } + ], + "returnType" : { + "void" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + } + ], + "returnType" : { + "void" : { + + } + } + } + ], + "name" : "JSInternalTarget", + "setters" : [ + + ], + "staticMethods" : [ + + ] + } + ] + } + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.swift new file mode 100644 index 000000000..fbd181fcc --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.swift @@ -0,0 +1,266 @@ +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule13JSPublicEventC_y") +fileprivate func invoke_js_callback_TestModule_10TestModule13JSPublicEventC_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModule13JSPublicEventC_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule13JSPublicEventC_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModule13JSPublicEventC_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule13JSPublicEventC_y") +fileprivate func make_swift_closure_TestModule_10TestModule13JSPublicEventC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule13JSPublicEventC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule13JSPublicEventC_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule13JSPublicEventC_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule13JSPublicEventC_y { + static func bridgeJSLift(_ callbackId: Int32) -> (JSPublicEvent) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModule13JSPublicEventC_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (JSPublicEvent) -> Void { + public init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (JSPublicEvent) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule13JSPublicEventC_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule13JSPublicEventC_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModule13JSPublicEventC_y") +public func _invoke_swift_closure_TestModule_10TestModule13JSPublicEventC_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(JSPublicEvent) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSPublicEvent.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule14JSPackageEventC_y") +fileprivate func invoke_js_callback_TestModule_10TestModule14JSPackageEventC_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModule14JSPackageEventC_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule14JSPackageEventC_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModule14JSPackageEventC_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule14JSPackageEventC_y") +fileprivate func make_swift_closure_TestModule_10TestModule14JSPackageEventC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule14JSPackageEventC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule14JSPackageEventC_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule14JSPackageEventC_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule14JSPackageEventC_y { + static func bridgeJSLift(_ callbackId: Int32) -> (JSPackageEvent) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModule14JSPackageEventC_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (JSPackageEvent) -> Void { + package init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (JSPackageEvent) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule14JSPackageEventC_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule14JSPackageEventC_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModule14JSPackageEventC_y") +public func _invoke_swift_closure_TestModule_10TestModule14JSPackageEventC_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(JSPackageEvent) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSPackageEvent.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule15JSInternalEventC_y") +fileprivate func invoke_js_callback_TestModule_10TestModule15JSInternalEventC_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModule15JSInternalEventC_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule15JSInternalEventC_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModule15JSInternalEventC_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule15JSInternalEventC_y") +fileprivate func make_swift_closure_TestModule_10TestModule15JSInternalEventC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule15JSInternalEventC_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule15JSInternalEventC_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule15JSInternalEventC_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule15JSInternalEventC_y { + static func bridgeJSLift(_ callbackId: Int32) -> (JSInternalEvent) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModule15JSInternalEventC_y(callbackValue, param0Value) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (JSInternalEvent) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (JSInternalEvent) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule15JSInternalEventC_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule15JSInternalEventC_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModule15JSInternalEventC_y") +public func _invoke_swift_closure_TestModule_10TestModule15JSInternalEventC_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(JSInternalEvent) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSInternalEvent.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_JSPublicTarget_addPublicListener") +fileprivate func bjs_JSPublicTarget_addPublicListener_extern(_ self: Int32, _ handler: Int32) -> Void +#else +fileprivate func bjs_JSPublicTarget_addPublicListener_extern(_ self: Int32, _ handler: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSPublicTarget_addPublicListener(_ self: Int32, _ handler: Int32) -> Void { + return bjs_JSPublicTarget_addPublicListener_extern(self, handler) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_JSPublicTarget_addInternalListener") +fileprivate func bjs_JSPublicTarget_addInternalListener_extern(_ self: Int32, _ handler: Int32) -> Void +#else +fileprivate func bjs_JSPublicTarget_addInternalListener_extern(_ self: Int32, _ handler: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSPublicTarget_addInternalListener(_ self: Int32, _ handler: Int32) -> Void { + return bjs_JSPublicTarget_addInternalListener_extern(self, handler) +} + +func _$JSPublicTarget_addPublicListener(_ self: JSObject, _ handler: JSTypedClosure<(JSPublicEvent) -> Void>) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let handlerFuncRef = handler.bridgeJSLowerParameter() + bjs_JSPublicTarget_addPublicListener(selfValue, handlerFuncRef) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$JSPublicTarget_addInternalListener(_ self: JSObject, _ handler: JSTypedClosure<(JSPublicEvent) -> Void>) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let handlerFuncRef = handler.bridgeJSLowerParameter() + bjs_JSPublicTarget_addInternalListener(selfValue, handlerFuncRef) + if let error = _swift_js_take_exception() { + throw error + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_JSPackageTarget_addPackageListener") +fileprivate func bjs_JSPackageTarget_addPackageListener_extern(_ self: Int32, _ handler: Int32) -> Void +#else +fileprivate func bjs_JSPackageTarget_addPackageListener_extern(_ self: Int32, _ handler: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSPackageTarget_addPackageListener(_ self: Int32, _ handler: Int32) -> Void { + return bjs_JSPackageTarget_addPackageListener_extern(self, handler) +} + +func _$JSPackageTarget_addPackageListener(_ self: JSObject, _ handler: JSTypedClosure<(JSPackageEvent) -> Void>) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let handlerFuncRef = handler.bridgeJSLowerParameter() + bjs_JSPackageTarget_addPackageListener(selfValue, handlerFuncRef) + if let error = _swift_js_take_exception() { + throw error + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_JSInternalTarget_addInternalListener") +fileprivate func bjs_JSInternalTarget_addInternalListener_extern(_ self: Int32, _ handler: Int32) -> Void +#else +fileprivate func bjs_JSInternalTarget_addInternalListener_extern(_ self: Int32, _ handler: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSInternalTarget_addInternalListener(_ self: Int32, _ handler: Int32) -> Void { + return bjs_JSInternalTarget_addInternalListener_extern(self, handler) +} + +func _$JSInternalTarget_addInternalListener(_ self: JSObject, _ handler: JSTypedClosure<(JSInternalEvent) -> Void>) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let handlerFuncRef = handler.bridgeJSLowerParameter() + bjs_JSInternalTarget_addInternalListener(selfValue, handlerFuncRef) + if let error = _swift_js_take_exception() { + throw error + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json index fd2e4c565..d31f775fb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/VoidParameterVoidReturn.json @@ -38,6 +38,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts new file mode 100644 index 000000000..99adf95b6 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.d.ts @@ -0,0 +1,33 @@ +// 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 interface JSPublicEvent { +} +export interface JSPackageEvent { +} +export interface JSInternalEvent { +} +export interface JSPublicTarget { + addPublicListener(handler: (arg0: JSPublicEvent) => void): void; + addInternalListener(handler: (arg0: JSPublicEvent) => void): void; +} +export interface JSPackageTarget { + addPackageListener(handler: (arg0: JSPackageEvent) => void): void; +} +export interface JSInternalTarget { + addInternalListener(handler: (arg0: JSInternalEvent) => void): void; +} +export type Exports = { +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js new file mode 100644 index 000000000..4e0fd8341 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js @@ -0,0 +1,329 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.unregistered) { return; } + instance?.exports?.bjs_release_swift_closure(state.pointer); + }); + const makeClosure = (pointer, file, line, func) => { + const state = { pointer, file, line, unregistered: false }; + const real = (...args) => { + if (state.unregistered) { + const bytes = new Uint8Array(memory.buffer, state.file); + let length = 0; + while (bytes[length] !== 0) { length += 1; } + const fileID = decodeString(state.file, length); + throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); + } + return func(...args); + }; + real.__unregister = () => { + if (state.unregistered) { return; } + state.unregistered = true; + swiftClosureRegistry.unregister(state); + }; + swiftClosureRegistry.register(real, state, state); + return swift.memory.retain(real); + }; + + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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(); + } + 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) {} + bjs["swift_js_closure_unregister"] = function(funcRef) { + const func = swift.memory.getObject(funcRef); + func.__unregister(); + } + bjs["invoke_js_callback_TestModule_10TestModule13JSPublicEventC_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(swift.memory.getObject(param0)); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModule13JSPublicEventC_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule13JSPublicEventC_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModule13JSPublicEventC_y(boxPtr, swift.memory.retain(param0)); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule13JSPublicEventC_y); + } + bjs["invoke_js_callback_TestModule_10TestModule14JSPackageEventC_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(swift.memory.getObject(param0)); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModule14JSPackageEventC_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule14JSPackageEventC_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModule14JSPackageEventC_y(boxPtr, swift.memory.retain(param0)); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule14JSPackageEventC_y); + } + bjs["invoke_js_callback_TestModule_10TestModule15JSInternalEventC_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + callback(swift.memory.getObject(param0)); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModule15JSInternalEventC_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule15JSInternalEventC_y = function(param0) { + instance.exports.invoke_swift_closure_TestModule_10TestModule15JSInternalEventC_y(boxPtr, swift.memory.retain(param0)); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule15JSInternalEventC_y); + } + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_JSPublicTarget_addPublicListener"] = function bjs_JSPublicTarget_addPublicListener(self, handler) { + try { + swift.memory.getObject(self).addPublicListener(swift.memory.getObject(handler)); + } catch (error) { + setException(error); + } + } + TestModule["bjs_JSPublicTarget_addInternalListener"] = function bjs_JSPublicTarget_addInternalListener(self, handler) { + try { + swift.memory.getObject(self).addInternalListener(swift.memory.getObject(handler)); + } catch (error) { + setException(error); + } + } + TestModule["bjs_JSPackageTarget_addPackageListener"] = function bjs_JSPackageTarget_addPackageListener(self, handler) { + try { + swift.memory.getObject(self).addPackageListener(swift.memory.getObject(handler)); + } catch (error) { + setException(error); + } + } + TestModule["bjs_JSInternalTarget_addInternalListener"] = function bjs_JSInternalTarget_addInternalListener(self, handler) { + try { + swift.memory.getObject(self).addInternalListener(swift.memory.getObject(handler)); + } 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const exports = { + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json index 7687430a7..56db0a3ed 100644 --- a/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSIdentityTests/Generated/JavaScript/BridgeJS.json @@ -407,6 +407,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -426,6 +427,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -438,6 +440,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index a37a7e4c5..db8962089 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -369,7 +369,7 @@ private enum _BJS_Closure_20BridgeJSRuntimeTests7GreeterC_SS { } extension JSTypedClosure where Signature == (Greeter) -> String { - init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Greeter) -> String) { + public init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Greeter) -> String) { self.init( makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests7GreeterC_SS, body: body, @@ -687,7 +687,7 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSS_7GreeterC { } extension JSTypedClosure where Signature == (String) -> Greeter { - init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) -> Greeter) { + public init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) -> Greeter) { self.init( makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC, body: body, @@ -753,7 +753,7 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSS_SS { } extension JSTypedClosure where Signature == (String) -> String { - init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) -> String) { + public init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) -> String) { self.init( makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_SS, body: body, diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index e396662b9..d9108f2e7 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -16410,7 +16410,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "id", @@ -16424,6 +16426,7 @@ }, "getters" : [ { + "accessLevel" : "internal", "name" : "id", "type" : { "string" : { @@ -16444,6 +16447,7 @@ ] }, { + "accessLevel" : "internal", "getters" : [ ], @@ -16456,6 +16460,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16489,6 +16494,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16526,6 +16532,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16557,6 +16564,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16588,6 +16596,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16619,6 +16628,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16650,6 +16660,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16681,6 +16692,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16712,6 +16724,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16759,6 +16772,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16800,6 +16814,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16841,6 +16856,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16882,6 +16898,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16923,6 +16940,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16964,6 +16982,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -16991,6 +17010,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17011,6 +17031,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17036,6 +17057,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -17048,6 +17070,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17064,6 +17087,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17087,6 +17111,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17110,6 +17135,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17133,6 +17159,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17166,6 +17193,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17199,6 +17227,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17230,6 +17259,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17261,6 +17291,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17292,6 +17323,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -17326,6 +17358,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -17338,6 +17371,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17376,6 +17410,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17414,6 +17449,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17476,6 +17512,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17526,6 +17563,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17576,6 +17614,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17626,6 +17665,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17677,6 +17717,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17719,6 +17760,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17761,6 +17803,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17820,6 +17863,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17879,6 +17923,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17946,6 +17991,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -17984,6 +18030,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18027,6 +18074,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18065,6 +18113,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18081,6 +18130,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18100,6 +18150,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18125,6 +18176,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -18137,6 +18189,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18162,6 +18215,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -18174,6 +18228,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18211,6 +18266,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18242,6 +18298,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18273,6 +18330,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18304,6 +18362,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18335,6 +18394,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18383,7 +18443,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "value", @@ -18397,6 +18459,7 @@ }, "getters" : [ { + "accessLevel" : "internal", "name" : "value", "type" : { "string" : { @@ -18421,6 +18484,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18437,6 +18501,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18460,6 +18525,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18483,6 +18549,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18506,6 +18573,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18529,6 +18597,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18552,6 +18621,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18575,6 +18645,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18598,6 +18669,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18621,6 +18693,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18646,6 +18719,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -18662,6 +18736,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : true, "isStatic" : false, @@ -18685,6 +18760,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18702,6 +18778,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18728,6 +18805,7 @@ ], "globalGetters" : [ { + "accessLevel" : "internal", "from" : "global", "name" : "globalObject1", "type" : { @@ -18739,7 +18817,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "name", @@ -18761,6 +18841,7 @@ }, "getters" : [ { + "accessLevel" : "internal", "name" : "name", "type" : { "string" : { @@ -18769,6 +18850,7 @@ } }, { + "accessLevel" : "internal", "name" : "prefix", "type" : { "string" : { @@ -18779,6 +18861,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18795,6 +18878,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18821,6 +18905,7 @@ "name" : "JsGreeter", "setters" : [ { + "accessLevel" : "internal", "functionName" : "name_set", "name" : "name", "type" : { @@ -18835,8 +18920,10 @@ ] }, { + "accessLevel" : "internal", "getters" : [ { + "accessLevel" : "internal", "name" : "temperature", "type" : { "double" : { @@ -18845,6 +18932,7 @@ } }, { + "accessLevel" : "internal", "name" : "description", "type" : { "string" : { @@ -18853,6 +18941,7 @@ } }, { + "accessLevel" : "internal", "name" : "humidity", "type" : { "double" : { @@ -18867,6 +18956,7 @@ "name" : "WeatherData", "setters" : [ { + "accessLevel" : "internal", "functionName" : "temperature_set", "name" : "temperature", "type" : { @@ -18876,6 +18966,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "description_set", "name" : "description", "type" : { @@ -18885,6 +18976,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "humidity_set", "name" : "humidity", "type" : { @@ -18899,7 +18991,9 @@ ] }, { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ ] @@ -18910,6 +19004,7 @@ "jsName" : "$WeirdClass", "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18936,7 +19031,9 @@ ] }, { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "value", @@ -18953,6 +19050,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18975,6 +19073,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -18998,6 +19097,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19014,6 +19114,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19030,6 +19131,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19049,7 +19151,9 @@ ] }, { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "name", @@ -19080,6 +19184,7 @@ "from" : "global", "getters" : [ { + "accessLevel" : "internal", "name" : "name", "type" : { "string" : { @@ -19088,6 +19193,7 @@ } }, { + "accessLevel" : "internal", "name" : "age", "type" : { "double" : { @@ -19096,6 +19202,7 @@ } }, { + "accessLevel" : "internal", "name" : "isCat", "type" : { "bool" : { @@ -19106,6 +19213,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19122,6 +19230,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19141,6 +19250,7 @@ "name" : "Animal", "setters" : [ { + "accessLevel" : "internal", "functionName" : "name_set", "name" : "name", "type" : { @@ -19150,6 +19260,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "age_set", "name" : "age", "type" : { @@ -19159,6 +19270,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "isCat_set", "name" : "isCat", "type" : { @@ -19177,6 +19289,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19232,6 +19345,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -19244,6 +19358,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19273,6 +19388,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19302,6 +19418,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19331,6 +19448,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19360,6 +19478,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19389,6 +19508,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19418,6 +19538,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19447,6 +19568,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19476,6 +19598,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19505,6 +19628,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19534,6 +19658,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19559,7 +19684,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ { "name" : "numbers", @@ -19592,6 +19719,7 @@ }, "getters" : [ { + "accessLevel" : "internal", "name" : "numbers", "type" : { "array" : { @@ -19607,6 +19735,7 @@ } }, { + "accessLevel" : "internal", "name" : "labels", "type" : { "array" : { @@ -19621,6 +19750,7 @@ ], "methods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19658,6 +19788,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19689,6 +19820,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19719,6 +19851,7 @@ "name" : "JSClassWithArrayMembers", "setters" : [ { + "accessLevel" : "internal", "functionName" : "numbers_set", "name" : "numbers", "type" : { @@ -19735,6 +19868,7 @@ } }, { + "accessLevel" : "internal", "functionName" : "labels_set", "name" : "labels", "type" : { @@ -19753,6 +19887,7 @@ ] }, { + "accessLevel" : "internal", "getters" : [ ], @@ -19765,6 +19900,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19816,7 +19952,9 @@ ], "types" : [ { + "accessLevel" : "internal", "constructor" : { + "accessLevel" : "internal", "parameters" : [ ] @@ -19837,7 +19975,9 @@ ] }, { + "accessLevel" : "public", "constructor" : { + "accessLevel" : "public", "parameters" : [ ] @@ -19858,7 +19998,9 @@ ] }, { + "accessLevel" : "package", "constructor" : { + "accessLevel" : "package", "parameters" : [ ] @@ -19883,6 +20025,7 @@ { "functions" : [ { + "accessLevel" : "package", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19899,6 +20042,7 @@ } }, { + "accessLevel" : "public", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19915,6 +20059,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19931,6 +20076,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19947,6 +20093,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -19973,6 +20120,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -19985,6 +20133,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20024,6 +20173,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20063,6 +20213,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20096,6 +20247,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20129,6 +20281,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20170,6 +20323,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20211,6 +20365,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20252,6 +20407,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20293,6 +20449,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20315,6 +20472,7 @@ { "functions" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20334,6 +20492,7 @@ ], "types" : [ { + "accessLevel" : "internal", "getters" : [ ], @@ -20346,6 +20505,7 @@ ], "staticMethods" : [ { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20369,6 +20529,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20392,6 +20553,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20425,6 +20587,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, @@ -20448,6 +20611,7 @@ } }, { + "accessLevel" : "internal", "effects" : { "isAsync" : false, "isStatic" : false, From 1c107ad27e29562859f114a18bf7bf128f42bd45 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 30 Apr 2026 11:52:53 +0200 Subject: [PATCH 42/68] BridgeJS: Add swift-format-ignore-file to generated Swift sources --- .../Sources/Generated/BridgeJS.Macros.swift | 1 + Benchmarks/Sources/Generated/BridgeJS.swift | 1 + .../Generated/BridgeJS.Macros.swift | 1 + .../PlayBridgeJS/Generated/BridgeJS.swift | 1 + .../Sources/BridgeJSUtilities/Utilities.swift | 1 + .../Sources/TS2Swift/JavaScript/src/cli.js | 1 + .../test/__snapshots__/ts2swift.test.js.snap | 75 ++++++++++++------- .../SwiftTypedClosureAccess.json | 5 +- .../Generated/BridgeJS.swift | 1 + .../Generated/BridgeJS.swift | 1 + .../Generated/BridgeJS.Macros.swift | 1 + .../Generated/BridgeJS.swift | 1 + 12 files changed, 64 insertions(+), 26 deletions(-) diff --git a/Benchmarks/Sources/Generated/BridgeJS.Macros.swift b/Benchmarks/Sources/Generated/BridgeJS.Macros.swift index 40fc29e91..b107d8d3c 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.Macros.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.Macros.swift @@ -1,3 +1,4 @@ +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Benchmarks/Sources/Generated/BridgeJS.swift b/Benchmarks/Sources/Generated/BridgeJS.swift index e199e4a29..384ca35a2 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.swift @@ -1,4 +1,5 @@ // bridge-js: skip +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.Macros.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.Macros.swift index 4a87a6d38..6c9960b02 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.Macros.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.Macros.swift @@ -1,3 +1,4 @@ +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index 056c1c27d..920f2cc2f 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift @@ -1,4 +1,5 @@ // bridge-js: skip +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift b/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift index 8a4171718..cb6e0d0b0 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSUtilities/Utilities.swift @@ -17,6 +17,7 @@ public enum BridgeJSGeneratedFile { // The generated Swift file itself should not be processed by BridgeJS again. """ \(skipLine) + // swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/cli.js b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/cli.js index 17086e92e..c5e89c208 100644 --- a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/cli.js +++ b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/cli.js @@ -149,6 +149,7 @@ export function run(filePaths, options) { } const prelude = [ + "// swift-format-ignore-file", "// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,", "// DO NOT EDIT.", "//", diff --git a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap index 643ac8441..0cb0e3206 100644 --- a/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap +++ b/Plugins/BridgeJS/Sources/TS2Swift/JavaScript/test/__snapshots__/ts2swift.test.js.snap @@ -1,7 +1,8 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`ts2swift > snapshots Swift output for ArrayParameter.d.ts > ArrayParameter 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -24,7 +25,8 @@ exports[`ts2swift > snapshots Swift output for ArrayParameter.d.ts > ArrayParame `; exports[`ts2swift > snapshots Swift output for Async.d.ts > Async 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -49,7 +51,8 @@ exports[`ts2swift > snapshots Swift output for Async.d.ts > Async 1`] = ` `; exports[`ts2swift > snapshots Swift output for CallableConst.d.ts > CallableConst 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -65,7 +68,8 @@ exports[`ts2swift > snapshots Swift output for CallableConst.d.ts > CallableCons `; exports[`ts2swift > snapshots Swift output for Documentation.d.ts > Documentation 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -122,7 +126,8 @@ exports[`ts2swift > snapshots Swift output for Documentation.d.ts > Documentatio `; exports[`ts2swift > snapshots Swift output for ExportAssignment.d.ts > ExportAssignment 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -135,7 +140,8 @@ exports[`ts2swift > snapshots Swift output for ExportAssignment.d.ts > ExportAss `; exports[`ts2swift > snapshots Swift output for Interface.d.ts > Interface 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -153,7 +159,8 @@ exports[`ts2swift > snapshots Swift output for Interface.d.ts > Interface 1`] = `; exports[`ts2swift > snapshots Swift output for InvalidPropertyNames.d.ts > InvalidPropertyNames 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -201,7 +208,8 @@ exports[`ts2swift > snapshots Swift output for InvalidPropertyNames.d.ts > Inval `; exports[`ts2swift > snapshots Swift output for MultipleImportedTypes.d.ts > MultipleImportedTypes 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -238,7 +246,8 @@ exports[`ts2swift > snapshots Swift output for MultipleImportedTypes.d.ts > Mult `; exports[`ts2swift > snapshots Swift output for ObjectLikeTypes.d.ts > ObjectLikeTypes 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -251,7 +260,8 @@ exports[`ts2swift > snapshots Swift output for ObjectLikeTypes.d.ts > ObjectLike `; exports[`ts2swift > snapshots Swift output for OptionalNullUndefined.d.ts > OptionalNullUndefined 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -292,7 +302,8 @@ exports[`ts2swift > snapshots Swift output for OptionalNullUndefined.d.ts > Opti `; exports[`ts2swift > snapshots Swift output for PrimitiveParameters.d.ts > PrimitiveParameters 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -305,7 +316,8 @@ exports[`ts2swift > snapshots Swift output for PrimitiveParameters.d.ts > Primit `; exports[`ts2swift > snapshots Swift output for PrimitiveReturn.d.ts > PrimitiveReturn 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -320,7 +332,8 @@ exports[`ts2swift > snapshots Swift output for PrimitiveReturn.d.ts > PrimitiveR `; exports[`ts2swift > snapshots Swift output for ReExportFrom.d.ts > ReExportFrom 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -338,7 +351,8 @@ exports[`ts2swift > snapshots Swift output for ReExportFrom.d.ts > ReExportFrom `; exports[`ts2swift > snapshots Swift output for RecordDictionary.d.ts > RecordDictionary 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -368,7 +382,8 @@ exports[`ts2swift > snapshots Swift output for RecordDictionary.d.ts > RecordDic `; exports[`ts2swift > snapshots Swift output for StaticProperty.d.ts > StaticProperty 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -384,7 +399,8 @@ exports[`ts2swift > snapshots Swift output for StaticProperty.d.ts > StaticPrope `; exports[`ts2swift > snapshots Swift output for StringEnum.d.ts > StringEnum 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -405,7 +421,8 @@ extension FeatureFlag: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum {} `; exports[`ts2swift > snapshots Swift output for StringLiteralUnion.d.ts > StringLiteralUnion 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -426,7 +443,8 @@ extension Direction: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum {} `; exports[`ts2swift > snapshots Swift output for StringParameter.d.ts > StringParameter 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -441,7 +459,8 @@ exports[`ts2swift > snapshots Swift output for StringParameter.d.ts > StringPara `; exports[`ts2swift > snapshots Swift output for StringReturn.d.ts > StringReturn 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -454,7 +473,8 @@ exports[`ts2swift > snapshots Swift output for StringReturn.d.ts > StringReturn `; exports[`ts2swift > snapshots Swift output for TS2SkeletonLike.d.ts > TS2SkeletonLike 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -480,7 +500,8 @@ exports[`ts2swift > snapshots Swift output for TS2SkeletonLike.d.ts > TS2Skeleto `; exports[`ts2swift > snapshots Swift output for TypeAlias.d.ts > TypeAlias 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -493,7 +514,8 @@ exports[`ts2swift > snapshots Swift output for TypeAlias.d.ts > TypeAlias 1`] = `; exports[`ts2swift > snapshots Swift output for TypeAliasObject.d.ts > TypeAliasObject 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -512,7 +534,8 @@ exports[`ts2swift > snapshots Swift output for TypeAliasObject.d.ts > TypeAliasO `; exports[`ts2swift > snapshots Swift output for TypeScriptClass.d.ts > TypeScriptClass 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -533,7 +556,8 @@ exports[`ts2swift > snapshots Swift output for TypeScriptClass.d.ts > TypeScript `; exports[`ts2swift > snapshots Swift output for VoidParameterVoidReturn.d.ts > VoidParameterVoidReturn 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run @@ -546,7 +570,8 @@ exports[`ts2swift > snapshots Swift output for VoidParameterVoidReturn.d.ts > Vo `; exports[`ts2swift > snapshots Swift output for WebIDLDOMDocs.d.ts > WebIDLDOMDocs 1`] = ` -"// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +"// swift-format-ignore-file +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // // To update this file, just rebuild your project or run diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json index e602989a1..f6c0c6fe1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftTypedClosureAccess.json @@ -281,5 +281,8 @@ } ] }, - "moduleName" : "TestModule" + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] } \ No newline at end of file diff --git a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift index 862debbf0..4e35a1c9f 100644 --- a/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSGlobalTests/Generated/BridgeJS.swift @@ -1,4 +1,5 @@ // bridge-js: skip +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift b/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift index ffab42367..72a8dfdd4 100644 --- a/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSIdentityTests/Generated/BridgeJS.swift @@ -1,4 +1,5 @@ // bridge-js: skip +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift index e3a6eec61..08d0db2a7 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.Macros.swift @@ -1,3 +1,4 @@ +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index db8962089..4d920873d 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -1,4 +1,5 @@ // bridge-js: skip +// swift-format-ignore-file // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, // DO NOT EDIT. // From 6eb6668f78a3d2b8e852c83c9e565a1c75d9dd89 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 30 Apr 2026 13:06:10 +0200 Subject: [PATCH 43/68] BridgeJS: Support nested @JS types inside structs and classes --- .../BridgeJSCore/SwiftToSkeleton.swift | 77 ++++- .../JSClassMacroTests.swift | 58 ++++ .../BridgeJSToolTests/DiagnosticsTests.swift | 69 ++++ .../Inputs/MacroSwift/NestedType.swift | 10 + .../BridgeJSCodegenTests/NestedType.json | 89 +++++ .../BridgeJSCodegenTests/NestedType.swift | 89 +++++ .../BridgeJSLinkTests/NestedType.d.ts | 33 ++ .../BridgeJSLinkTests/NestedType.js | 304 ++++++++++++++++++ 8 files changed, 717 insertions(+), 12 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 61306bf2c..209242e79 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -504,6 +504,14 @@ public final class SwiftToSkeleton { enumDecl.attributes.hasJSAttribute() { swiftPath.insert(enumDecl.name.text, at: 0) + } else if let structDecl = parent.as(StructDeclSyntax.self), + structDecl.attributes.hasJSAttribute() + { + swiftPath.insert(structDecl.name.text, at: 0) + } else if let classDecl = parent.as(ClassDeclSyntax.self), + classDecl.attributes.hasJSAttribute() + { + swiftPath.insert(classDecl.name.text, at: 0) } currentNode = parent.parent } @@ -648,6 +656,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { var state: State { return stateStack.current } + let parent: SwiftToSkeleton init(parent: SwiftToSkeleton) { @@ -1453,6 +1462,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { guard namespaceResult.isValid else { return .skipChildren } + let effectiveNamespace = effectiveNamespace( + resolvedNamespace: namespaceResult.namespace, + parentTypeNamespace: computeParentTypeNamespace(for: node) + ) let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: node, itemName: name) let explicitAccessControl = computeExplicitAtLeastInternalAccessControl( for: node, @@ -1466,10 +1479,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { constructor: nil, methods: [], properties: [], - namespace: namespaceResult.namespace, + namespace: effectiveNamespace, identityMode: classIdentityMode ) - let uniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) + let uniqueKey = makeKey(name: name, namespace: effectiveNamespace) stateStack.push(state: .classBody(name: name, key: uniqueKey)) exportedClassByName[uniqueKey] = exportedClass @@ -1558,6 +1571,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { guard namespaceResult.isValid else { return .skipChildren } + let effectiveNamespace = effectiveNamespace( + resolvedNamespace: namespaceResult.namespace, + parentTypeNamespace: computeParentTypeNamespace(for: node) + ) let emitStyle = extractEnumStyle(from: jsAttribute) ?? .const let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: node, itemName: name) let explicitAccessControl = computeExplicitAtLeastInternalAccessControl( @@ -1566,7 +1583,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { ) let tsFullPath: String - if let namespace = namespaceResult.namespace, !namespace.isEmpty { + if let namespace = effectiveNamespace, !namespace.isEmpty { tsFullPath = namespace.joined(separator: ".") + "." + name } else { tsFullPath = name @@ -1580,13 +1597,13 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { explicitAccessControl: explicitAccessControl, cases: [], // Will be populated in visit(EnumCaseDeclSyntax) rawType: SwiftEnumRawType(rawType), - namespace: namespaceResult.namespace, + namespace: effectiveNamespace, emitStyle: emitStyle, staticMethods: [], staticProperties: [] ) - let enumUniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) + let enumUniqueKey = makeKey(name: name, namespace: effectiveNamespace) exportedEnumByName[enumUniqueKey] = exportedEnum exportedEnumNames.append(enumUniqueKey) @@ -1685,18 +1702,22 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { guard namespaceResult.isValid else { return .skipChildren } + let effectiveNamespace = effectiveNamespace( + resolvedNamespace: namespaceResult.namespace, + parentTypeNamespace: computeParentTypeNamespace(for: node) + ) _ = computeExplicitAtLeastInternalAccessControl( for: node, message: "Protocol visibility must be at least internal" ) - let protocolUniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) + let protocolUniqueKey = makeKey(name: name, namespace: effectiveNamespace) exportedProtocolByName[protocolUniqueKey] = ExportedProtocol( name: name, methods: [], properties: [], - namespace: namespaceResult.namespace + namespace: effectiveNamespace ) stateStack.push(state: .protocolBody(name: name, key: protocolUniqueKey)) @@ -1707,7 +1728,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { if let exportedFunction = visitProtocolMethod( node: funcDecl, protocolName: name, - namespace: namespaceResult.namespace + namespace: effectiveNamespace ) { methods.append(exportedFunction) } @@ -1720,7 +1741,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { name: name, methods: methods, properties: exportedProtocolByName[protocolUniqueKey]?.properties ?? [], - namespace: namespaceResult.namespace + namespace: effectiveNamespace ) exportedProtocolByName[protocolUniqueKey] = exportedProtocol @@ -1742,6 +1763,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { guard namespaceResult.isValid else { return .skipChildren } + let effectiveNamespace = effectiveNamespace( + resolvedNamespace: namespaceResult.namespace, + parentTypeNamespace: computeParentTypeNamespace(for: node) + ) let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: node, itemName: name) let explicitAccessControl = computeExplicitAtLeastInternalAccessControl( for: node, @@ -1791,7 +1816,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { type: fieldType, isReadonly: true, isStatic: false, - namespace: namespaceResult.namespace, + namespace: effectiveNamespace, staticContext: nil ) properties.append(property) @@ -1799,14 +1824,14 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } - let structUniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) + let structUniqueKey = makeKey(name: name, namespace: effectiveNamespace) let exportedStruct = ExportedStruct( name: name, swiftCallName: swiftCallName, explicitAccessControl: explicitAccessControl, properties: properties, methods: [], - namespace: namespaceResult.namespace + namespace: effectiveNamespace ) exportedStructByName[structUniqueKey] = exportedStruct @@ -2035,6 +2060,34 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return namespace.isEmpty ? nil : namespace } + private func computeParentTypeNamespace(for node: some SyntaxProtocol) -> [String]? { + var path: [String] = [] + var currentNode: Syntax? = node.parent + + while let parent = currentNode { + if let structDecl = parent.as(StructDeclSyntax.self), + structDecl.attributes.hasJSAttribute() + { + path.insert(structDecl.name.text, at: 0) + } else if let classDecl = parent.as(ClassDeclSyntax.self), + classDecl.attributes.hasJSAttribute() + { + path.insert(classDecl.name.text, at: 0) + } + currentNode = parent.parent + } + + return path.isEmpty ? nil : path + } + + private func effectiveNamespace( + resolvedNamespace: [String]?, + parentTypeNamespace: [String]? + ) -> [String]? { + let combined = (parentTypeNamespace ?? []) + (resolvedNamespace ?? []) + return combined.isEmpty ? nil : combined + } + /// Requires the node to have at least internal access control. private func computeExplicitAtLeastInternalAccessControl( for node: some WithModifiersSyntax, diff --git a/Plugins/BridgeJS/Tests/BridgeJSMacrosTests/JSClassMacroTests.swift b/Plugins/BridgeJS/Tests/BridgeJSMacrosTests/JSClassMacroTests.swift index 77dc814eb..c52bc9db0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSMacrosTests/JSClassMacroTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSMacrosTests/JSClassMacroTests.swift @@ -445,6 +445,64 @@ import BridgeJSMacros ) } + @Test func nestedJSClassStruct() { + let combinedSpecs: [String: MacroSpec] = [ + "JSClass": MacroSpec(type: JSClassMacro.self, conformances: ["_JSBridgedClass"]), + "JSGetter": MacroSpec(type: JSGetterMacro.self), + ] + TestSupport.assertMacroExpansion( + """ + @JSClass + struct User { + @JSGetter + var stats: Stats + + @JSClass + struct Stats { + @JSGetter + var health: Int + } + } + """, + expandedSource: """ + struct User { + var stats: Stats { + get throws(JSException) { + return try _$User_stats_get(self.jsObject) + } + } + struct Stats { + var health: Int { + get throws(JSException) { + return try _$Stats_health_get(self.jsObject) + } + } + + let jsObject: JSObject + + init(unsafelyWrapping jsObject: JSObject) { + self.jsObject = jsObject + } + } + + let jsObject: JSObject + + init(unsafelyWrapping jsObject: JSObject) { + self.jsObject = jsObject + } + } + + extension User.Stats: _JSBridgedClass { + } + + extension User: _JSBridgedClass { + } + """, + macroSpecs: combinedSpecs, + indentationWidth: indentationWidth + ) + } + @Test func fileprivateStructIsRejected() { TestSupport.assertMacroExpansion( """ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift index 500a5db95..869bb2d3e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift @@ -165,6 +165,75 @@ import Testing #expect(description.contains(":2:")) } + // MARK: - Nested type validation + + @Test + func nestedStructInsideClassSucceeds() throws { + let source = """ + @JS class User { + @JS struct Stats { + var health: Int + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + #expect(skeleton.exported != nil) + let structs = skeleton.exported?.structs ?? [] + #expect(structs.count == 1) + #expect(structs.first?.swiftCallName == "User.Stats") + } + + @Test + func nestedClassInsideStructSucceeds() throws { + let source = """ + @JS struct Container { + var value: Int + @JS class Inner { + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + #expect(skeleton.exported != nil) + let classes = skeleton.exported?.classes ?? [] + #expect(classes.count == 1) + #expect(classes.first?.swiftCallName == "Container.Inner") + } + + @Test + func structInsideEnumNamespaceSucceeds() throws { + let source = """ + @JS enum API { + @JS struct Point { + var x: Double + var y: Double + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + #expect(skeleton.exported != nil) + } + @Test func omitsNextLineWhenErrorIsOnLastLine() throws { let source = """ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift new file mode 100644 index 000000000..bd2bcc4fe --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift @@ -0,0 +1,10 @@ +@JS class User { + @JS func getName() -> String { + return "test" + } + + @JS struct Stats { + var health: Int + var score: Double + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json new file mode 100644 index 000000000..e8666bbc4 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json @@ -0,0 +1,89 @@ +{ + "exported" : { + "classes" : [ + { + "methods" : [ + { + "abiName" : "bjs_User_getName", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getName", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "User", + "properties" : [ + + ], + "swiftCallName" : "User" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "methods" : [ + + ], + "name" : "Stats", + "namespace" : [ + "User" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "health", + "namespace" : [ + "User" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "score", + "namespace" : [ + "User" + ], + "type" : { + "double" : { + + } + } + } + ], + "swiftCallName" : "User.Stats" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ 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 new file mode 100644 index 000000000..35ead0856 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift @@ -0,0 +1,89 @@ +extension User.Stats: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> User.Stats { + let score = Double.bridgeJSStackPop() + let health = Int.bridgeJSStackPop() + return User.Stats(health: health, score: score) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.health.bridgeJSStackPush() + self.score.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_User_Stats(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_User_Stats())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_User_Stats") +fileprivate func _bjs_struct_lower_User_Stats_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_User_Stats_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_User_Stats(_ objectId: Int32) -> Void { + return _bjs_struct_lower_User_Stats_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_User_Stats") +fileprivate func _bjs_struct_lift_User_Stats_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_User_Stats_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_User_Stats() -> Int32 { + return _bjs_struct_lift_User_Stats_extern() +} + +@_expose(wasm, "bjs_User_getName") +@_cdecl("bjs_User_getName") +public func _bjs_User_getName(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = User.bridgeJSLiftParameter(_self).getName() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_User_deinit") +@_cdecl("bjs_User_deinit") +public func _bjs_User_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension User: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_User_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_User_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_User_wrap") +fileprivate func _bjs_User_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_User_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_User_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_User_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts new file mode 100644 index 000000000..2d3942e06 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts @@ -0,0 +1,33 @@ +// 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 interface Stats { + health: number; + score: number; +} +/// 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 User extends SwiftHeapObject { + getName(): string; +} +export type Exports = { + User: { + } +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => 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 new file mode 100644 index 000000000..cf24e7e2d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -0,0 +1,304 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const __bjs_createStatsHelpers = () => ({ + lower: (value) => { + i32Stack.push((value.health | 0)); + f64Stack.push(value.score); + }, + lift: () => { + const f64 = f64Stack.pop(); + const int = i32Stack.pop(); + return { health: int, score: f64 }; + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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(); + } + bjs["swift_js_struct_lower_User_Stats"] = function(objectId) { + structHelpers.Stats.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_User_Stats"] = function() { + const value = structHelpers.Stats.lift(); + return swift.memory.retain(value); + } + 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_User_wrap"] = function(pointer) { + const obj = _exports['User'].__construct(pointer); + return swift.memory.retain(obj); + }; + }, + 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) + } + }, + /** @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) { + 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 User extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_User_deinit, User.prototype, null); + } + + getName() { + instance.exports.bjs_User_getName(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + } + const StatsHelpers = __bjs_createStatsHelpers(); + structHelpers.Stats = StatsHelpers; + + const exports = { + User, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file From f90fe98ca77f356af4041da967831068262a1d7b Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 30 Apr 2026 12:28:05 +0200 Subject: [PATCH 44/68] BridgeJS: Diagnose struct initializer parameter order mismatch --- .../BridgeJSCore/SwiftToSkeleton.swift | 37 +++++++++- .../BridgeJSToolTests/DiagnosticsTests.swift | 71 +++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 209242e79..f39ac16f8 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -1843,11 +1843,46 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } override func visitPost(_ node: StructDeclSyntax) { - if case .structBody(_, _) = stateStack.current { + if case .structBody(_, let structKey) = stateStack.current { stateStack.pop() + validateStructInitOrder(node: node, structKey: structKey) } } + private func validateStructInitOrder(node: StructDeclSyntax, structKey: String) { + guard let exportedStruct = exportedStructByName[structKey], + let constructor = exportedStruct.constructor + else { + // No explicit @JS init — synthesized memberwise init is assumed, + // which always matches declaration order. + return + } + + let instanceProps = exportedStruct.properties.filter { !$0.isStatic } + let expectedLabels = instanceProps.map(\.name) + let actualLabels = constructor.parameters.compactMap(\.label) + + guard expectedLabels != actualLabels else { return } + + // Find the @JS init node so we can point the diagnostic at it. + let initNode: (any SyntaxProtocol) = + node.memberBlock.members + .compactMap { $0.decl.as(InitializerDeclSyntax.self) } + .first(where: { $0.attributes.hasJSAttribute() }) + ?? node + + let expectedOrder = expectedLabels.joined(separator: ", ") + let actualOrder = actualLabels.joined(separator: ", ") + + diagnose( + node: initNode, + message: + "@JS struct initializer parameters must match stored properties in declaration order. Expected (\(expectedOrder)), got (\(actualOrder))", + hint: + "Reorder the initializer parameters to match the property declaration order, or remove the @JS init to use the synthesized memberwise initializer" + ) + } + private func visitProtocolMethod( node: FunctionDeclSyntax, protocolName: String, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift index 869bb2d3e..e71a1f84e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift @@ -3,6 +3,7 @@ import SwiftSyntax import Testing @testable import BridgeJSCore +@testable import BridgeJSSkeleton @Suite struct DiagnosticsTests { /// Returns the first parameter's type node from a function in the source (the first `@JS func`-like decl), for pinpointing diagnostics. @@ -234,6 +235,76 @@ import Testing #expect(skeleton.exported != nil) } + // MARK: - Struct init order validation + + @Test + func structInitMismatchedOrderProducesDiagnostic() throws { + let source = """ + @JS struct Animal { + var size: Double + var age: Int + + @JS init(age: Int, size: Double) { + self.age = age + self.size = size + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + #expect(throws: BridgeJSCoreDiagnosticError.self) { + _ = try swiftAPI.finalize() + } + } + + @Test + func structInitMatchingOrderSucceeds() throws { + let source = """ + @JS struct Point { + var x: Double + var y: Double + + @JS init(x: Double, y: Double) { + self.x = x + self.y = y + } + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + #expect(skeleton.exported != nil) + } + + @Test + func structWithoutExplicitInitSucceeds() throws { + let source = """ + @JS struct Point { + var x: Double + var y: Double + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + #expect(skeleton.exported != nil) + } + @Test func omitsNextLineWhenErrorIsOnLastLine() throws { let source = """ From 549b727240775adcacf2dae0bedafaf5ee36b5e2 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Mon, 4 May 2026 15:39:11 +1000 Subject: [PATCH 45/68] BridgeJS: Fix closures with struct return --- .../Inputs/MacroSwift/SwiftClosure.swift | 11 + .../BridgeJSCodegenTests/SwiftClosure.json | 184 ++++++++++++++++ .../BridgeJSCodegenTests/SwiftClosure.swift | 205 ++++++++++++++++++ .../BridgeJSLinkTests/SwiftClosure.d.ts | 8 + .../BridgeJSLinkTests/SwiftClosure.js | 106 +++++++++ .../JavaScriptKit/BridgeJSIntrinsics.swift | 4 + .../BridgeJSRuntimeTests/ExportAPITests.swift | 12 + .../Generated/BridgeJS.swift | 148 +++++++++++++ .../Generated/JavaScript/BridgeJS.json | 93 ++++++++ .../JavaScript/ClosureSupportTests.mjs | 11 + 10 files changed, 782 insertions(+) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift index 791b1b7a9..6872d7989 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift @@ -8,10 +8,21 @@ import JavaScriptKit } } +@JS public struct Animal { + public let type: String + + @JS public init(type: String) { + self.type = type + } +} + @JS class TestProcessor { @JS init(transform: @escaping (String) -> String) {} } +@JS func roundtripAnimal(_ animalClosure: (Animal) -> Animal) -> (Animal) -> Animal +@JS func roundtripOptionalAnimal(_ animalClosure: (Animal?) -> Animal?) -> (Animal?) -> Animal? + @JS func roundtripString(_ stringClosure: (String) -> String) -> (String) -> String @JS func roundtripInt(_ intClosure: (Int) -> Int) -> (Int) -> Int @JS func roundtripBool(_ boolClosure: (Bool) -> Bool) -> (Bool) -> Bool diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json index abca80150..ac18f6dc2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json @@ -284,6 +284,152 @@ ], "exposeToGlobal" : false, "functions" : [ + { + "abiName" : "bjs_roundtripAnimal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripAnimal", + "parameters" : [ + { + "label" : "_", + "name" : "animalClosure", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule6AnimalV_6AnimalV", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftStruct" : { + "_0" : "Animal" + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Animal" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule6AnimalV_6AnimalV", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftStruct" : { + "_0" : "Animal" + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Animal" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + }, + { + "abiName" : "bjs_roundtripOptionalAnimal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripOptionalAnimal", + "parameters" : [ + { + "label" : "_", + "name" : "animalClosure", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModuleSq6AnimalV_Sq6AnimalV", + "moduleName" : "TestModule", + "parameters" : [ + { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Animal" + } + }, + "_1" : "null" + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Animal" + } + }, + "_1" : "null" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModuleSq6AnimalV_Sq6AnimalV", + "moduleName" : "TestModule", + "parameters" : [ + { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Animal" + } + }, + "_1" : "null" + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Animal" + } + }, + "_1" : "null" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + }, { "abiName" : "bjs_roundtripString", "effects" : { @@ -1872,7 +2018,45 @@ ], "structs" : [ + { + "constructor" : { + "abiName" : "bjs_Animal_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "type", + "name" : "type", + "type" : { + "string" : { + } + } + } + ] + }, + "explicitAccessControl" : "public", + "methods" : [ + + ], + "name" : "Animal", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "type", + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Animal" + } ] }, "moduleName" : "TestModule", diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index 348f9a788..4eb7c8da4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -127,6 +127,69 @@ public func _invoke_swift_closure_TestModule_10TestModule5ThemeO_5ThemeO(_ boxPt #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV") +fileprivate func invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV(_ callback: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV") +fileprivate func make_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule6AnimalV_6AnimalV { + static func bridgeJSLift(_ callbackId: Int32) -> (Animal) -> Animal { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let _ = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV(callbackValue) + return Animal.bridgeJSLiftReturn() + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Animal) -> Animal { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Animal) -> Animal) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV") +@_cdecl("invoke_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV") +public func _invoke_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Animal) -> Animal>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Animal.bridgeJSLiftParameter()) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule6PersonC_6PersonC") fileprivate func invoke_js_callback_TestModule_10TestModule6PersonC_6PersonC_extern(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer @@ -761,6 +824,69 @@ public func _invoke_swift_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(_ b #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV") +fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV") +fileprivate func make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleSq6AnimalV_Sq6AnimalV { + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> Optional { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0IsSome = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(callbackValue, param0IsSome) + return Optional.bridgeJSLiftReturn() + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Optional) -> Optional { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> Optional) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV") +public func _invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> Optional>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Optional.bridgeJSLiftParameter()) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSq6PersonC_Sq6PersonC") fileprivate func invoke_js_callback_TestModule_10TestModuleSq6PersonC_Sq6PersonC_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Pointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer @@ -1358,6 +1484,85 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } +extension Animal: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Animal { + let type = String.bridgeJSStackPop() + return Animal(type: type) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.type.bridgeJSStackPush() + } + + public init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Animal(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + public func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Animal())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Animal") +fileprivate func _bjs_struct_lower_Animal_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Animal_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Animal(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Animal_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Animal") +fileprivate func _bjs_struct_lift_Animal_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Animal_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Animal() -> Int32 { + return _bjs_struct_lift_Animal_extern() +} + +@_expose(wasm, "bjs_Animal_init") +@_cdecl("bjs_Animal_init") +public func _bjs_Animal_init(_ typeBytes: Int32, _ typeLength: Int32) -> Void { + #if arch(wasm32) + let ret = Animal(type: String.bridgeJSLiftParameter(typeBytes, typeLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundtripAnimal") +@_cdecl("bjs_roundtripAnimal") +public func _bjs_roundtripAnimal(_ animalClosure: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundtripAnimal(_: _BJS_Closure_10TestModule6AnimalV_6AnimalV.bridgeJSLift(animalClosure)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundtripOptionalAnimal") +@_cdecl("bjs_roundtripOptionalAnimal") +public func _bjs_roundtripOptionalAnimal(_ animalClosure: Int32) -> Int32 { + #if arch(wasm32) + let ret = roundtripOptionalAnimal(_: _BJS_Closure_10TestModuleSq6AnimalV_Sq6AnimalV.bridgeJSLift(animalClosure)) + return JSTypedClosure(ret).bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundtripString") @_cdecl("bjs_roundtripString") public func _bjs_roundtripString(_ stringClosure: Int32) -> Int32 { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts index ccc95eb3b..a0cbe6c4e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts @@ -41,6 +41,9 @@ export const APIResultValues: { export type APIResultTag = { tag: typeof APIResultValues.Tag.Success; param0: string } | { tag: typeof APIResultValues.Tag.Failure; param0: number } | { tag: typeof APIResultValues.Tag.Flag; param0: boolean } | { tag: typeof APIResultValues.Tag.Rate; param0: number } | { tag: typeof APIResultValues.Tag.Precise; param0: number } | { tag: typeof APIResultValues.Tag.Info } +export interface Animal { + type: string; +} export type DirectionObject = typeof DirectionValues; export type ThemeObject = typeof ThemeValues; @@ -67,6 +70,8 @@ export type Exports = { TestProcessor: { new(transform: (arg0: string) => string): TestProcessor; } + roundtripAnimal(animalClosure: (arg0: AnimalTag) => AnimalTag): (arg0: AnimalTag) => AnimalTag; + roundtripOptionalAnimal(animalClosure: (arg0: AnimalTag | null) => AnimalTag | null): (arg0: AnimalTag | null) => AnimalTag | null; roundtripString(stringClosure: (arg0: string) => string): (arg0: string) => string; roundtripInt(intClosure: (arg0: number) => number): (arg0: number) => number; roundtripBool(boolClosure: (arg0: boolean) => boolean): (arg0: boolean) => boolean; @@ -92,6 +97,9 @@ export type Exports = { Theme: ThemeObject HttpStatus: HttpStatusObject APIResult: APIResultObject + Animal: { + init(type: string): Animal; + } } export type Imports = { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 03a5504e4..0b4ca3dcc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -85,6 +85,18 @@ export async function createInstantiator(options, swift) { return swift.memory.retain(real); }; + const __bjs_createAnimalHelpers = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.type); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return { type: string }; + } + }); const __bjs_createAPIResultValuesHelpers = () => ({ lower: (value) => { const enumTag = value.tag; @@ -214,6 +226,13 @@ export async function createInstantiator(options, swift) { bjs["swift_js_pop_i64"] = function() { return i64Stack.pop(); } + bjs["swift_js_struct_lower_Animal"] = function(objectId) { + structHelpers.Animal.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Animal"] = function() { + const value = structHelpers.Animal.lift(); + return swift.memory.retain(value); + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -359,6 +378,31 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule5ThemeO_5ThemeO); } + bjs["invoke_js_callback_TestModule_10TestModule6AnimalV_6AnimalV"] = function(callbackId) { + try { + const callback = swift.memory.getObject(callbackId); + const structValue = structHelpers.Animal.lift(); + let ret = callback(structValue); + structHelpers.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); + instance.exports.invoke_swift_closure_TestModule_10TestModule6AnimalV_6AnimalV(boxPtr); + const structValue = structHelpers.Animal.lift(); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return structValue; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule6AnimalV_6AnimalV); + } bjs["invoke_js_callback_TestModule_10TestModule6PersonC_6PersonC"] = function(callbackId, param0) { try { const callback = swift.memory.getObject(callbackId); @@ -620,6 +664,46 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO); } + bjs["invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + let optResult; + if (param0) { + const struct = structHelpers.Animal.lift(); + optResult = struct; + } else { + optResult = null; + } + let ret = callback(optResult); + const isSome = ret != null; + if (isSome) { + structHelpers.Animal.lower(ret); + } + i32Stack.push(isSome ? 1 : 0); + } 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); + instance.exports.invoke_swift_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(boxPtr); + const isSome1 = i32Stack.pop(); + const optResult = isSome1 ? structHelpers.Animal.lift() : null; + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return optResult; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV); + } bjs["invoke_js_callback_TestModule_10TestModuleSq6PersonC_Sq6PersonC"] = function(callbackId, param0IsSome, param0Pointer) { try { const callback = swift.memory.getObject(callbackId); @@ -971,12 +1055,25 @@ export async function createInstantiator(options, swift) { return TestProcessor.__construct(ret); } } + const AnimalHelpers = __bjs_createAnimalHelpers(); + structHelpers.Animal = AnimalHelpers; + const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; const exports = { Person, TestProcessor, + roundtripAnimal: function bjs_roundtripAnimal(animalClosure) { + const callbackId = swift.memory.retain(animalClosure); + const ret = instance.exports.bjs_roundtripAnimal(callbackId); + return swift.memory.getObject(ret); + }, + roundtripOptionalAnimal: function bjs_roundtripOptionalAnimal(animalClosure) { + const callbackId = swift.memory.retain(animalClosure); + const ret = instance.exports.bjs_roundtripOptionalAnimal(callbackId); + return swift.memory.getObject(ret); + }, roundtripString: function bjs_roundtripString(stringClosure) { const callbackId = swift.memory.retain(stringClosure); const ret = instance.exports.bjs_roundtripString(callbackId); @@ -1086,6 +1183,15 @@ export async function createInstantiator(options, swift) { Theme: ThemeValues, HttpStatus: HttpStatusValues, APIResult: APIResultValues, + Animal: { + init: function(type) { + const typeBytes = textEncoder.encode(type); + const typeId = swift.memory.retain(typeBytes); + instance.exports.bjs_Animal_init(typeId, typeBytes.length); + const structValue = structHelpers.Animal.lift(); + return structValue; + }, + }, }; _exports = exports; return exports; diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 867d0e835..2a18401b4 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -847,6 +847,10 @@ extension _BridgedSwiftStruct { return Self(unsafelyCopying: jsObject) } + @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> Self { + bridgeJSStackPop() + } + @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { bridgeJSStackPop() } diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 2562fe18e..c81622f0d 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -1285,6 +1285,18 @@ enum GraphOperations { processor.increment(by: 7) return callback(processor) + " | " + callback(nil) } + + @JS func processVector(_ callback: (Double) -> Vector2D) -> Double { + return callback(3.0).magnitude() + } + + @JS func processOptionalVector(_ callback: (Double) -> Vector2D?) -> String { + let some = callback(2.0) + let none = callback(-1.0) + let someStr = some.map { "(\($0.dx),\($0.dy))" } ?? "nil" + let noneStr = none.map { "(\($0.dx),\($0.dy))" } ?? "nil" + return "\(someStr) | \(noneStr)" + } } class ExportAPITests: XCTestCase { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 4d920873d..771838716 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -776,6 +776,69 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_ #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV_extern(_ callback: Int32, _ param0: Float64) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV_extern(_ callback: Int32, _ param0: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV(_ callback: Int32, _ param0: Float64) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsSd_8Vector2DV { + static func bridgeJSLift(_ callbackId: Int32) -> (Double) -> Vector2D { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV(callbackValue, param0Value) + return Vector2D.bridgeJSLiftReturn() + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Double) -> Vector2D { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Double) -> Vector2D) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_8Vector2DV(_ boxPtr: UnsafeMutableRawPointer, _ param0: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Double) -> Vector2D>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Double.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sd") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sd_extern(_ callback: Int32, _ param0: Float64) -> Float64 @@ -839,6 +902,69 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_ #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV_extern(_ callback: Int32, _ param0: Float64) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV_extern(_ callback: Int32, _ param0: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV(_ callback: Int32, _ param0: Float64) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsSd_Sq8Vector2DV { + static func bridgeJSLift(_ callbackId: Int32) -> (Double) -> Optional { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV(callbackValue, param0Value) + return Optional.bridgeJSLiftReturn() + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Double) -> Optional { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Double) -> Optional) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSd_Sq8Vector2DV(_ boxPtr: UnsafeMutableRawPointer, _ param0: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Double) -> Optional>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Double.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSiSSSd_SS_extern(_ callback: Int32, _ param0: Int32, _ param1Bytes: Int32, _ param1Length: Int32, _ param2: Float64) -> Int32 @@ -10442,6 +10568,28 @@ public func _bjs_TextProcessor_processOptionalDataProcessor(_ _self: UnsafeMutab #endif } +@_expose(wasm, "bjs_TextProcessor_processVector") +@_cdecl("bjs_TextProcessor_processVector") +public func _bjs_TextProcessor_processVector(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Float64 { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processVector(_: _BJS_Closure_20BridgeJSRuntimeTestsSd_8Vector2DV.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalVector") +@_cdecl("bjs_TextProcessor_processOptionalVector") +public func _bjs_TextProcessor_processOptionalVector(_ _self: UnsafeMutableRawPointer, _ callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalVector(_: _BJS_Closure_20BridgeJSRuntimeTestsSd_Sq8Vector2DV.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_TextProcessor_deinit") @_cdecl("bjs_TextProcessor_deinit") public func _bjs_TextProcessor_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index d9108f2e7..7a3e7f7fe 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -4057,6 +4057,99 @@ "returnType" : { "string" : { + } + } + }, + { + "abiName" : "bjs_TextProcessor_processVector", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processVector", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsSd_8Vector2DV", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "double" : { + + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Vector2D" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "double" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_processOptionalVector", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalVector", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsSd_Sq8Vector2DV", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "double" : { + + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Vector2D" + } + }, + "_1" : "null" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + } } } diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs index ebe00548b..bab496d09 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs @@ -355,6 +355,17 @@ export function runJsClosureSupportTests(exports) { }); assert.equal(optDpResult, "DP: 7 | DP: null"); + const vectorMagnitude = processor.processVector((value) => ({ + dx: value, + dy: 4.0, + })); + assert.equal(vectorMagnitude, 5.0); + + const optVectorResult = processor.processOptionalVector((value) => + value > 0 ? { dx: value, dy: value * 2 } : null, + ); + assert.equal(optVectorResult, "(2.0,4.0) | nil"); + processor.release(); const intToInt = exports.ClosureSupportExports.makeIntToInt(10); From f8b2c96fdb82dcb4d8074297668ca098b3620819 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 4 May 2026 15:11:42 +0200 Subject: [PATCH 46/68] BridgeJS: Fix optionals build error with Embedded Swift (#734) Remove @_spi(BridgeJS) from _BridgedAsOptional protocol and its Optional/JSUndefinedOr conformances so the conformances are visible in Embedded Swift mode. The underscore-prefixed protocol name already signals internal API, and all extension methods remain @_spi-gated. Fixes #689 --- Sources/JavaScriptKit/BridgeJSIntrinsics.swift | 4 ++-- Sources/JavaScriptKit/JSUndefinedOr.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 867d0e835..07e021be9 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -182,13 +182,13 @@ extension _BridgedSwiftStackType { /// Types that bridge with the same (isSome, value) ABI as Optional. /// Used by JSUndefinedOr so all bridge methods delegate to Optional. -@_spi(BridgeJS) public protocol _BridgedAsOptional { +public protocol _BridgedAsOptional { associatedtype Wrapped var asOptional: Wrapped? { get } init(optional: Wrapped?) } -@_spi(BridgeJS) extension Optional: _BridgedAsOptional { +extension Optional: _BridgedAsOptional { public var asOptional: Wrapped? { self } public init(optional: Wrapped?) { self = optional } } diff --git a/Sources/JavaScriptKit/JSUndefinedOr.swift b/Sources/JavaScriptKit/JSUndefinedOr.swift index c4d601738..de7be09b4 100644 --- a/Sources/JavaScriptKit/JSUndefinedOr.swift +++ b/Sources/JavaScriptKit/JSUndefinedOr.swift @@ -53,4 +53,4 @@ extension JSUndefinedOr: ConvertibleToJSValue where Wrapped: ConvertibleToJSValu // MARK: - BridgeJS (via _BridgedAsOptional in BridgeJSIntrinsics) -@_spi(BridgeJS) extension JSUndefinedOr: _BridgedAsOptional {} +extension JSUndefinedOr: _BridgedAsOptional {} From 43ed78f06d3ee4505f52f034595041c4bb446f87 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 4 May 2026 15:23:41 +0200 Subject: [PATCH 47/68] BridgeJS: Move optional JSObject to stack ABI, enabling Optional<@JSClass> (#738) --- .../Sources/BridgeJSCore/ImportTS.swift | 8 ++- .../Sources/BridgeJSLink/JSGlueGen.swift | 4 +- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 4 +- .../Inputs/MacroSwift/Optionals.swift | 6 ++ .../BridgeJSCodegenTests/Optionals.json | 63 ++++++++++++++++++ .../BridgeJSCodegenTests/Optionals.swift | 64 +++++++++++++++++++ .../BridgeJSLinkTests/Optionals.d.ts | 2 + .../BridgeJSLinkTests/Optionals.js | 51 +++++++++++++++ .../JavaScriptKit/BridgeJSIntrinsics.swift | 6 +- 9 files changed, 198 insertions(+), 10 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 536c7eeab..d491c4058 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -128,7 +128,9 @@ public struct ImportTS { self.returnType = returnType self.context = context let liftingInfo = try returnType.liftingReturnInfo(context: context) - if effects.isAsync || returnType == .void || returnType.usesSideChannelForOptionalReturn() { + if effects.isAsync || returnType == .void || returnType.usesSideChannelForOptionalReturn() + || liftingInfo.valueToLift == nil + { abiReturnType = nil } else { abiReturnType = liftingInfo.valueToLift @@ -1032,6 +1034,10 @@ extension BridgeType { case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as return values") case .nullable(let wrappedType, _): + // jsObject uses stack ABI for optionals — returns void, value goes through stacks + if case .jsObject = wrappedType { + return LiftingReturnInfo(valueToLift: nil) + } let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) case .array, .dictionary: diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 599b6df39..1ad397f71 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -2648,7 +2648,7 @@ private extension BridgeType { case .string: return .sideChannelReturn(.storage) case .jsObject: - return .sideChannelReturn(.retainedObject) + return .stackABI case .jsValue: return .inlineFlag case .swiftHeapObject: @@ -2685,7 +2685,7 @@ private extension BridgeType { var nilSentinel: NilSentinel { switch self { - case .jsObject, .swiftProtocol: + case .swiftProtocol: return .i32(0) case .swiftHeapObject: return .pointer diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 055ef2552..346b7333b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -1655,7 +1655,7 @@ extension BridgeType { } switch wrappedType { - case .string, .integer, .float, .double, .jsObject, .swiftProtocol: + case .string, .integer, .float, .double, .swiftProtocol: return true case .rawValueEnum(_, let rawType): switch rawType { @@ -1666,7 +1666,7 @@ extension BridgeType { default: return false } - case .bool, .caseEnum, .swiftHeapObject, .associatedValueEnum: + case .bool, .caseEnum, .swiftHeapObject, .associatedValueEnum, .jsObject: return false default: return false diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift index 927fac6a0..5df48d9c0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift @@ -155,4 +155,10 @@ func testMixedOptionals(firstName: String?, lastName: String?, age: Int?, active @JSSetter func setIntOrUndefined(_ value: JSUndefinedOr) throws(JSException) @JSFunction func roundTripIntOrNull(value: Int?) throws(JSException) -> Int? @JSFunction func roundTripIntOrUndefined(value: JSUndefinedOr) throws(JSException) -> JSUndefinedOr + + @JSGetter var childOrNull: WithOptionalJSClass? + @JSSetter func setChildOrNull(_ value: WithOptionalJSClass?) throws(JSException) + @JSFunction func roundTripChildOrNull( + value: WithOptionalJSClass? + ) throws(JSException) -> WithOptionalJSClass? } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json index 921983115..91291c24e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json @@ -1158,6 +1158,20 @@ "_1" : "undefined" } } + }, + { + "accessLevel" : "internal", + "name" : "childOrNull", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "WithOptionalJSClass" + } + }, + "_1" : "null" + } + } } ], "methods" : [ @@ -1444,6 +1458,40 @@ "_1" : "undefined" } } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "roundTripChildOrNull", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "WithOptionalJSClass" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "WithOptionalJSClass" + } + }, + "_1" : "null" + } + } } ], "name" : "WithOptionalJSClass", @@ -1573,6 +1621,21 @@ "_1" : "undefined" } } + }, + { + "accessLevel" : "internal", + "functionName" : "childOrNull_set", + "name" : "childOrNull", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "WithOptionalJSClass" + } + }, + "_1" : "null" + } + } } ], "staticMethods" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift index 0c6a79bf5..0a2528340 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift @@ -526,6 +526,18 @@ fileprivate func bjs_WithOptionalJSClass_intOrUndefined_get_extern(_ self: Int32 return bjs_WithOptionalJSClass_intOrUndefined_get_extern(self) } +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_childOrNull_get") +fileprivate func bjs_WithOptionalJSClass_childOrNull_get_extern(_ self: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_childOrNull_get_extern(_ self: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WithOptionalJSClass_childOrNull_get(_ self: Int32) -> Void { + return bjs_WithOptionalJSClass_childOrNull_get_extern(self) +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_stringOrNull_set") fileprivate func bjs_WithOptionalJSClass_stringOrNull_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueBytes: Int32, _ newValueLength: Int32) -> Void @@ -622,6 +634,18 @@ fileprivate func bjs_WithOptionalJSClass_intOrUndefined_set_extern(_ self: Int32 return bjs_WithOptionalJSClass_intOrUndefined_set_extern(self, newValueIsSome, newValueValue) } +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_childOrNull_set") +fileprivate func bjs_WithOptionalJSClass_childOrNull_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_childOrNull_set_extern(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WithOptionalJSClass_childOrNull_set(_ self: Int32, _ newValueIsSome: Int32, _ newValueValue: Int32) -> Void { + return bjs_WithOptionalJSClass_childOrNull_set_extern(self, newValueIsSome, newValueValue) +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripStringOrNull") fileprivate func bjs_WithOptionalJSClass_roundTripStringOrNull_extern(_ self: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void @@ -718,6 +742,18 @@ fileprivate func bjs_WithOptionalJSClass_roundTripIntOrUndefined_extern(_ self: return bjs_WithOptionalJSClass_roundTripIntOrUndefined_extern(self, valueIsSome, valueValue) } +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_WithOptionalJSClass_roundTripChildOrNull") +fileprivate func bjs_WithOptionalJSClass_roundTripChildOrNull_extern(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func bjs_WithOptionalJSClass_roundTripChildOrNull_extern(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_WithOptionalJSClass_roundTripChildOrNull(_ self: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + return bjs_WithOptionalJSClass_roundTripChildOrNull_extern(self, valueIsSome, valueValue) +} + func _$WithOptionalJSClass_init(_ valueOrNull: Optional, _ valueOrUndefined: JSUndefinedOr) throws(JSException) -> JSObject { let ret0 = valueOrNull.bridgeJSWithLoweredParameter { (valueOrNullIsSome, valueOrNullBytes, valueOrNullLength) in let ret1 = valueOrUndefined.bridgeJSWithLoweredParameter { (valueOrUndefinedIsSome, valueOrUndefinedBytes, valueOrUndefinedLength) in @@ -805,6 +841,15 @@ func _$WithOptionalJSClass_intOrUndefined_get(_ self: JSObject) throws(JSExcepti return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() } +func _$WithOptionalJSClass_childOrNull_get(_ self: JSObject) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_childOrNull_get(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn() +} + func _$WithOptionalJSClass_stringOrNull_set(_ self: JSObject, _ newValue: Optional) throws(JSException) -> Void { let selfValue = self.bridgeJSLowerParameter() newValue.bridgeJSWithLoweredParameter { (newValueIsSome, newValueBytes, newValueLength) in @@ -879,6 +924,15 @@ func _$WithOptionalJSClass_intOrUndefined_set(_ self: JSObject, _ newValue: JSUn } } +func _$WithOptionalJSClass_childOrNull_set(_ self: JSObject, _ newValue: Optional) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let (newValueIsSome, newValueValue) = newValue.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_childOrNull_set(selfValue, newValueIsSome, newValueValue) + if let error = _swift_js_take_exception() { + throw error + } +} + func _$WithOptionalJSClass_roundTripStringOrNull(_ self: JSObject, _ value: Optional) throws(JSException) -> Optional { let selfValue = self.bridgeJSLowerParameter() value.bridgeJSWithLoweredParameter { (valueIsSome, valueBytes, valueLength) in @@ -959,4 +1013,14 @@ func _$WithOptionalJSClass_roundTripIntOrUndefined(_ self: JSObject, _ value: JS throw error } return JSUndefinedOr.bridgeJSLiftReturnFromSideChannel() +} + +func _$WithOptionalJSClass_roundTripChildOrNull(_ self: JSObject, _ value: Optional) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_WithOptionalJSClass_roundTripChildOrNull(selfValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts index a5a6e16fb..fb9d68db7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts @@ -30,6 +30,7 @@ export interface WithOptionalJSClass { roundTripBoolOrUndefined(value: boolean | undefined): boolean | undefined; roundTripIntOrNull(value: number | null): number | null; roundTripIntOrUndefined(value: number | undefined): number | undefined; + roundTripChildOrNull(value: WithOptionalJSClass | null): WithOptionalJSClass | null; stringOrNull: string | null; stringOrUndefined: string | undefined; doubleOrNull: number | null; @@ -38,6 +39,7 @@ export interface WithOptionalJSClass { boolOrUndefined: boolean | undefined; intOrNull: number | null; intOrUndefined: number | undefined; + childOrNull: WithOptionalJSClass | null; } export type Exports = { Greeter: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 5971c2fa8..1d585ce0b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -296,6 +296,19 @@ export async function createInstantiator(options, swift) { setException(error); } } + 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); + } catch (error) { + setException(error); + } + } TestModule["bjs_WithOptionalJSClass_stringOrNull_set"] = function bjs_WithOptionalJSClass_stringOrNull_set(self, newValueIsSome, newValueBytes, newValueCount) { try { let optResult; @@ -366,6 +379,22 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_WithOptionalJSClass_childOrNull_set"] = function bjs_WithOptionalJSClass_childOrNull_set(self, newValue) { + try { + let optResult; + if (newValue) { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + optResult = obj; + } else { + optResult = null; + } + swift.memory.getObject(self).childOrNull = optResult; + } catch (error) { + setException(error); + } + } TestModule["bjs_WithOptionalJSClass_roundTripStringOrNull"] = function bjs_WithOptionalJSClass_roundTripStringOrNull(self, valueIsSome, valueBytes, valueCount) { try { let optResult; @@ -452,6 +481,28 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_WithOptionalJSClass_roundTripChildOrNull"] = function bjs_WithOptionalJSClass_roundTripChildOrNull(self, value) { + try { + let optResult; + if (value) { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + optResult = obj; + } else { + optResult = null; + } + let ret = swift.memory.getObject(self).roundTripChildOrNull(optResult); + const isSome = ret != null; + if (isSome) { + const objId1 = swift.memory.retain(ret); + i32Stack.push(objId1); + } + i32Stack.push(isSome ? 1 : 0); + } catch (error) { + setException(error); + } + } }, setInstance: (i) => { instance = i; diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 07e021be9..ebad67a4d 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -1693,11 +1693,7 @@ extension _BridgedAsOptional where Wrapped == JSObject { } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - asOptional._bridgeJSLowerReturn( - noneValue: 0, - lowerWrapped: { $0.bridgeJSLowerReturn() }, - write: _swift_js_return_optional_object - ) + Wrapped.bridgeJSStackPushAsOptional(asOptional) } } From 4326481aacc61943b10fe5efaa2227b625ffa683 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Tue, 5 May 2026 10:13:50 +1000 Subject: [PATCH 48/68] BridgeJS: Fix TypeScript type definition generation for struct arguments --- Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift | 4 +--- .../__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 64a0d2394..ceaaae8f1 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1441,8 +1441,6 @@ public struct BridgeJSLink { } } return type.tsType - case .swiftStruct(let name): - return name.components(separatedBy: ".").last ?? name case .nullable(let wrapped, let kind): let base = resolveTypeScriptType(wrapped, exportedSkeletons: exportedSkeletons) return "\(base) | \(kind.absenceLiteral)" @@ -3612,7 +3610,7 @@ extension BridgeType { case .associatedValueEnum(let name): return "\(name)Tag" case .swiftStruct(let name): - return "\(name)Tag" + return name.components(separatedBy: ".").last ?? name case .namespaceEnum(let name): return name case .swiftProtocol(let name): diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts index a0cbe6c4e..d024be7dd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts @@ -70,8 +70,8 @@ export type Exports = { TestProcessor: { new(transform: (arg0: string) => string): TestProcessor; } - roundtripAnimal(animalClosure: (arg0: AnimalTag) => AnimalTag): (arg0: AnimalTag) => AnimalTag; - roundtripOptionalAnimal(animalClosure: (arg0: AnimalTag | null) => AnimalTag | null): (arg0: AnimalTag | null) => AnimalTag | null; + roundtripAnimal(animalClosure: (arg0: Animal) => Animal): (arg0: Animal) => Animal; + roundtripOptionalAnimal(animalClosure: (arg0: Animal | null) => Animal | null): (arg0: Animal | null) => Animal | null; roundtripString(stringClosure: (arg0: string) => string): (arg0: string) => string; roundtripInt(intClosure: (arg0: number) => number): (arg0: number) => number; roundtripBool(boolClosure: (arg0: boolean) => boolean): (arg0: boolean) => boolean; From d3f96f43bfd91b027d18086aa645673cb4804d85 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 6 May 2026 18:29:34 +0000 Subject: [PATCH 49/68] Fix cross-thread JSString deinit by wrapping JSObject instead of raw ref JSString.Guts previously held a raw JavaScriptObjectRef and released it unconditionally on whatever thread ran deinit. In the multithreaded Wasm runtime each thread has its own JSObjectSpace, so releasing a ref on the wrong thread caused a TypeError crash (BugSnag: rc property of undefined). JSObject already handles this correctly by capturing ownerTid at init time and routing deinit through swjs_release_remote when destroyed off-thread. This change makes Guts hold a JSObject instead of a raw ref, delegating the correct cross-thread release behaviour to the existing JSObject.deinit path. Adds a regression test testDeinitJSStringOnDifferentThread that reproduces the crash deterministically: it forces JS ref allocation on the main thread via asInternalJSRef(), then drops the last reference on a worker thread. Fixes the crash seen in v292745-rc4 after upgrading to JavaScriptKit 0.50.2. https://claude.ai/code/session_01Qhg5GLXZYNJtH63Gs1SwJH --- .../FundamentalObjects/JSString.swift | 27 ++++++++----------- .../WebWorkerTaskExecutorTests.swift | 25 +++++++++++++++++ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSString.swift b/Sources/JavaScriptKit/FundamentalObjects/JSString.swift index 4e6a0a085..0eabfa78d 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSString.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSString.swift @@ -16,25 +16,26 @@ import _CJavaScriptKit /// public struct JSString: LosslessStringConvertible, Equatable { /// The internal representation of JS compatible string - /// The initializers of this type must initialize `jsRef` or `buffer`. + /// The initializers of this type must initialize `jsObject` or `buffer`. /// And the uninitialized one will be lazily initialized class Guts { - var shouldDeallocateRef: Bool = false - lazy var jsRef: JavaScriptObjectRef = { - self.shouldDeallocateRef = true - return buffer.withUTF8 { bufferPtr in + // Owns the JS-side ref via JSObject, whose deinit routes the release to + // the correct thread via swjs_release_remote when destroyed off-owner-thread. + lazy var jsObject: JSObject = { + let ref = buffer.withUTF8 { bufferPtr in return swjs_decode_string(bufferPtr.baseAddress!, Int32(bufferPtr.count)) } + return JSObject(id: ref) // captures ownerTid = current thread here }() lazy var buffer: String = { var bytesRef: JavaScriptObjectRef = 0 - let bytesLength = Int(swjs_encode_string(jsRef, &bytesRef)) + let bytesLength = Int(swjs_encode_string(jsObject.id, &bytesRef)) // +1 for null terminator let buffer = UnsafeMutablePointer.allocate(capacity: bytesLength + 1) defer { buffer.deallocate() - swjs_release(bytesRef) + swjs_release(bytesRef) // bytesRef is a same-thread temporary } swjs_load_string(bytesRef, buffer) buffer[bytesLength] = 0 @@ -46,13 +47,7 @@ public struct JSString: LosslessStringConvertible, Equatable { } init(from jsRef: JavaScriptObjectRef) { - self.jsRef = jsRef - self.shouldDeallocateRef = true - } - - deinit { - guard shouldDeallocateRef else { return } - swjs_release(jsRef) + self.jsObject = JSObject(id: jsRef) } } @@ -79,7 +74,7 @@ public struct JSString: LosslessStringConvertible, Equatable { public static func == (lhs: JSString, rhs: JSString) -> Bool { withExtendedLifetime(lhs.guts) { lhsGuts in withExtendedLifetime(rhs.guts) { rhsGuts in - return swjs_value_equals(lhsGuts.jsRef, rhsGuts.jsRef) + return swjs_value_equals(lhsGuts.jsObject.id, rhsGuts.jsObject.id) } } } @@ -95,6 +90,6 @@ extension JSString: ExpressibleByStringLiteral { extension JSString { func asInternalJSRef() -> JavaScriptObjectRef { - guts.jsRef + guts.jsObject.id } } diff --git a/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift b/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift index 54559f3d8..69b3390dc 100644 --- a/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift +++ b/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift @@ -789,5 +789,30 @@ final class WebWorkerTaskExecutorTests: XCTestCase { // await task.value // executor.terminate() // } + + func testDeinitJSStringOnDifferentThread() async throws { + final class Box: @unchecked Sendable { + var string: JSString? + init(_ string: JSString) { self.string = string } + } + + let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1) + defer { executor.terminate() } + + // Force JS ref allocation on the main thread so ownerTid = main thread. + var string: JSString? = JSString("main-thread-owned-key") + _ = string!.asInternalJSRef() + + let box = Box(string!) + string = nil + + // Drop the last reference on a worker — deinit fires on the worker. + // Before the fix this crashed: TypeError: Cannot read properties of undefined (reading 'rc') + let task = Task(executorPreference: executor) { + XCTAssertFalse(isMainThread()) + box.string = nil + } + await task.value + } } #endif From f1f290b40ffff79672fc49fdeef8e770d1976dc9 Mon Sep 17 00:00:00 2001 From: Simon Leeb <52261246+sliemeobn@users.noreply.github.com> Date: Wed, 13 May 2026 09:21:23 +0200 Subject: [PATCH 50/68] faster JSObjectSpace (JS runtime retain / release) (#676) --- Plugins/PackageToJS/Templates/runtime.d.ts | 14 +- Plugins/PackageToJS/Templates/runtime.mjs | 109 ++++++++++----- Runtime/src/object-heap.ts | 125 +++++++++++++----- Tests/JavaScriptKitTests/JSClosureTests.swift | 46 +++---- 4 files changed, 192 insertions(+), 102 deletions(-) diff --git a/Plugins/PackageToJS/Templates/runtime.d.ts b/Plugins/PackageToJS/Templates/runtime.d.ts index 87cbeea72..e4795bedf 100644 --- a/Plugins/PackageToJS/Templates/runtime.d.ts +++ b/Plugins/PackageToJS/Templates/runtime.d.ts @@ -2,14 +2,16 @@ type ref = number; type pointer = number; declare class JSObjectSpace { - private _heapValueById; - private _heapEntryByValue; - private _heapNextKey; + private _slotByValue; + private _values; + private _stateBySlot; + private _freeSlotStack; constructor(); retain(value: any): number; - retainByRef(ref: ref): number; - release(ref: ref): void; - getObject(ref: ref): any; + retainByRef(reference: ref): number; + release(reference: ref): void; + getObject(reference: ref): any; + private _getValidatedSlotState; } /** diff --git a/Plugins/PackageToJS/Templates/runtime.mjs b/Plugins/PackageToJS/Templates/runtime.mjs index ab85e7893..daf4f3ab0 100644 --- a/Plugins/PackageToJS/Templates/runtime.mjs +++ b/Plugins/PackageToJS/Templates/runtime.mjs @@ -241,44 +241,91 @@ function deserializeError(error) { const globalVariable = globalThis; +const SLOT_BITS = 24; +const SLOT_MASK = (1 << SLOT_BITS) - 1; +const GEN_MASK = (1 << (32 - SLOT_BITS)) - 1; class JSObjectSpace { constructor() { - this._heapValueById = new Map(); - this._heapValueById.set(1, globalVariable); - this._heapEntryByValue = new Map(); - this._heapEntryByValue.set(globalVariable, { id: 1, rc: 1 }); + this._slotByValue = new Map(); + this._values = []; + this._stateBySlot = []; + this._freeSlotStack = []; // Note: 0 is preserved for invalid references, 1 is preserved for globalThis - this._heapNextKey = 2; + this._values[0] = undefined; + this._values[1] = globalVariable; + this._slotByValue.set(globalVariable, 1); + this._stateBySlot[1] = 1; // gen=0, rc=1 } retain(value) { - const entry = this._heapEntryByValue.get(value); - if (entry) { - entry.rc++; - return entry.id; - } - const id = this._heapNextKey++; - this._heapValueById.set(id, value); - this._heapEntryByValue.set(value, { id: id, rc: 1 }); - return id; - } - retainByRef(ref) { - return this.retain(this.getObject(ref)); - } - release(ref) { - const value = this._heapValueById.get(ref); - const entry = this._heapEntryByValue.get(value); - entry.rc--; - if (entry.rc != 0) + const slot = this._slotByValue.get(value); + if (slot !== undefined) { + const state = this._stateBySlot[slot]; + const nextState = (state + 1) >>> 0; + if ((nextState & SLOT_MASK) === 0) { + throw new RangeError(`Reference count overflow at slot ${slot}`); + } + this._stateBySlot[slot] = nextState; + return ((nextState & ~SLOT_MASK) | slot) >>> 0; + } + let newSlot; + let state; + if (this._freeSlotStack.length > 0) { + newSlot = this._freeSlotStack.pop(); + const gen = this._stateBySlot[newSlot] >>> SLOT_BITS; + state = ((gen << SLOT_BITS) | 1) >>> 0; + } + else { + newSlot = this._values.length; + if (newSlot > SLOT_MASK) { + throw new RangeError(`Reference slot overflow: ${newSlot} exceeds ${SLOT_MASK}`); + } + state = 1; + } + this._stateBySlot[newSlot] = state; + this._values[newSlot] = value; + this._slotByValue.set(value, newSlot); + return ((state & ~SLOT_MASK) | newSlot) >>> 0; + } + retainByRef(reference) { + const state = this._getValidatedSlotState(reference); + const slot = reference & SLOT_MASK; + const nextState = (state + 1) >>> 0; + if ((nextState & SLOT_MASK) === 0) { + throw new RangeError(`Reference count overflow at slot ${slot}`); + } + this._stateBySlot[slot] = nextState; + return reference; + } + release(reference) { + const state = this._getValidatedSlotState(reference); + const slot = reference & SLOT_MASK; + if ((state & SLOT_MASK) > 1) { + this._stateBySlot[slot] = (state - 1) >>> 0; return; - this._heapEntryByValue.delete(value); - this._heapValueById.delete(ref); - } - getObject(ref) { - const value = this._heapValueById.get(ref); - if (value === undefined) { - throw new ReferenceError("Attempted to read invalid reference " + ref); } - return value; + this._slotByValue.delete(this._values[slot]); + this._values[slot] = undefined; + const nextGen = ((state >>> SLOT_BITS) + 1) & GEN_MASK; + this._stateBySlot[slot] = (nextGen << SLOT_BITS) >>> 0; + this._freeSlotStack.push(slot); + } + getObject(reference) { + this._getValidatedSlotState(reference); + return this._values[reference & SLOT_MASK]; + } + // Returns the packed state for the slot, after validating the reference. + _getValidatedSlotState(reference) { + const slot = reference & SLOT_MASK; + if (slot === 0) + throw new ReferenceError(`Attempted to use invalid reference ${reference}`); + const state = this._stateBySlot[slot]; + if (state === undefined || (state & SLOT_MASK) === 0) { + throw new ReferenceError(`Attempted to use invalid reference ${reference}`); + } + if (state >>> SLOT_BITS !== reference >>> SLOT_BITS) { + throw new ReferenceError(`Attempted to use stale reference ${reference}`); + } + return state; } } diff --git a/Runtime/src/object-heap.ts b/Runtime/src/object-heap.ts index ba9cf8021..6138953e9 100644 --- a/Runtime/src/object-heap.ts +++ b/Runtime/src/object-heap.ts @@ -1,59 +1,114 @@ import { globalVariable } from "./find-global.js"; import { ref } from "./types.js"; -type SwiftRuntimeHeapEntry = { - id: number; - rc: number; -}; +const SLOT_BITS = 24; +const SLOT_MASK = (1 << SLOT_BITS) - 1; +const GEN_MASK = (1 << (32 - SLOT_BITS)) - 1; + export class JSObjectSpace { - private _heapValueById: Map; - private _heapEntryByValue: Map; - private _heapNextKey: number; + private _slotByValue: Map; + private _values: (any | undefined)[]; + private _stateBySlot: number[]; + private _freeSlotStack: number[]; constructor() { - this._heapValueById = new Map(); - this._heapValueById.set(1, globalVariable); - - this._heapEntryByValue = new Map(); - this._heapEntryByValue.set(globalVariable, { id: 1, rc: 1 }); + this._slotByValue = new Map(); + this._values = []; + this._stateBySlot = []; + this._freeSlotStack = []; // Note: 0 is preserved for invalid references, 1 is preserved for globalThis - this._heapNextKey = 2; + this._values[0] = undefined; + this._values[1] = globalVariable; + this._slotByValue.set(globalVariable, 1); + this._stateBySlot[1] = 1; // gen=0, rc=1 } retain(value: any) { - const entry = this._heapEntryByValue.get(value); - if (entry) { - entry.rc++; - return entry.id; + const slot = this._slotByValue.get(value); + if (slot !== undefined) { + const state = this._stateBySlot[slot]!; + const nextState = (state + 1) >>> 0; + if ((nextState & SLOT_MASK) === 0) { + throw new RangeError( + `Reference count overflow at slot ${slot}`, + ); + } + this._stateBySlot[slot] = nextState; + return ((nextState & ~SLOT_MASK) | slot) >>> 0; + } + + let newSlot: number; + let state: number; + if (this._freeSlotStack.length > 0) { + newSlot = this._freeSlotStack.pop()!; + const gen = this._stateBySlot[newSlot]! >>> SLOT_BITS; + state = ((gen << SLOT_BITS) | 1) >>> 0; + } else { + newSlot = this._values.length; + if (newSlot > SLOT_MASK) { + throw new RangeError( + `Reference slot overflow: ${newSlot} exceeds ${SLOT_MASK}`, + ); + } + state = 1; } - const id = this._heapNextKey++; - this._heapValueById.set(id, value); - this._heapEntryByValue.set(value, { id: id, rc: 1 }); - return id; + + this._stateBySlot[newSlot] = state; + this._values[newSlot] = value; + this._slotByValue.set(value, newSlot); + return ((state & ~SLOT_MASK) | newSlot) >>> 0; } - retainByRef(ref: ref) { - return this.retain(this.getObject(ref)); + retainByRef(reference: ref) { + const state = this._getValidatedSlotState(reference); + const slot = reference & SLOT_MASK; + const nextState = (state + 1) >>> 0; + if ((nextState & SLOT_MASK) === 0) { + throw new RangeError(`Reference count overflow at slot ${slot}`); + } + this._stateBySlot[slot] = nextState; + return reference; } - release(ref: ref) { - const value = this._heapValueById.get(ref); - const entry = this._heapEntryByValue.get(value)!; - entry.rc--; - if (entry.rc != 0) return; + release(reference: ref) { + const state = this._getValidatedSlotState(reference); + const slot = reference & SLOT_MASK; + if ((state & SLOT_MASK) > 1) { + this._stateBySlot[slot] = (state - 1) >>> 0; + return; + } + + this._slotByValue.delete(this._values[slot]); + this._values[slot] = undefined; + const nextGen = ((state >>> SLOT_BITS) + 1) & GEN_MASK; + this._stateBySlot[slot] = (nextGen << SLOT_BITS) >>> 0; + this._freeSlotStack.push(slot); + } - this._heapEntryByValue.delete(value); - this._heapValueById.delete(ref); + getObject(reference: ref) { + this._getValidatedSlotState(reference); + return this._values[reference & SLOT_MASK]; } - getObject(ref: ref) { - const value = this._heapValueById.get(ref); - if (value === undefined) { + // Returns the packed state for the slot, after validating the reference. + private _getValidatedSlotState(reference: ref): number { + const slot = reference & SLOT_MASK; + if (slot === 0) + throw new ReferenceError( + `Attempted to use invalid reference ${reference}`, + ); + const state = this._stateBySlot[slot]; + if (state === undefined || (state & SLOT_MASK) === 0) { + throw new ReferenceError( + `Attempted to use invalid reference ${reference}`, + ); + } + if (state >>> SLOT_BITS !== reference >>> SLOT_BITS) { throw new ReferenceError( - "Attempted to read invalid reference " + ref, + `Attempted to use stale reference ${reference}`, ); } - return value; + return state; } } diff --git a/Tests/JavaScriptKitTests/JSClosureTests.swift b/Tests/JavaScriptKitTests/JSClosureTests.swift index 3d609a9b9..e278656d8 100644 --- a/Tests/JavaScriptKitTests/JSClosureTests.swift +++ b/Tests/JavaScriptKitTests/JSClosureTests.swift @@ -92,52 +92,38 @@ class JSClosureTests: XCTestCase { throw XCTSkip("Missing --expose-gc flag") } - // Step 1: Create many JSClosure instances + // Step 1: Create many source closures and keep only JS references alive. + // These closures must remain callable even after heavy finalizer churn. let obj = JSObject() - var closurePointers: Set = [] let numberOfSourceClosures = 10_000 do { var closures: [JSClosure] = [] for i in 0.. maxClosurePointer { - break + let numberOfProbeClosures = 50_000 + for i in 0.. Date: Wed, 13 May 2026 12:44:09 +0200 Subject: [PATCH 51/68] BridgeJS: Fix name collision for same-named nested structs --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 56 +++++- .../Sources/BridgeJSLink/JSGlueGen.swift | 20 +- .../Inputs/MacroSwift/NestedType.swift | 11 ++ .../BridgeJSCodegenTests/NestedType.json | 67 +++++++ .../BridgeJSCodegenTests/NestedType.swift | 90 +++++++++ .../BridgeJSLinkTests/NestedType.d.ts | 19 +- .../BridgeJSLinkTests/NestedType.js | 55 +++++- .../BridgeJSRuntimeTests/ExportAPITests.swift | 18 ++ .../Generated/BridgeJS.swift | 118 ++++++++++++ .../Generated/JavaScript/BridgeJS.json | 173 ++++++++++++++++++ Tests/prelude.mjs | 11 ++ 11 files changed, 611 insertions(+), 27 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index ceaaae8f1..6c283a3b4 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -232,7 +232,9 @@ public struct BridgeJSLink { var structExportEntries: [(js: [String], dts: [String])] = [] for structDefinition in skeleton.structs { let (jsStruct, dtsType, dtsExportEntry) = try renderExportedStruct(structDefinition) - data.topLevelDtsTypeLines.append(contentsOf: dtsType) + if structDefinition.namespace == nil { + data.topLevelDtsTypeLines.append(contentsOf: dtsType) + } if structDefinition.namespace == nil && (!jsStruct.isEmpty || !dtsExportEntry.isEmpty) { structExportEntries.append((js: jsStruct, dts: dtsExportEntry)) @@ -492,7 +494,7 @@ public struct BridgeJSLink { printer.write("bjs[\"swift_js_struct_lower_\(structDef.abiName)\"] = function(objectId) {") printer.indent { printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));" + "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));" ) } printer.write("}") @@ -500,7 +502,7 @@ public struct BridgeJSLink { printer.write("bjs[\"swift_js_struct_lift_\(structDef.abiName)\"] = function() {") printer.indent { printer.write( - "const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lift();" + "const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lift();" ) printer.write("return \(JSGlueVariableScope.reservedSwift).memory.retain(value);") } @@ -1005,7 +1007,7 @@ public struct BridgeJSLink { let structScope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry) let fragment = IntrinsicJSFragment.structHelper(structDefinition: structDef, allStructs: allStructs) _ = try fragment.printCode( - [structDef.name], + [structDef.abiName], IntrinsicJSFragment.PrintCodeContext( scope: structScope, printer: structPrinter, @@ -1159,10 +1161,10 @@ public struct BridgeJSLink { for skeleton in skeletons.compactMap(\.exported) { for structDef in skeleton.structs { printer.write( - "const \(structDef.name)Helpers = __bjs_create\(structDef.name)Helpers();" + "const \(structDef.abiName)Helpers = __bjs_create\(structDef.abiName)Helpers();" ) printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name) = \(structDef.name)Helpers;" + "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName) = \(structDef.abiName)Helpers;" ) printer.nextLine() } @@ -2616,6 +2618,7 @@ extension BridgeJSLink { var functions: [ExportedFunction] = [] var classes: [ExportedClass] = [] var enums: [ExportedEnum] = [] + var structs: [ExportedStruct] = [] var staticProperties: [ExportedProperty] = [] var functionJsLines: [(name: String, lines: [String])] = [] var functionDtsLines: [(name: String, lines: [String])] = [] @@ -2664,6 +2667,14 @@ extension BridgeJSLink { currentNode.content.classes.append(klass) } + for structDef in skeleton.structs where structDef.namespace != nil { + var currentNode = rootNode + for part in structDef.namespace! { + currentNode = currentNode.addChild(part) + } + currentNode.content.structs.append(structDef) + } + for enumDef in skeleton.enums where enumDef.namespace != nil && enumDef.enumType != .namespace { var currentNode = rootNode for part in enumDef.namespace! { @@ -2845,8 +2856,18 @@ extension BridgeJSLink { } } + private func hasExportContent(node: NamespaceNode) -> Bool { + if !node.content.classDtsLines.isEmpty || !node.content.enumDtsLines.isEmpty + || !node.content.functionDtsLines.isEmpty || !node.content.staticProperties.isEmpty + { + return true + } + return node.children.values.contains(where: { hasExportContent(node: $0) }) + } + private func printExportsTypeHierarchy(node: NamespaceNode, printer: CodeFragmentPrinter) { for (childName, childNode) in node.children.sorted(by: { $0.key < $1.key }) { + guard hasExportContent(node: childNode) else { continue } printer.write("\(childName): {") printer.indent { for (_, lines) in childNode.content.classDtsLines.sorted(by: { $0.name < $1.name }) { @@ -2983,8 +3004,8 @@ extension BridgeJSLink { renderTSSignatureCallback: @escaping ([Parameter], BridgeType, Effects) -> String ) { func hasContent(node: NamespaceNode) -> Bool { - // Enums are always included - if !node.content.enums.isEmpty { + // Enums and structs are always included + if !node.content.enums.isEmpty || !node.content.structs.isEmpty { return true } @@ -3164,6 +3185,23 @@ extension BridgeJSLink { } } + // Generate struct interface definitions + let sortedStructs = childNode.content.structs.sorted { $0.name < $1.name } + for structDef in sortedStructs { + let instanceProps = structDef.properties.filter { !$0.isStatic } + printer.write("export interface \(structDef.name) {") + printer.indent { + for property in instanceProps { + let tsType = BridgeJSLink.resolveTypeScriptType( + property.type, + exportedSkeletons: exportedSkeletons + ) + printer.write("\(property.name): \(tsType);") + } + } + printer.write("}") + } + // Only include functions and properties when exposeToGlobal is true if exposeToGlobal { let sortedFunctions = childNode.content.functions.sorted { $0.name < $1.name } @@ -3610,7 +3648,7 @@ extension BridgeType { case .associatedValueEnum(let name): return "\(name)Tag" case .swiftStruct(let name): - return name.components(separatedBy: ".").last ?? name + return name case .namespaceEnum(let name): return name case .swiftProtocol(let name): diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 1ad397f71..accc2a287 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -944,7 +944,7 @@ struct IntrinsicJSFragment: Sendable { fullName: String, kind: JSOptionalKind ) -> IntrinsicJSFragment { - let base = fullName.components(separatedBy: ".").last ?? fullName + let base = fullName.replacingOccurrences(of: ".", with: "_") let absenceLiteral = kind.absenceLiteral return IntrinsicJSFragment( parameters: [], @@ -1300,7 +1300,7 @@ struct IntrinsicJSFragment: Sendable { let base = fullName.components(separatedBy: ".").last ?? fullName return .associatedEnumLowerParameter(enumBase: base) case .swiftStruct(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName + let base = fullName.replacingOccurrences(of: ".", with: "_") return swiftStructLowerParameter(structBase: base) case .closure: return IntrinsicJSFragment( @@ -1360,7 +1360,7 @@ struct IntrinsicJSFragment: Sendable { let base = fullName.components(separatedBy: ".").last ?? fullName return .associatedEnumLiftReturn(enumBase: base) case .swiftStruct(let fullName): - let base = fullName.components(separatedBy: ".").last ?? fullName + let base = fullName.replacingOccurrences(of: ".", with: "_") return swiftStructLiftReturn(structBase: base) case .closure: return IntrinsicJSFragment( @@ -1446,7 +1446,7 @@ struct IntrinsicJSFragment: Sendable { case .importTS: return .jsObjectLiftRetainedObjectId case .exportSwift: - let base = fullName.components(separatedBy: ".").last ?? fullName + let base = fullName.replacingOccurrences(of: ".", with: "_") return IntrinsicJSFragment( parameters: [], printCode: { arguments, context in @@ -1805,7 +1805,7 @@ struct IntrinsicJSFragment: Sendable { } static func swiftStructLowerReturn(fullName: String) -> IntrinsicJSFragment { - swiftStructLower(structBase: fullName.components(separatedBy: ".").last ?? fullName) + swiftStructLower(structBase: fullName.replacingOccurrences(of: ".", with: "_")) } static func swiftStructLowerParameter(structBase: String) -> IntrinsicJSFragment { @@ -2008,7 +2008,7 @@ struct IntrinsicJSFragment: Sendable { } ) case .swiftStruct(let fullName): - let structBase = fullName.components(separatedBy: ".").last ?? fullName + let structBase = fullName.replacingOccurrences(of: ".", with: "_") return IntrinsicJSFragment( parameters: [], printCode: { arguments, context in @@ -2130,7 +2130,7 @@ struct IntrinsicJSFragment: Sendable { } ) case .swiftStruct(let fullName): - let structBase = fullName.components(separatedBy: ".").last ?? fullName + let structBase = fullName.replacingOccurrences(of: ".", with: "_") return IntrinsicJSFragment( parameters: ["value"], printCode: { arguments, context in @@ -2426,7 +2426,7 @@ struct IntrinsicJSFragment: Sendable { ) try printer.indent { printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(this);" + "\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(this);" ) var paramForwardings: [String] = [] @@ -2502,7 +2502,7 @@ struct IntrinsicJSFragment: Sendable { let printer = context.printer let value = arguments[0] printer.write( - "\(JSGlueVariableScope.reservedStructHelpers).\(nestedName).lower(\(value));" + "\(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lower(\(value));" ) return [] } @@ -2540,7 +2540,7 @@ struct IntrinsicJSFragment: Sendable { let (scope, printer) = (context.scope, context.printer) let structVar = scope.variable("struct") printer.write( - "const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedName).lift();" + "const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lift();" ) return [structVar] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift index bd2bcc4fe..12fccb379 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedType.swift @@ -8,3 +8,14 @@ var score: Double } } + +@JS class Player { + @JS func getTag() -> String { + return "player" + } + + @JS struct Stats { + var level: Int + var rating: String + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json index e8666bbc4..f924b3eba 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.json @@ -26,6 +26,32 @@ ], "swiftCallName" : "User" + }, + { + "methods" : [ + { + "abiName" : "bjs_Player_getTag", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getTag", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Player", + "properties" : [ + + ], + "swiftCallName" : "Player" } ], "enums" : [ @@ -79,6 +105,47 @@ } ], "swiftCallName" : "User.Stats" + }, + { + "methods" : [ + + ], + "name" : "Stats", + "namespace" : [ + "Player" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "level", + "namespace" : [ + "Player" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "rating", + "namespace" : [ + "Player" + ], + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Player.Stats" } ] }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift index 35ead0856..ed1a080e9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedType.swift @@ -46,6 +46,54 @@ fileprivate func _bjs_struct_lift_User_Stats_extern() -> Int32 { return _bjs_struct_lift_User_Stats_extern() } +extension Player.Stats: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Player.Stats { + let rating = String.bridgeJSStackPop() + let level = Int.bridgeJSStackPop() + return Player.Stats(level: level, rating: rating) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.level.bridgeJSStackPush() + self.rating.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Player_Stats(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Player_Stats())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Player_Stats") +fileprivate func _bjs_struct_lower_Player_Stats_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Player_Stats_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Player_Stats(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Player_Stats_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Player_Stats") +fileprivate func _bjs_struct_lift_Player_Stats_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Player_Stats_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Player_Stats() -> Int32 { + return _bjs_struct_lift_Player_Stats_extern() +} + @_expose(wasm, "bjs_User_getName") @_cdecl("bjs_User_getName") public func _bjs_User_getName(_ _self: UnsafeMutableRawPointer) -> Void { @@ -86,4 +134,46 @@ 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) +} + +@_expose(wasm, "bjs_Player_getTag") +@_cdecl("bjs_Player_getTag") +public func _bjs_Player_getTag(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Player.bridgeJSLiftParameter(_self).getTag() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Player_deinit") +@_cdecl("bjs_Player_deinit") +public func _bjs_Player_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Player: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Player_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Player_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Player_wrap") +fileprivate func _bjs_Player_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Player_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Player_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Player_wrap_extern(pointer) } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts index 2d3942e06..4e966661e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.d.ts @@ -4,9 +4,17 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. -export interface Stats { - health: number; - score: number; +export namespace Player { + export interface Stats { + level: number; + rating: string; + } +} +export namespace User { + export interface Stats { + health: number; + score: number; + } } /// Represents a Swift heap object like a class instance or an actor instance. export interface SwiftHeapObject { @@ -18,9 +26,14 @@ export interface SwiftHeapObject { export interface User extends SwiftHeapObject { getName(): string; } +export interface Player extends SwiftHeapObject { + getTag(): string; +} export type Exports = { User: { } + Player: { + } } export type Imports = { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index cf24e7e2d..f276877e0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -30,7 +30,7 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; - const __bjs_createStatsHelpers = () => ({ + const __bjs_createUser_StatsHelpers = () => ({ lower: (value) => { i32Stack.push((value.health | 0)); f64Stack.push(value.score); @@ -41,6 +41,20 @@ export async function createInstantiator(options, swift) { return { health: int, score: f64 }; } }); + const __bjs_createPlayer_StatsHelpers = () => ({ + lower: (value) => { + i32Stack.push((value.level | 0)); + const bytes = textEncoder.encode(value.rating); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + const int = i32Stack.pop(); + return { level: int, rating: string }; + } + }); return { /** @@ -110,10 +124,17 @@ export async function createInstantiator(options, swift) { return i64Stack.pop(); } bjs["swift_js_struct_lower_User_Stats"] = function(objectId) { - structHelpers.Stats.lower(swift.memory.getObject(objectId)); + structHelpers.User_Stats.lower(swift.memory.getObject(objectId)); } bjs["swift_js_struct_lift_User_Stats"] = function() { - const value = structHelpers.Stats.lift(); + const value = structHelpers.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)); + } + bjs["swift_js_struct_lift_Player_Stats"] = function() { + const value = structHelpers.Player_Stats.lift(); return swift.memory.retain(value); } bjs["swift_js_return_optional_bool"] = function(isSome, value) { @@ -210,6 +231,10 @@ export async function createInstantiator(options, swift) { if (!importObject["TestModule"]) { importObject["TestModule"] = {}; } + importObject["TestModule"]["bjs_Player_wrap"] = function(pointer) { + const obj = _exports['Player'].__construct(pointer); + return swift.memory.retain(obj); + }; importObject["TestModule"]["bjs_User_wrap"] = function(pointer) { const obj = _exports['User'].__construct(pointer); return swift.memory.retain(obj); @@ -291,11 +316,31 @@ export async function createInstantiator(options, swift) { return ret; } } - const StatsHelpers = __bjs_createStatsHelpers(); - structHelpers.Stats = StatsHelpers; + class Player extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Player_deinit, Player.prototype, null); + } + + getTag() { + instance.exports.bjs_Player_getTag(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + } + const User_StatsHelpers = __bjs_createUser_StatsHelpers(); + structHelpers.User_Stats = User_StatsHelpers; + + const Player_StatsHelpers = __bjs_createPlayer_StatsHelpers(); + structHelpers.Player_Stats = Player_StatsHelpers; const exports = { User, + Player, + Player: { + }, + User: { + }, }; _exports = exports; return exports; diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index c81622f0d..c6e216203 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -1299,6 +1299,24 @@ enum GraphOperations { } } +@JS enum NestedStructGroupA { + @JS struct Metadata { + var label: String + var count: Int + } + + @JS static func roundtripMetadata(_ m: Metadata) -> Metadata { m } +} + +@JS enum NestedStructGroupB { + @JS struct Metadata { + var tag: String + var value: Double + } + + @JS static func roundtripMetadata(_ m: Metadata) -> Metadata { m } +} + class ExportAPITests: XCTestCase { func testAll() { var hasDeinitGreeter = false diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 771838716..f695917db 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -4809,6 +4809,28 @@ public func _bjs_StaticPropertyNamespace_NestedProperties_static_nestedDouble_se #endif } +@_expose(wasm, "bjs_NestedStructGroupA_static_roundtripMetadata") +@_cdecl("bjs_NestedStructGroupA_static_roundtripMetadata") +public func _bjs_NestedStructGroupA_static_roundtripMetadata() -> Void { + #if arch(wasm32) + let ret = NestedStructGroupA.roundtripMetadata(_: NestedStructGroupA.Metadata.bridgeJSLiftParameter()) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_NestedStructGroupB_static_roundtripMetadata") +@_cdecl("bjs_NestedStructGroupB_static_roundtripMetadata") +public func _bjs_NestedStructGroupB_static_roundtripMetadata() -> Void { + #if arch(wasm32) + let ret = NestedStructGroupB.roundtripMetadata(_: NestedStructGroupB.Metadata.bridgeJSLiftParameter()) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt") @_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt") public func _bjs_IntegerTypesSupportExports_static_roundTripInt(_ v: Int32) -> Int32 { @@ -5319,6 +5341,102 @@ extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { } } +extension NestedStructGroupA.Metadata: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> NestedStructGroupA.Metadata { + let count = Int.bridgeJSStackPop() + let label = String.bridgeJSStackPop() + return NestedStructGroupA.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_NestedStructGroupA_Metadata(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_NestedStructGroupA_Metadata())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_NestedStructGroupA_Metadata") +fileprivate func _bjs_struct_lower_NestedStructGroupA_Metadata_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_NestedStructGroupA_Metadata_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_NestedStructGroupA_Metadata(_ objectId: Int32) -> Void { + return _bjs_struct_lower_NestedStructGroupA_Metadata_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_NestedStructGroupA_Metadata") +fileprivate func _bjs_struct_lift_NestedStructGroupA_Metadata_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_NestedStructGroupA_Metadata_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_NestedStructGroupA_Metadata() -> Int32 { + return _bjs_struct_lift_NestedStructGroupA_Metadata_extern() +} + +extension NestedStructGroupB.Metadata: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> NestedStructGroupB.Metadata { + let value = Double.bridgeJSStackPop() + let tag = String.bridgeJSStackPop() + return NestedStructGroupB.Metadata(tag: tag, value: value) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.tag.bridgeJSStackPush() + self.value.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_NestedStructGroupB_Metadata(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_NestedStructGroupB_Metadata())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_NestedStructGroupB_Metadata") +fileprivate func _bjs_struct_lower_NestedStructGroupB_Metadata_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_NestedStructGroupB_Metadata_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_NestedStructGroupB_Metadata(_ objectId: Int32) -> Void { + return _bjs_struct_lower_NestedStructGroupB_Metadata_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_NestedStructGroupB_Metadata") +fileprivate func _bjs_struct_lift_NestedStructGroupB_Metadata_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_NestedStructGroupB_Metadata_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_NestedStructGroupB_Metadata() -> Int32 { + return _bjs_struct_lift_NestedStructGroupB_Metadata_extern() +} + extension Point: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Point { let y = Int.bridgeJSStackPop() diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 7a3e7f7fe..5222902e0 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -9163,6 +9163,100 @@ { "cases" : [ + ], + "emitStyle" : "const", + "name" : "NestedStructGroupA", + "staticMethods" : [ + { + "abiName" : "bjs_NestedStructGroupA_static_roundtripMetadata", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundtripMetadata", + "namespace" : [ + "NestedStructGroupA" + ], + "parameters" : [ + { + "label" : "_", + "name" : "m", + "type" : { + "swiftStruct" : { + "_0" : "NestedStructGroupA.Metadata" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "NestedStructGroupA.Metadata" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "NestedStructGroupA" + } + } + } + ], + "staticProperties" : [ + + ], + "swiftCallName" : "NestedStructGroupA", + "tsFullPath" : "NestedStructGroupA" + }, + { + "cases" : [ + + ], + "emitStyle" : "const", + "name" : "NestedStructGroupB", + "staticMethods" : [ + { + "abiName" : "bjs_NestedStructGroupB_static_roundtripMetadata", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundtripMetadata", + "namespace" : [ + "NestedStructGroupB" + ], + "parameters" : [ + { + "label" : "_", + "name" : "m", + "type" : { + "swiftStruct" : { + "_0" : "NestedStructGroupB.Metadata" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "NestedStructGroupB.Metadata" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "NestedStructGroupB" + } + } + } + ], + "staticProperties" : [ + + ], + "swiftCallName" : "NestedStructGroupB", + "tsFullPath" : "NestedStructGroupB" + }, + { + "cases" : [ + ], "emitStyle" : "const", "name" : "IntegerTypesSupportExports", @@ -14890,6 +14984,85 @@ } ], "structs" : [ + { + "methods" : [ + + ], + "name" : "Metadata", + "namespace" : [ + "NestedStructGroupA" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "label", + "namespace" : [ + "NestedStructGroupA" + ], + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "count", + "namespace" : [ + "NestedStructGroupA" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "NestedStructGroupA.Metadata" + }, + { + "methods" : [ + + ], + "name" : "Metadata", + "namespace" : [ + "NestedStructGroupB" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "tag", + "namespace" : [ + "NestedStructGroupB" + ], + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "value", + "namespace" : [ + "NestedStructGroupB" + ], + "type" : { + "double" : { + + } + } + } + ], + "swiftCallName" : "NestedStructGroupB.Metadata" + }, { "methods" : [ diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 10c73ec2f..42aa9feaf 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -1023,6 +1023,17 @@ function testStructSupport(exports) { const fooContainerResult2 = exports.roundTripFooContainer(fooContainer2); assert.equal(fooContainerResult2.foo.value, "first"); assert.equal(fooContainerResult2.optionalFoo, null); + + // Test nested structs with same short name under different parents + const metaA = { label: "hello", count: 42 }; + const metaAResult = exports.NestedStructGroupA.roundtripMetadata(metaA); + assert.equal(metaAResult.label, "hello"); + assert.equal(metaAResult.count, 42); + + const metaB = { tag: "world", value: 3.14 }; + const metaBResult = exports.NestedStructGroupB.roundtripMetadata(metaB); + assert.equal(metaBResult.tag, "world"); + assert.equal(metaBResult.value, 3.14); } /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ From fc672e7b429f835888f999437dfd28843287e643 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 13 May 2026 19:50:35 +0200 Subject: [PATCH 52/68] BridgeJS: Add JSTypedArray as a recognized BridgeJS type (#746) BridgeJS: Add JSTypedArray convenience typealiases as recognized types Add JSInt8Array, JSUint8Array, JSInt16Array, JSUint16Array, JSInt32Array, JSUint32Array, JSFloat32Array, JSFloat64Array typealiases and pre-seed them in SwiftToSkeleton so BridgeJS recognizes them in @JS signatures. Users can now write: @JS func processData(_ data: JSUint8Array) -> JSUint8Array Generated TypeScript uses native typed array names: processData(data: Uint8Array): Uint8Array Bridging is reference-based (passes JSObject ID, no data copying). Follows the existing JSPromise pre-seeding pattern. --- .../BridgeJSCore/SwiftToSkeleton.swift | 32 ++ .../Sources/BridgeJSLink/BridgeJSLink.swift | 15 + .../Inputs/MacroSwift/JSTypedArrayTypes.swift | 19 ++ .../JSTypedArrayTypes.json | 123 ++++++++ .../JSTypedArrayTypes.swift | 43 +++ .../BridgeJSLinkTests/JSTypedArrayTypes.d.ts | 21 ++ .../BridgeJSLinkTests/JSTypedArrayTypes.js | 235 ++++++++++++++ .../BasicObjects/JSTypedArray.swift | 9 + .../Exporting-Swift/Exporting-Swift-Array.md | 36 +++ .../Articles/BridgeJS/Supported-Types.md | 14 + .../Generated/BridgeJS.swift | 167 ++++++++++ .../Generated/JavaScript/BridgeJS.json | 298 ++++++++++++++++++ .../JSTypedArrayTests.swift | 53 ++++ .../JavaScript/JSTypedArrayTests.mjs | 77 +++++ Tests/prelude.mjs | 2 + 15 files changed, 1144 insertions(+) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSTypedArrayTypes.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js create mode 100644 Tests/BridgeJSRuntimeTests/JSTypedArrayTests.swift create mode 100644 Tests/BridgeJSRuntimeTests/JavaScript/JSTypedArrayTests.mjs diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index f39ac16f8..57b9a57df 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -42,6 +42,14 @@ public final class SwiftToSkeleton { self.typeDeclResolver.addSourceFile( """ @JSClass struct JSPromise {} + @JSClass struct JSInt8Array {} + @JSClass struct JSUint8Array {} + @JSClass struct JSInt16Array {} + @JSClass struct JSUint16Array {} + @JSClass struct JSInt32Array {} + @JSClass struct JSUint32Array {} + @JSClass struct JSFloat32Array {} + @JSClass struct JSFloat64Array {} """ ) } @@ -128,11 +136,35 @@ public final class SwiftToSkeleton { ) } + private static let jsTypedArrayTypealiasNames: [String: String] = [ + "Int8": "JSInt8Array", + "UInt8": "JSUint8Array", + "Int16": "JSInt16Array", + "UInt16": "JSUint16Array", + "Int32": "JSInt32Array", + "UInt32": "JSUint32Array", + "Float": "JSFloat32Array", + "Float32": "JSFloat32Array", + "Double": "JSFloat64Array", + "Float64": "JSFloat64Array", + ] + func lookupType(for type: TypeSyntax, errors: inout [DiagnosticError]) -> BridgeType? { if let attributedType = type.as(AttributedTypeSyntax.self) { return lookupType(for: attributedType.baseType, errors: &errors) } + // JSTypedArray + if let identifierType = type.as(IdentifierTypeSyntax.self), + identifierType.name.text == "JSTypedArray", + let genericArgs = identifierType.genericArgumentClause?.arguments, + genericArgs.count == 1, + let elementName = genericArgs.first?.argument.as(IdentifierTypeSyntax.self)?.name.text, + let typealiasName = Self.jsTypedArrayTypealiasNames[elementName] + { + return .jsObject(typealiasName) + } + if let identifierType = type.as(IdentifierTypeSyntax.self), identifierType.name.text == "JSTypedClosure", let genericArgs = identifierType.genericArgumentClause?.arguments, diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 6c283a3b4..aed27437b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -3632,6 +3632,9 @@ extension BridgeType { case .bool: return "boolean" case .jsObject(let name): + if let name, let tsName = Self.jsTypedArrayTSNames[name] { + return tsName + } return name ?? "any" case .jsValue: return "any" @@ -3668,6 +3671,18 @@ extension BridgeType { return "Record" } } + + /// Maps JSTypedArray Swift typealias names to their JavaScript TypedArray constructor names. + private static let jsTypedArrayTSNames: [String: String] = [ + "JSInt8Array": "Int8Array", + "JSUint8Array": "Uint8Array", + "JSInt16Array": "Int16Array", + "JSUint16Array": "Uint16Array", + "JSInt32Array": "Int32Array", + "JSUint32Array": "Uint32Array", + "JSFloat32Array": "Float32Array", + "JSFloat64Array": "Float64Array", + ] } extension WasmCoreType { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSTypedArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSTypedArrayTypes.swift new file mode 100644 index 000000000..7f308f560 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSTypedArrayTypes.swift @@ -0,0 +1,19 @@ +import JavaScriptKit + +// Using typealiases +@JS func processBytes(_ data: JSUint8Array) -> JSUint8Array { + return data +} + +@JS func processFloats(_ data: JSFloat32Array) -> JSFloat32Array { + return data +} + +// Using generic form directly +@JS func processGenericDoubles(_ data: JSTypedArray) -> JSTypedArray { + return data +} + +@JS func processGenericInts(_ data: JSTypedArray) -> JSTypedArray { + return data +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.json new file mode 100644 index 000000000..a7b9c8623 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.json @@ -0,0 +1,123 @@ +{ + "exported" : { + "classes" : [ + + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_processBytes", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processBytes", + "parameters" : [ + { + "label" : "_", + "name" : "data", + "type" : { + "jsObject" : { + "_0" : "JSUint8Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSUint8Array" + } + } + }, + { + "abiName" : "bjs_processFloats", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processFloats", + "parameters" : [ + { + "label" : "_", + "name" : "data", + "type" : { + "jsObject" : { + "_0" : "JSFloat32Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSFloat32Array" + } + } + }, + { + "abiName" : "bjs_processGenericDoubles", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processGenericDoubles", + "parameters" : [ + { + "label" : "_", + "name" : "data", + "type" : { + "jsObject" : { + "_0" : "JSFloat64Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSFloat64Array" + } + } + }, + { + "abiName" : "bjs_processGenericInts", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processGenericInts", + "parameters" : [ + { + "label" : "_", + "name" : "data", + "type" : { + "jsObject" : { + "_0" : "JSInt32Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSInt32Array" + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.swift new file mode 100644 index 000000000..4777af058 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSTypedArrayTypes.swift @@ -0,0 +1,43 @@ +@_expose(wasm, "bjs_processBytes") +@_cdecl("bjs_processBytes") +public func _bjs_processBytes(_ data: Int32) -> Int32 { + #if arch(wasm32) + let ret = processBytes(_: JSUint8Array.bridgeJSLiftParameter(data)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_processFloats") +@_cdecl("bjs_processFloats") +public func _bjs_processFloats(_ data: Int32) -> Int32 { + #if arch(wasm32) + let ret = processFloats(_: JSFloat32Array.bridgeJSLiftParameter(data)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_processGenericDoubles") +@_cdecl("bjs_processGenericDoubles") +public func _bjs_processGenericDoubles(_ data: Int32) -> Int32 { + #if arch(wasm32) + let ret = processGenericDoubles(_: JSFloat64Array.bridgeJSLiftParameter(data)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_processGenericInts") +@_cdecl("bjs_processGenericInts") +public func _bjs_processGenericInts(_ data: Int32) -> Int32 { + #if arch(wasm32) + let ret = processGenericInts(_: JSInt32Array.bridgeJSLiftParameter(data)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts new file mode 100644 index 000000000..b842e7d7d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.d.ts @@ -0,0 +1,21 @@ +// 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 type Exports = { + processBytes(data: Uint8Array): Uint8Array; + processFloats(data: Float32Array): Float32Array; + processGenericDoubles(data: Float64Array): Float64Array; + processGenericInts(data: Int32Array): Int32Array; +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => void; + createExports: (instance: WebAssembly.Instance) => Exports; +}>; \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js new file mode 100644 index 000000000..ee51d4a28 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js @@ -0,0 +1,235 @@ +// 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 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 = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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(); + } + 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) {} + }, + 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const exports = { + processBytes: function bjs_processBytes(data) { + const ret = instance.exports.bjs_processBytes(swift.memory.retain(data)); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + processFloats: function bjs_processFloats(data) { + const ret = instance.exports.bjs_processFloats(swift.memory.retain(data)); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + processGenericDoubles: function bjs_processGenericDoubles(data) { + const ret = instance.exports.bjs_processGenericDoubles(swift.memory.retain(data)); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + processGenericInts: function bjs_processGenericInts(data) { + const ret = instance.exports.bjs_processGenericInts(swift.memory.retain(data)); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift index 0ad7b235a..4717b6705 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift @@ -204,3 +204,12 @@ public enum JSUInt8Clamped: TypedArrayElement { } public typealias JSUInt8ClampedArray = JSTypedArray + +public typealias JSInt8Array = JSTypedArray +public typealias JSUint8Array = JSTypedArray +public typealias JSInt16Array = JSTypedArray +public typealias JSUint16Array = JSTypedArray +public typealias JSInt32Array = JSTypedArray +public typealias JSUint32Array = JSTypedArray +public typealias JSFloat32Array = JSTypedArray +public typealias JSFloat64Array = JSTypedArray diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Array.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Array.md index e97bceefa..1100358ba 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Array.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Array.md @@ -95,6 +95,42 @@ TypeScript definitions: - `[Int]?` becomes `number[] | null` - `[[Int]]` becomes `number[][]` +## Using TypedArrays + +When you need the JavaScript API to use native TypedArray types (e.g., `Uint8Array` for `fetch` body, `Float32Array` for WebGPU), use ``JSTypedArray`` instead of a plain Swift array: + +```swift +import JavaScriptKit + +@JS func processData(_ data: JSTypedArray) -> JSTypedArray { + return data +} + +// Convenience typealiases also work: +@JS func processFloats(_ data: JSFloat32Array) -> JSFloat32Array { + return data +} +``` + +Generated TypeScript: + +```typescript +export type Exports = { + processData(data: Uint8Array): Uint8Array; + processFloats(data: Float32Array): Float32Array; +} +``` + +Unlike plain arrays which use copy semantics, `JSTypedArray` uses **reference semantics** — it wraps a JavaScript TypedArray object and passes it by reference (no data copying). This is ideal for large binary data or when interacting with JavaScript APIs that expect TypedArrays. + +| Swift | TypeScript | +|:------|:-----------| +| `JSTypedArray` / `JSUint8Array` | `Uint8Array` | +| `JSTypedArray` / `JSInt8Array` | `Int8Array` | +| `JSTypedArray` / `JSInt32Array` | `Int32Array` | +| `JSTypedArray` / `JSFloat32Array` | `Float32Array` | +| `JSTypedArray` / `JSFloat64Array` | `Float64Array` | + ## How It Works Arrays use **copy semantics** when crossing the Swift/JavaScript boundary: diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md index 81a135af3..5c609ab72 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Supported-Types.md @@ -16,6 +16,20 @@ Swift types and their JavaScript/TypeScript equivalents at the BridgeJS boundary | ``JSUndefinedOr`` `` | `undefined` or `T` | `T \| undefined` | | ``JSObject`` | object | `object` | | ``JSValue`` | any | `any` | +| ``JSTypedArray`` `` | TypedArray | `Uint8Array`, `Float32Array`, etc. | + +### TypedArray mapping + +When using `JSTypedArray` (or convenience typealiases) in `@JS` signatures, the TypeScript type maps to the corresponding JavaScript TypedArray: + +| Swift | TypeScript | +|:--|:--| +| `JSTypedArray` / `JSUint8Array` | `Uint8Array` | +| `JSTypedArray` / `JSInt32Array` | `Int32Array` | +| `JSTypedArray` / `JSFloat32Array` | `Float32Array` | +| `JSTypedArray` / `JSFloat64Array` | `Float64Array` | + +See for usage details. ## See Also diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index f695917db..3fa4eb9d5 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -4941,6 +4941,50 @@ public func _bjs_IntegerTypesSupportExports_static_roundTripUInt64(_ v: Int64) - #endif } +@_expose(wasm, "bjs_JSTypedArrayExports_static_roundTripUint8Array") +@_cdecl("bjs_JSTypedArrayExports_static_roundTripUint8Array") +public func _bjs_JSTypedArrayExports_static_roundTripUint8Array(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = JSTypedArrayExports.roundTripUint8Array(_: JSUint8Array.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSTypedArrayExports_static_roundTripFloat32Array") +@_cdecl("bjs_JSTypedArrayExports_static_roundTripFloat32Array") +public func _bjs_JSTypedArrayExports_static_roundTripFloat32Array(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = JSTypedArrayExports.roundTripFloat32Array(_: JSFloat32Array.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSTypedArrayExports_static_roundTripFloat64Array") +@_cdecl("bjs_JSTypedArrayExports_static_roundTripFloat64Array") +public func _bjs_JSTypedArrayExports_static_roundTripFloat64Array(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = JSTypedArrayExports.roundTripFloat64Array(_: JSFloat64Array.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSTypedArrayExports_static_roundTripInt32Array") +@_cdecl("bjs_JSTypedArrayExports_static_roundTripInt32Array") +public func _bjs_JSTypedArrayExports_static_roundTripInt32Array(_ v: Int32) -> Int32 { + #if arch(wasm32) + let ret = JSTypedArrayExports.roundTripInt32Array(_: JSInt32Array.bridgeJSLiftParameter(v)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_OptionalSupportExports_static_roundTripOptionalString") @_cdecl("bjs_OptionalSupportExports_static_roundTripOptionalString") public func _bjs_OptionalSupportExports_static_roundTripOptionalString(_ vIsSome: Int32, _ vBytes: Int32, _ vLength: Int32) -> Void { @@ -13658,6 +13702,129 @@ func _$JSClassSupportImports_makeJSClassWithArrayMembers(_ numbers: [Int], _ lab return JSClassWithArrayMembers.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSTypedArrayImports_jsCreateUint8Array_static") +fileprivate func bjs_JSTypedArrayImports_jsCreateUint8Array_static_extern() -> Int32 +#else +fileprivate func bjs_JSTypedArrayImports_jsCreateUint8Array_static_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSTypedArrayImports_jsCreateUint8Array_static() -> Int32 { + return bjs_JSTypedArrayImports_jsCreateUint8Array_static_extern() +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSTypedArrayImports_jsRoundTripUint8Array_static") +fileprivate func bjs_JSTypedArrayImports_jsRoundTripUint8Array_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_JSTypedArrayImports_jsRoundTripUint8Array_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSTypedArrayImports_jsRoundTripUint8Array_static(_ v: Int32) -> Int32 { + return bjs_JSTypedArrayImports_jsRoundTripUint8Array_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSTypedArrayImports_jsRoundTripFloat32Array_static") +fileprivate func bjs_JSTypedArrayImports_jsRoundTripFloat32Array_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_JSTypedArrayImports_jsRoundTripFloat32Array_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSTypedArrayImports_jsRoundTripFloat32Array_static(_ v: Int32) -> Int32 { + return bjs_JSTypedArrayImports_jsRoundTripFloat32Array_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSTypedArrayImports_jsRoundTripFloat64Array_static") +fileprivate func bjs_JSTypedArrayImports_jsRoundTripFloat64Array_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_JSTypedArrayImports_jsRoundTripFloat64Array_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSTypedArrayImports_jsRoundTripFloat64Array_static(_ v: Int32) -> Int32 { + return bjs_JSTypedArrayImports_jsRoundTripFloat64Array_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSTypedArrayImports_jsRoundTripInt32Array_static") +fileprivate func bjs_JSTypedArrayImports_jsRoundTripInt32Array_static_extern(_ v: Int32) -> Int32 +#else +fileprivate func bjs_JSTypedArrayImports_jsRoundTripInt32Array_static_extern(_ v: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSTypedArrayImports_jsRoundTripInt32Array_static(_ v: Int32) -> Int32 { + return bjs_JSTypedArrayImports_jsRoundTripInt32Array_static_extern(v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSTypedArrayImports_runJsTypedArrayTests_static") +fileprivate func bjs_JSTypedArrayImports_runJsTypedArrayTests_static_extern() -> Void +#else +fileprivate func bjs_JSTypedArrayImports_runJsTypedArrayTests_static_extern() -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_JSTypedArrayImports_runJsTypedArrayTests_static() -> Void { + return bjs_JSTypedArrayImports_runJsTypedArrayTests_static_extern() +} + +func _$JSTypedArrayImports_jsCreateUint8Array() throws(JSException) -> JSUint8Array { + let ret = bjs_JSTypedArrayImports_jsCreateUint8Array_static() + if let error = _swift_js_take_exception() { + throw error + } + return JSUint8Array.bridgeJSLiftReturn(ret) +} + +func _$JSTypedArrayImports_jsRoundTripUint8Array(_ v: JSUint8Array) throws(JSException) -> JSUint8Array { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_JSTypedArrayImports_jsRoundTripUint8Array_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSUint8Array.bridgeJSLiftReturn(ret) +} + +func _$JSTypedArrayImports_jsRoundTripFloat32Array(_ v: JSFloat32Array) throws(JSException) -> JSFloat32Array { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_JSTypedArrayImports_jsRoundTripFloat32Array_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSFloat32Array.bridgeJSLiftReturn(ret) +} + +func _$JSTypedArrayImports_jsRoundTripFloat64Array(_ v: JSFloat64Array) throws(JSException) -> JSFloat64Array { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_JSTypedArrayImports_jsRoundTripFloat64Array_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSFloat64Array.bridgeJSLiftReturn(ret) +} + +func _$JSTypedArrayImports_jsRoundTripInt32Array(_ v: JSInt32Array) throws(JSException) -> JSInt32Array { + let vValue = v.bridgeJSLowerParameter() + let ret = bjs_JSTypedArrayImports_jsRoundTripInt32Array_static(vValue) + if let error = _swift_js_take_exception() { + throw error + } + return JSInt32Array.bridgeJSLiftReturn(ret) +} + +func _$JSTypedArrayImports_runJsTypedArrayTests() throws(JSException) -> Void { + bjs_JSTypedArrayImports_runJsTypedArrayTests_static() + if let error = _swift_js_take_exception() { + throw error + } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_MyJSClassInternal_init") fileprivate func bjs_MyJSClassInternal_init_extern() -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 5222902e0..94142f470 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -9661,6 +9661,152 @@ { "cases" : [ + ], + "emitStyle" : "const", + "name" : "JSTypedArrayExports", + "staticMethods" : [ + { + "abiName" : "bjs_JSTypedArrayExports_static_roundTripUint8Array", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripUint8Array", + "namespace" : [ + "JSTypedArrayExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSUint8Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSUint8Array" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "JSTypedArrayExports" + } + } + }, + { + "abiName" : "bjs_JSTypedArrayExports_static_roundTripFloat32Array", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripFloat32Array", + "namespace" : [ + "JSTypedArrayExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSFloat32Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSFloat32Array" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "JSTypedArrayExports" + } + } + }, + { + "abiName" : "bjs_JSTypedArrayExports_static_roundTripFloat64Array", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripFloat64Array", + "namespace" : [ + "JSTypedArrayExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSFloat64Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSFloat64Array" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "JSTypedArrayExports" + } + } + }, + { + "abiName" : "bjs_JSTypedArrayExports_static_roundTripInt32Array", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "roundTripInt32Array", + "namespace" : [ + "JSTypedArrayExports" + ], + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSInt32Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSInt32Array" + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "JSTypedArrayExports" + } + } + } + ], + "staticProperties" : [ + + ], + "swiftCallName" : "JSTypedArrayExports", + "tsFullPath" : "JSTypedArrayExports" + }, + { + "cases" : [ + ], "emitStyle" : "const", "name" : "OptionalSupportExports", @@ -20215,6 +20361,158 @@ { "functions" : [ + ], + "types" : [ + { + "accessLevel" : "internal", + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "JSTypedArrayImports", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsCreateUint8Array", + "parameters" : [ + + ], + "returnType" : { + "jsObject" : { + "_0" : "JSUint8Array" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripUint8Array", + "parameters" : [ + { + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSUint8Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSUint8Array" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripFloat32Array", + "parameters" : [ + { + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSFloat32Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSFloat32Array" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripFloat64Array", + "parameters" : [ + { + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSFloat64Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSFloat64Array" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripInt32Array", + "parameters" : [ + { + "name" : "v", + "type" : { + "jsObject" : { + "_0" : "JSInt32Array" + } + } + } + ], + "returnType" : { + "jsObject" : { + "_0" : "JSInt32Array" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "runJsTypedArrayTests", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ] + } + ] + }, + { + "functions" : [ + ], "types" : [ { diff --git a/Tests/BridgeJSRuntimeTests/JSTypedArrayTests.swift b/Tests/BridgeJSRuntimeTests/JSTypedArrayTests.swift new file mode 100644 index 000000000..25045ecc8 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/JSTypedArrayTests.swift @@ -0,0 +1,53 @@ +import XCTest +import JavaScriptKit + +@JS enum JSTypedArrayExports { + @JS static func roundTripUint8Array(_ v: JSUint8Array) -> JSUint8Array { v } + @JS static func roundTripFloat32Array(_ v: JSFloat32Array) -> JSFloat32Array { v } + @JS static func roundTripFloat64Array(_ v: JSFloat64Array) -> JSFloat64Array { v } + @JS static func roundTripInt32Array(_ v: JSInt32Array) -> JSInt32Array { v } +} + +@JSClass struct JSTypedArrayImports { + @JSFunction static func jsCreateUint8Array() throws(JSException) -> JSUint8Array + @JSFunction static func jsRoundTripUint8Array(_ v: JSUint8Array) throws(JSException) -> JSUint8Array + @JSFunction static func jsRoundTripFloat32Array(_ v: JSFloat32Array) throws(JSException) -> JSFloat32Array + @JSFunction static func jsRoundTripFloat64Array(_ v: JSFloat64Array) throws(JSException) -> JSFloat64Array + @JSFunction static func jsRoundTripInt32Array(_ v: JSInt32Array) throws(JSException) -> JSInt32Array + @JSFunction static func runJsTypedArrayTests() throws(JSException) +} + +final class JSTypedArrayTests: XCTestCase { + func testRunJsTypedArrayTests() throws { + try JSTypedArrayImports.runJsTypedArrayTests() + } + + func testRoundTripUint8Array() throws { + let arr = JSUint8Array([1, 2, 3, 255]) + let result = try JSTypedArrayImports.jsRoundTripUint8Array(arr) + XCTAssertEqual(result.length, 4) + } + + func testCreateUint8Array() throws { + let result = try JSTypedArrayImports.jsCreateUint8Array() + XCTAssertEqual(result.length, 3) + } + + func testRoundTripFloat32Array() throws { + let arr = JSFloat32Array([1.0, 2.5, 3.0]) + let result = try JSTypedArrayImports.jsRoundTripFloat32Array(arr) + XCTAssertEqual(result.length, 3) + } + + func testRoundTripFloat64Array() throws { + let arr = JSFloat64Array([1.0, 2.5, 3.14159]) + let result = try JSTypedArrayImports.jsRoundTripFloat64Array(arr) + XCTAssertEqual(result.length, 3) + } + + func testRoundTripInt32Array() throws { + let arr = JSInt32Array([1, -2, 2_147_483_647]) + let result = try JSTypedArrayImports.jsRoundTripInt32Array(arr) + XCTAssertEqual(result.length, 3) + } +} diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/JSTypedArrayTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/JSTypedArrayTests.mjs new file mode 100644 index 000000000..f29c248f9 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/JavaScript/JSTypedArrayTests.mjs @@ -0,0 +1,77 @@ +// @ts-check + +import assert from 'node:assert'; + +/** + * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["JSTypedArrayImports"]} + */ +export function getImports(importsContext) { + return { + jsCreateUint8Array: function () { + return new Uint8Array([10, 20, 30]); + }, + jsRoundTripUint8Array: function (arr) { + assert.ok(arr instanceof Uint8Array, 'Expected Uint8Array'); + return arr; + }, + jsRoundTripFloat32Array: function (arr) { + assert.ok(arr instanceof Float32Array, 'Expected Float32Array'); + return arr; + }, + jsRoundTripFloat64Array: function (arr) { + assert.ok(arr instanceof Float64Array, 'Expected Float64Array'); + return arr; + }, + jsRoundTripInt32Array: function (arr) { + assert.ok(arr instanceof Int32Array, 'Expected Int32Array'); + return arr; + }, + runJsTypedArrayTests: () => { + const exports = importsContext.getExports(); + if (!exports) { throw new Error("No exports!?"); } + runJsTypedArrayTests(exports); + }, + }; +} + +/** + * JSTypedArray bridging coverage for BridgeJS runtime tests. + * @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} rootExports + */ +export function runJsTypedArrayTests(rootExports) { + const exports = rootExports.JSTypedArrayExports; + + // Uint8Array round-trip + const u8 = new Uint8Array([1, 2, 3, 255]); + const u8Result = exports.roundTripUint8Array(u8); + assert.ok(u8Result instanceof Uint8Array, 'Expected Uint8Array back from Swift'); + assert.equal(u8Result.length, 4); + assert.deepEqual(Array.from(u8Result), [1, 2, 3, 255]); + + // Float32Array round-trip + const f32 = new Float32Array([1.0, 2.5, 3.0]); + const f32Result = exports.roundTripFloat32Array(f32); + assert.ok(f32Result instanceof Float32Array, 'Expected Float32Array back from Swift'); + assert.equal(f32Result.length, 3); + assert.deepEqual(Array.from(f32Result), [1.0, 2.5, 3.0]); + + // Float64Array round-trip + const f64 = new Float64Array([1.0, 2.5, 3.14159]); + const f64Result = exports.roundTripFloat64Array(f64); + assert.ok(f64Result instanceof Float64Array, 'Expected Float64Array back from Swift'); + assert.equal(f64Result.length, 3); + assert.deepEqual(Array.from(f64Result), [1.0, 2.5, 3.14159]); + + // Int32Array round-trip + const i32 = new Int32Array([1, -2, 2147483647]); + const i32Result = exports.roundTripInt32Array(i32); + assert.ok(i32Result instanceof Int32Array, 'Expected Int32Array back from Swift'); + assert.equal(i32Result.length, 3); + assert.deepEqual(Array.from(i32Result), [1, -2, 2147483647]); + + // Empty typed array + const emptyU8 = new Uint8Array([]); + const emptyResult = exports.roundTripUint8Array(emptyU8); + assert.ok(emptyResult instanceof Uint8Array, 'Expected Uint8Array for empty array'); + assert.equal(emptyResult.length, 0); +} diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 42aa9feaf..2c922dbe2 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -14,6 +14,7 @@ import { getImports as getDefaultArgumentImports } from './BridgeJSRuntimeTests/ import { getImports as getJSClassSupportImports, JSClassWithArrayMembers } from './BridgeJSRuntimeTests/JavaScript/JSClassSupportTests.mjs'; import { getImports as getIntegerTypesSupportImports } from './BridgeJSRuntimeTests/JavaScript/IntegerTypesSupportTests.mjs'; import { getImports as getAsyncImportImports, runAsyncWorksTests } from './BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs'; +import { getImports as getJSTypedArrayImports } from './BridgeJSRuntimeTests/JavaScript/JSTypedArrayTests.mjs'; import { getImports as getIdentityModeTestImports } from './BridgeJSIdentityTests/JavaScript/IdentityModeTests.mjs'; /** @type {import('../.build/plugins/PackageToJS/outputs/PackageTests/test.d.ts').SetupOptionsFn} */ @@ -156,6 +157,7 @@ export async function setupOptions(options, context) { DefaultArgumentImports: getDefaultArgumentImports(importsContext), JSClassSupportImports: getJSClassSupportImports(importsContext), IntegerTypesSupportImports: getIntegerTypesSupportImports(importsContext), + JSTypedArrayImports: getJSTypedArrayImports(importsContext), IdentityModeTestImports: getIdentityModeTestImports(importsContext), }; }, From 403ae956d68503957699b6dc4c07b73caad031b7 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 13 May 2026 22:58:13 +0200 Subject: [PATCH 53/68] BridgeJS: Optimize numeric array transfer with bulk TypedArray copy (#745) --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 16 + .../Sources/BridgeJSLink/JSGlueGen.swift | 29 +- .../BridgeJSLinkTests/ArrayTypes.js | 623 +++++++++++------- .../__Snapshots__/BridgeJSLinkTests/Async.js | 8 + .../BridgeJSLinkTests/AsyncImport.js | 8 + .../BridgeJSLinkTests/AsyncStaticImport.js | 8 + .../BridgeJSLinkTests/DefaultParameters.js | 83 ++- .../BridgeJSLinkTests/DictionaryTypes.js | 23 +- .../BridgeJSLinkTests/EnumAssociatedValue.js | 38 +- .../BridgeJSLinkTests/EnumCase.js | 8 + .../BridgeJSLinkTests/EnumNamespace.Global.js | 8 + .../BridgeJSLinkTests/EnumNamespace.js | 8 + .../BridgeJSLinkTests/EnumRawType.js | 8 + .../BridgeJSLinkTests/FixedWidthIntegers.js | 8 + .../BridgeJSLinkTests/GlobalGetter.js | 8 + .../BridgeJSLinkTests/GlobalThisImports.js | 8 + .../IdentityModeClass.ConfigPointer.js | 8 + .../IdentityModeClass.PerClass.js | 8 + .../BridgeJSLinkTests/IdentityModeClass.js | 8 + .../BridgeJSLinkTests/ImportArray.js | 38 +- .../ImportedTypeInExportedInterface.js | 58 +- .../BridgeJSLinkTests/InvalidPropertyNames.js | 8 + .../BridgeJSLinkTests/JSClass.js | 8 + .../JSClassStaticFunctions.js | 8 + .../BridgeJSLinkTests/JSTypedArrayTypes.js | 8 + .../BridgeJSLinkTests/JSValue.js | 71 +- .../BridgeJSLinkTests/MixedGlobal.js | 8 + .../BridgeJSLinkTests/MixedModules.js | 8 + .../BridgeJSLinkTests/MixedPrivate.js | 8 + .../BridgeJSLinkTests/Namespaces.Global.js | 25 +- .../BridgeJSLinkTests/Namespaces.js | 25 +- .../BridgeJSLinkTests/NestedType.js | 8 + .../BridgeJSLinkTests/Optionals.js | 8 + .../BridgeJSLinkTests/PrimitiveParameters.js | 8 + .../BridgeJSLinkTests/PrimitiveReturn.js | 8 + .../BridgeJSLinkTests/PropertyTypes.js | 8 + .../BridgeJSLinkTests/Protocol.js | 46 +- .../BridgeJSLinkTests/ProtocolInClosure.js | 8 + .../StaticFunctions.Global.js | 8 + .../BridgeJSLinkTests/StaticFunctions.js | 8 + .../StaticProperties.Global.js | 8 + .../BridgeJSLinkTests/StaticProperties.js | 8 + .../BridgeJSLinkTests/StringParameter.js | 8 + .../BridgeJSLinkTests/StringReturn.js | 8 + .../BridgeJSLinkTests/SwiftClass.js | 8 + .../BridgeJSLinkTests/SwiftClosure.js | 8 + .../BridgeJSLinkTests/SwiftClosureImports.js | 8 + .../BridgeJSLinkTests/SwiftStruct.js | 8 + .../BridgeJSLinkTests/SwiftStructImports.js | 8 + .../SwiftTypedClosureAccess.js | 8 + .../__Snapshots__/BridgeJSLinkTests/Throws.js | 8 + .../BridgeJSLinkTests/UnsafePointer.js | 8 + .../VoidParameterVoidReturn.js | 8 + Plugins/PackageToJS/Templates/instantiate.js | 1 + .../JavaScriptKit/BridgeJSIntrinsics.swift | 140 +++- 55 files changed, 1183 insertions(+), 361 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index aed27437b..03dfa87a2 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -347,6 +347,7 @@ public struct BridgeJSLink { "let \(JSGlueVariableScope.reservedF32Stack) = [];", "let \(JSGlueVariableScope.reservedF64Stack) = [];", "let \(JSGlueVariableScope.reservedPointerStack) = [];", + "let \(JSGlueVariableScope.reservedTaStack) = [];", "const \(JSGlueVariableScope.reservedEnumHelpers) = {};", "const \(JSGlueVariableScope.reservedStructHelpers) = {};", "", @@ -489,6 +490,21 @@ public struct BridgeJSLink { printer.write("return \(JSGlueVariableScope.reservedI64Stack).pop();") } printer.write("}") + // Typed array constructors indexed by kind (must match _BridgedNumericArrayKind) + printer.write( + "const taCtors = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array];" + ) + printer.write("bjs[\"swift_js_push_typed_array\"] = function(kind, ptr, count) {") + printer.indent { + printer.write("const Ctor = taCtors[kind];") + printer.write("const byteLen = count * Ctor.BYTES_PER_ELEMENT;") + // slice() copies the bytes into a new ArrayBuffer that is properly aligned + printer.write( + "const copy = \(JSGlueVariableScope.reservedMemory).buffer.slice(ptr, ptr + byteLen);" + ) + printer.write("\(JSGlueVariableScope.reservedTaStack).push(Array.from(new Ctor(copy)));") + } + printer.write("}") if !allStructs.isEmpty { for structDef in allStructs { printer.write("bjs[\"swift_js_struct_lower_\(structDef.abiName)\"] = function(objectId) {") diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index accc2a287..51ef16b20 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -34,6 +34,7 @@ final class JSGlueVariableScope { static let reservedStructHelpers = "structHelpers" static let reservedSwiftClosureRegistry = "swiftClosureRegistry" static let reservedMakeSwiftClosure = "makeClosure" + static let reservedTaStack = "taStack" private let intrinsicRegistry: JSIntrinsicRegistry @@ -63,6 +64,7 @@ final class JSGlueVariableScope { reservedStructHelpers, reservedSwiftClosureRegistry, reservedMakeSwiftClosure, + reservedTaStack, ] init(intrinsicRegistry: JSIntrinsicRegistry) { @@ -1896,20 +1898,31 @@ struct IntrinsicJSFragment: Sendable { let (scope, printer) = (context.scope, context.printer) let resultVar = scope.variable("arrayResult") let lenVar = scope.variable("arrayLen") - let iVar = scope.variable("i") printer.write("const \(lenVar) = \(scope.popI32());") - printer.write("const \(resultVar) = [];") - printer.write("for (let \(iVar) = 0; \(iVar) < \(lenVar); \(iVar)++) {") + 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 { - let elementFragment = try stackLiftFragment(elementType: elementType) - let elementResults = try elementFragment.printCode([], context) - if let elementExpr = elementResults.first { - printer.write("\(resultVar).push(\(elementExpr));") + // 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("}") - printer.write("\(resultVar).reverse();") return [resultVar] } ) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index 8359220c9..ad0111929 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -38,6 +38,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -123,6 +124,13 @@ export async function createInstantiator(options, swift) { 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_Point"] = function(objectId) { structHelpers.Point.lower(swift.memory.getObject(objectId)); } @@ -250,12 +258,17 @@ export async function createInstantiator(options, swift) { TestModule["bjs_importProcessNumbers"] = function bjs_importProcessNumbers() { try { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); + 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(); } - arrayResult.reverse(); imports.importProcessNumbers(arrayResult); } catch (error) { setException(error); @@ -275,12 +288,17 @@ export async function createInstantiator(options, swift) { TestModule["bjs_importTransformNumbers"] = function bjs_importTransformNumbers() { try { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); + 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(); } - arrayResult.reverse(); let ret = imports.importTransformNumbers(arrayResult); for (const elem of ret) { f64Stack.push(elem); @@ -293,12 +311,17 @@ export async function createInstantiator(options, swift) { TestModule["bjs_importProcessStrings"] = function bjs_importProcessStrings() { try { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); + 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(); } - arrayResult.reverse(); let ret = imports.importProcessStrings(arrayResult); for (const elem of ret) { const bytes = textEncoder.encode(elem); @@ -314,12 +337,17 @@ export async function createInstantiator(options, swift) { TestModule["bjs_importProcessBooleans"] = function bjs_importProcessBooleans() { try { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); + 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(); } - arrayResult.reverse(); let ret = imports.importProcessBooleans(arrayResult); for (const elem of ret) { i32Stack.push(elem ? 1 : 0); @@ -423,23 +451,33 @@ export async function createInstantiator(options, swift) { get numbers() { instance.exports.bjs_MultiArrayContainer_numbers_get(this.pointer); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); return arrayResult; } get strings() { instance.exports.bjs_MultiArrayContainer_strings_get(this.pointer); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); + 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(); } - arrayResult.reverse(); return arrayResult; } } @@ -456,12 +494,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processIntArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); return arrayResult; }, processStringArray: function bjs_processStringArray(values) { @@ -474,12 +517,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processStringArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); + 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(); } - arrayResult.reverse(); return arrayResult; }, processDoubleArray: function bjs_processDoubleArray(values) { @@ -489,12 +537,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processDoubleArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); + 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(); } - arrayResult.reverse(); return arrayResult; }, processBoolArray: function bjs_processBoolArray(values) { @@ -504,12 +557,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processBoolArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); + 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(); } - arrayResult.reverse(); return arrayResult; }, processPointArray: function bjs_processPointArray(points) { @@ -519,12 +577,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(points.length); instance.exports.bjs_processPointArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const struct = structHelpers.Point.lift(); - arrayResult.push(struct); + 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(); } - arrayResult.reverse(); return arrayResult; }, processDirectionArray: function bjs_processDirectionArray(directions) { @@ -534,12 +597,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(directions.length); instance.exports.bjs_processDirectionArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const caseId = i32Stack.pop(); - arrayResult.push(caseId); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const caseId = i32Stack.pop(); + arrayResult.push(caseId); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processStatusArray: function bjs_processStatusArray(statuses) { @@ -549,12 +617,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(statuses.length); instance.exports.bjs_processStatusArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const rawValue = i32Stack.pop(); - arrayResult.push(rawValue); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const rawValue = i32Stack.pop(); + arrayResult.push(rawValue); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, sumIntArray: function bjs_sumIntArray(values) { @@ -583,12 +656,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processUnsafeRawPointerArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const pointer = ptrStack.pop(); - arrayResult.push(pointer); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const pointer = ptrStack.pop(); + arrayResult.push(pointer); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processUnsafeMutableRawPointerArray: function bjs_processUnsafeMutableRawPointerArray(values) { @@ -598,12 +676,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processUnsafeMutableRawPointerArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const pointer = ptrStack.pop(); - arrayResult.push(pointer); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const pointer = ptrStack.pop(); + arrayResult.push(pointer); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processOpaquePointerArray: function bjs_processOpaquePointerArray(values) { @@ -613,12 +696,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processOpaquePointerArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const pointer = ptrStack.pop(); - arrayResult.push(pointer); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const pointer = ptrStack.pop(); + arrayResult.push(pointer); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processOptionalIntArray: function bjs_processOptionalIntArray(values) { @@ -632,19 +720,24 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processOptionalIntArray(); const arrayLen = i32Stack.pop(); - const 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; + 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.push(optValue); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processOptionalStringArray: function bjs_processOptionalStringArray(values) { @@ -661,19 +754,24 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processOptionalStringArray(); const arrayLen = i32Stack.pop(); - const 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; + 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.push(optValue); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processOptionalArray: function bjs_processOptionalArray(values) { @@ -690,12 +788,17 @@ export async function createInstantiator(options, swift) { let optResult; if (isSome1) { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); optResult = arrayResult; } else { optResult = null; @@ -713,19 +816,24 @@ export async function createInstantiator(options, swift) { i32Stack.push(points.length); instance.exports.bjs_processOptionalPointArray(); const arrayLen = i32Stack.pop(); - const 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; + 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.push(optValue); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processOptionalDirectionArray: function bjs_processOptionalDirectionArray(directions) { @@ -739,19 +847,24 @@ export async function createInstantiator(options, swift) { i32Stack.push(directions.length); instance.exports.bjs_processOptionalDirectionArray(); const arrayLen = i32Stack.pop(); - const 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; + 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.push(optValue); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processOptionalStatusArray: function bjs_processOptionalStatusArray(statuses) { @@ -765,19 +878,24 @@ export async function createInstantiator(options, swift) { i32Stack.push(statuses.length); instance.exports.bjs_processOptionalStatusArray(); const arrayLen = i32Stack.pop(); - const 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; + 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.push(optValue); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processNestedIntArray: function bjs_processNestedIntArray(values) { @@ -790,18 +908,28 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processNestedIntArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - const arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const int = i32Stack.pop(); - arrayResult1.push(int); + 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); } - arrayResult1.reverse(); - arrayResult.push(arrayResult1); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processNestedStringArray: function bjs_processNestedStringArray(values) { @@ -817,18 +945,28 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_processNestedStringArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - const arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const string = strStack.pop(); - arrayResult1.push(string); + 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); } - arrayResult1.reverse(); - arrayResult.push(arrayResult1); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processNestedPointArray: function bjs_processNestedPointArray(points) { @@ -841,18 +979,28 @@ export async function createInstantiator(options, swift) { i32Stack.push(points.length); instance.exports.bjs_processNestedPointArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - const arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const struct = structHelpers.Point.lift(); - arrayResult1.push(struct); + 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); } - arrayResult1.reverse(); - arrayResult.push(arrayResult1); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processItemArray: function bjs_processItemArray(items) { @@ -862,13 +1010,18 @@ export async function createInstantiator(options, swift) { i32Stack.push(items.length); instance.exports.bjs_processItemArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - arrayResult.push(obj); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const ptr = ptrStack.pop(); + const obj = Item.__construct(ptr); + arrayResult.push(obj); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processNestedItemArray: function bjs_processNestedItemArray(items) { @@ -881,19 +1034,29 @@ export async function createInstantiator(options, swift) { i32Stack.push(items.length); instance.exports.bjs_processNestedItemArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - const arrayResult1 = []; - for (let i1 = 0; i1 < arrayLen1; i1++) { - const ptr = ptrStack.pop(); - const obj = Item.__construct(ptr); - arrayResult1.push(obj); + 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); } - arrayResult1.reverse(); - arrayResult.push(arrayResult1); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processJSObjectArray: function bjs_processJSObjectArray(objects) { @@ -904,14 +1067,19 @@ export async function createInstantiator(options, swift) { i32Stack.push(objects.length); instance.exports.bjs_processJSObjectArray(); const arrayLen = i32Stack.pop(); - const 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(); + 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(); + } return arrayResult; }, processOptionalJSObjectArray: function bjs_processOptionalJSObjectArray(objects) { @@ -926,21 +1094,26 @@ export async function createInstantiator(options, swift) { i32Stack.push(objects.length); instance.exports.bjs_processOptionalJSObjectArray(); const arrayLen = i32Stack.pop(); - const 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; + 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.push(optValue); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, processNestedJSObjectArray: function bjs_processNestedJSObjectArray(objects) { @@ -954,20 +1127,30 @@ export async function createInstantiator(options, swift) { i32Stack.push(objects.length); instance.exports.bjs_processNestedJSObjectArray(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const arrayLen1 = i32Stack.pop(); - const 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); + 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); } - arrayResult1.reverse(); - arrayResult.push(arrayResult1); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, multiArrayParams: function bjs_multiArrayParams(nums, strs) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index bf368738e..a4c42674e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js index 89ab29827..fd27e3d67 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -213,6 +214,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js index 7fd6a0d6b..6b6698377 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -212,6 +213,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index cafd250b0..8f8463bf0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -31,6 +31,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -140,6 +141,13 @@ export async function createInstantiator(options, swift) { 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_Config"] = function(objectId) { structHelpers.Config.lower(swift.memory.getObject(objectId)); } @@ -550,12 +558,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_testIntArrayDefault(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); return arrayResult; }, testStringArrayDefault: function bjs_testStringArrayDefault(names = ["a", "b", "c"]) { @@ -568,12 +581,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(names.length); instance.exports.bjs_testStringArrayDefault(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); + 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(); } - arrayResult.reverse(); return arrayResult; }, testDoubleArrayDefault: function bjs_testDoubleArrayDefault(values = [1.5, 2.5, 3.5]) { @@ -583,12 +601,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_testDoubleArrayDefault(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const f64 = f64Stack.pop(); - arrayResult.push(f64); + 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(); } - arrayResult.reverse(); return arrayResult; }, testBoolArrayDefault: function bjs_testBoolArrayDefault(flags = [true, false, true]) { @@ -598,12 +621,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(flags.length); instance.exports.bjs_testBoolArrayDefault(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const bool = i32Stack.pop() !== 0; - arrayResult.push(bool); + 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(); } - arrayResult.reverse(); return arrayResult; }, testEmptyArrayDefault: function bjs_testEmptyArrayDefault(items = []) { @@ -613,12 +641,17 @@ export async function createInstantiator(options, swift) { i32Stack.push(items.length); instance.exports.bjs_testEmptyArrayDefault(); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); return arrayResult; }, testMixedWithArrayDefault: function bjs_testMixedWithArrayDefault(name = "test", values = [10, 20, 30], enabled = true) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 920017972..d040df41c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -139,6 +140,13 @@ export async function createInstantiator(options, swift) { 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_Counters"] = function(objectId) { structHelpers.Counters.lower(swift.memory.getObject(objectId)); } @@ -420,12 +428,17 @@ export async function createInstantiator(options, swift) { const dictResult = {}; for (let i = 0; i < dictLen; i++) { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i1 = 0; i1 < arrayLen; i1++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); const string = strStack.pop(); dictResult[string] = arrayResult; } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 3d2230c6c..23819a6e8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -106,6 +106,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -623,12 +624,17 @@ export async function createInstantiator(options, swift) { } case AllTypesResultValues.Tag.ArrayPayload: { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); return { tag: AllTypesResultValues.Tag.ArrayPayload, param0: arrayResult }; } case AllTypesResultValues.Tag.Empty: return { tag: AllTypesResultValues.Tag.Empty }; @@ -748,12 +754,17 @@ export async function createInstantiator(options, swift) { optValue = null; } else { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); optValue = arrayResult; } return { tag: OptionalAllTypesResultValues.Tag.OptArray, param0: optValue }; @@ -831,6 +842,13 @@ export async function createInstantiator(options, swift) { 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_Point"] = function(objectId) { structHelpers.Point.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index fe94c046f..5272717ec 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -49,6 +49,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -122,6 +123,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index 10fe31f64..ecf121aa4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -69,6 +69,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -142,6 +143,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index a6aeee4b0..247a11e54 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -50,6 +50,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -123,6 +124,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 7e5334811..b004e3b74 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -100,6 +100,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -174,6 +175,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js index 53ddd7301..4aa424d68 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js index 346b74eac..f5895589d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js index f74095374..77e8002f8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js index c2490c0ea..db876ff02 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js index d970c5d77..ca958e564 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js index d970c5d77..ca958e564 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 06cf6550e..613d4a10b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -193,12 +201,17 @@ export async function createInstantiator(options, swift) { TestModule["bjs_roundtrip"] = function bjs_roundtrip() { try { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const int = i32Stack.pop(); - arrayResult.push(int); + 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(); } - arrayResult.reverse(); let ret = imports.roundtrip(arrayResult); for (const elem of ret) { i32Stack.push((elem | 0)); @@ -211,12 +224,17 @@ export async function createInstantiator(options, swift) { TestModule["bjs_logStrings"] = function bjs_logStrings() { try { const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const string = strStack.pop(); - arrayResult.push(string); + 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(); } - arrayResult.reverse(); imports.logStrings(arrayResult); } catch (error) { setException(error); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index c469fcb58..ab4b4b34d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -137,6 +138,13 @@ export async function createInstantiator(options, swift) { 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_FooContainer"] = function(objectId) { structHelpers.FooContainer.lower(swift.memory.getObject(objectId)); } @@ -281,14 +289,19 @@ export async function createInstantiator(options, swift) { i32Stack.push(foos.length); instance.exports.bjs_processFooArray(); const arrayLen = i32Stack.pop(); - const 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); + 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(); } - arrayResult.reverse(); return arrayResult; }, processOptionalFooArray: function bjs_processOptionalFooArray(foos) { @@ -303,21 +316,26 @@ export async function createInstantiator(options, swift) { i32Stack.push(foos.length); instance.exports.bjs_processOptionalFooArray(); const arrayLen = i32Stack.pop(); - const 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; + 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.push(optValue); + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; }, roundtripFooContainer: function bjs_roundtripFooContainer(container) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js index 952197c2a..59c8be11d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js index 88a5adb38..f3293ae52 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js index 10fafb7a0..ef666149b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js index ee51d4a28..b12640234 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 0258b63b6..71e66827e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -188,6 +189,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -302,15 +310,20 @@ export async function createInstantiator(options, swift) { TestModule["bjs_jsEchoJSValueArray"] = function bjs_jsEchoJSValueArray() { try { const arrayLen = i32Stack.pop(); - const 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); + 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(); } - arrayResult.reverse(); let ret = imports.jsEchoJSValueArray(arrayResult); for (const elem of ret) { const [elemKind, elemPayload1, elemPayload2] = __bjs_jsValueLower(elem); @@ -553,15 +566,20 @@ export async function createInstantiator(options, swift) { i32Stack.push(values.length); instance.exports.bjs_roundTripJSValueArray(); const arrayLen = i32Stack.pop(); - const 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); + 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(); } - arrayResult.reverse(); return arrayResult; }, roundTripOptionalJSValueArray: function bjs_roundTripOptionalJSValueArray(values) { @@ -581,15 +599,20 @@ export async function createInstantiator(options, swift) { let optResult; if (isSome1) { const arrayLen = i32Stack.pop(); - const 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); + 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(); } - arrayResult.reverse(); optResult = arrayResult; } else { optResult = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index 195eef468..6c3ddb555 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index ca54493f6..70f1575b4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index 3551caab2..16ec9433c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index a63df44be..d698857d3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -341,13 +349,18 @@ export async function createInstantiator(options, swift) { getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const ptr = ptrStack.pop(); - const obj = Greeter.__construct(ptr); - arrayResult.push(obj); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const ptr = ptrStack.pop(); + const obj = Greeter.__construct(ptr); + arrayResult.push(obj); + } + arrayResult.reverse(); } - arrayResult.reverse(); 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 32a325bda..92b8f5dae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -341,13 +349,18 @@ export async function createInstantiator(options, swift) { getItems() { instance.exports.bjs_Collections_Container_getItems(this.pointer); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const ptr = ptrStack.pop(); - const obj = Greeter.__construct(ptr); - arrayResult.push(obj); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const ptr = ptrStack.pop(); + const obj = Greeter.__construct(ptr); + arrayResult.push(obj); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; } addItem(item) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index f276877e0..33b4e60c1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -123,6 +124,13 @@ export async function createInstantiator(options, swift) { 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_User_Stats"] = function(objectId) { structHelpers.User_Stats.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 1d585ce0b..f376c1b24 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js index 490f2b4e2..97c1a44fe 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js index bec07b959..a140ea232 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index 7f840708e..b8116a32f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 9fb9b172b..d992bf75d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -49,6 +49,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -155,6 +156,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -722,14 +730,19 @@ export async function createInstantiator(options, swift) { get delegates() { instance.exports.bjs_DelegateManager_delegates_get(this.pointer); const arrayLen = i32Stack.pop(); - const arrayResult = []; - for (let i = 0; i < arrayLen; i++) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - arrayResult.push(obj); + let arrayResult; + if (arrayLen === -1) { + arrayResult = taStack.pop(); + } else { + arrayResult = []; + for (let i = 0; i < arrayLen; i++) { + const objId = i32Stack.pop(); + const obj = swift.memory.getObject(objId); + swift.memory.release(objId); + arrayResult.push(obj); + } + arrayResult.reverse(); } - arrayResult.reverse(); return arrayResult; } set delegates(value) { @@ -783,14 +796,19 @@ export async function createInstantiator(options, swift) { i32Stack.push(delegates.length); instance.exports.bjs_processDelegates(); const arrayLen = i32Stack.pop(); - const 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); + 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(); } - arrayResult.reverse(); return arrayResult; }, processDelegatesByName: function bjs_processDelegatesByName(delegates) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js index aefdb5679..89f84d29a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -123,6 +124,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index ef685b8a4..32a739587 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -36,6 +36,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -142,6 +143,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 1fd066076..16cf2881f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -36,6 +36,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -142,6 +143,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 5800fcb56..b616665ca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -30,6 +30,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -103,6 +104,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index b81255810..f6e1fdbce 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -30,6 +30,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -103,6 +104,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js index 033f08cd2..885c0980f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js index 8187b9e92..aab8b67fe 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 9ee57d692..88f04efe9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 0b4ca3dcc..c82bc5b8d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -55,6 +55,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -226,6 +227,13 @@ export async function createInstantiator(options, swift) { 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_Animal"] = function(objectId) { structHelpers.Animal.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index d9df868ec..cffbdcf67 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -124,6 +125,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index abfb24d48..d55d5c095 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -30,6 +30,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -311,6 +312,13 @@ export async function createInstantiator(options, swift) { 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_DataPoint"] = function(objectId) { structHelpers.DataPoint.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index d4f1160f3..0197aefe8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -110,6 +111,13 @@ export async function createInstantiator(options, swift) { 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_Point"] = function(objectId) { structHelpers.Point.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js index 4e0fd8341..2b51ebd3b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -123,6 +124,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js index b2c381a03..9c41c3061 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -98,6 +99,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index ef81ef69e..97a00c278 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -115,6 +116,13 @@ export async function createInstantiator(options, swift) { 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_PointerFields"] = function(objectId) { structHelpers.PointerFields.lower(swift.memory.getObject(objectId)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js index 97948b286..2951ef5f8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js @@ -25,6 +25,7 @@ export async function createInstantiator(options, swift) { let f32Stack = []; let f64Stack = []; let ptrStack = []; + let taStack = []; const enumHelpers = {}; const structHelpers = {}; @@ -99,6 +100,13 @@ export async function createInstantiator(options, swift) { 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_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 3dda6b28e..88e322538 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -68,6 +68,7 @@ async function createInstantiator(options, swift) { swift_js_push_i64: unexpectedBjsCall, swift_js_pop_i64: unexpectedBjsCall, swift_js_closure_unregister: unexpectedBjsCall, + swift_js_push_typed_array: unexpectedBjsCall, }; }, /** @param {WebAssembly.Instance} instance */ diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 86a1aaf3f..ff586b45b 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -154,6 +154,11 @@ public protocol _BridgedSwiftStackType { static func bridgeJSStackPopAsOptional() -> StackLiftResult? /// Specialization point for pushing an `Optional` static func bridgeJSStackPushAsOptional(_ value: consuming Self?) + + /// Specialization point for popping an `Array` from the bridge stack + static func bridgeJSStackPopAsArray() -> [StackLiftResult] + /// Specialization point for pushing an `Array` onto the bridge stack + static func bridgeJSStackPushAsArray(_ value: consuming [Self]) } extension _BridgedSwiftStackType { @@ -178,6 +183,25 @@ extension _BridgedSwiftStackType { _swift_js_push_i32(1) } } + + public static func bridgeJSStackPopAsArray() -> [StackLiftResult] { + let count = Int(_swift_js_pop_i32()) + var result: [StackLiftResult] = [] + result.reserveCapacity(count) + for _ in 0.. Float64 { _swift_js_pop_f64_extern() } +// MARK: Typed array bulk push extern + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_push_typed_array") +private func _swift_js_push_typed_array_extern(_ kind: Int32, _ ptr: UnsafeRawPointer, _ count: Int32) +#else +private func _swift_js_push_typed_array_extern(_ kind: Int32, _ ptr: UnsafeRawPointer, _ count: Int32) { + _onlyAvailableOnWasm() +} +#endif + +/// Pushes a typed array onto the JS typed-array stack via bulk copy. +@_spi(BridgeJS) @inline(never) public func _swift_js_push_typed_array( + _ kind: Int32, + _ ptr: UnsafeRawPointer, + _ count: Int32 +) { + _swift_js_push_typed_array_extern(kind, ptr, count) +} + +/// Numeric TypedArray kind identifiers (must match the JS `taCtors` table in BridgeJSLink). +public enum _BridgedNumericArrayKind: Int32 { + case int8 = 0 + case uint8 = 1 + case int16 = 2 + case uint16 = 3 + case int32 = 4 + case uint32 = 5 + case float32 = 6 + case float64 = 7 +} + +// MARK: - Numeric typed-array bulk push + +/// Numeric types that opt into bulk typed-array push. +public protocol _BridgedNumericArray: _BridgedSwiftStackType where StackLiftResult == Self { + static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { get } +} + +extension _BridgedNumericArray { + @_spi(BridgeJS) + public static func bridgeJSStackPushAsArray(_ value: consuming [Self]) { + value.withUnsafeBufferPointer { buffer in + guard let base = buffer.baseAddress else { + _swift_js_push_i32(0) + return + } + _swift_js_push_typed_array( + Self._bridgedNumericArrayKind.rawValue, + UnsafeRawPointer(base), + Int32(buffer.count) + ) + // -1 discriminator tells JS arrayLift to pop from the typed-array stack + _swift_js_push_i32(-1) + } + } +} + +extension Int8: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .int8 } +} +extension UInt8: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .uint8 } +} +extension Int16: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .int16 } +} +extension UInt16: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .uint16 } +} +extension Int32: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .int32 } +} +extension UInt32: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .uint32 } +} +extension Float: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .float32 } +} +extension Double: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { .float64 } +} +extension Int: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { + #if _pointerBitWidth(_32) + return .int32 + #else + return .int32 + #endif + } +} +extension UInt: _BridgedNumericArray { + public static var _bridgedNumericArrayKind: _BridgedNumericArrayKind { + #if _pointerBitWidth(_32) + return .uint32 + #else + return .uint32 + #endif + } +} + // MARK: Wasm externs used by type lowering/lifting #if arch(wasm32) @@ -1973,22 +2098,11 @@ extension Array: _BridgedSwiftStackType where Element: _BridgedSwiftStackType, E public typealias StackLiftResult = [Element] @_spi(BridgeJS) public static func bridgeJSStackPop() -> [Element] { - let count = Int(_swift_js_pop_i32()) - var result: [Element] = [] - result.reserveCapacity(count) - for _ in 0.. [Element] { From d1e0f95a1ddee38a699889ba5ceb605e0ed4a6f8 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 2 Jun 2026 01:51:05 +0900 Subject: [PATCH 54/68] Change Data.construct(from uint8Array:) return type from Data? to Data (#752) Make Data typed-array constructor non-optional --- Sources/JavaScriptFoundationCompat/Data+JSValue.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JavaScriptFoundationCompat/Data+JSValue.swift b/Sources/JavaScriptFoundationCompat/Data+JSValue.swift index 6e74ba266..c4408d8cf 100644 --- a/Sources/JavaScriptFoundationCompat/Data+JSValue.swift +++ b/Sources/JavaScriptFoundationCompat/Data+JSValue.swift @@ -22,7 +22,7 @@ extension Data: ConvertibleToJSValue, ConstructibleFromJSValue { public var jsValue: JSValue { jsTypedArray.jsValue } /// Construct a Data from a JSTypedArray. - public static func construct(from uint8Array: JSTypedArray) -> Data? { + public static func construct(from uint8Array: JSTypedArray) -> Data { // First, allocate the data storage var data = Data(count: uint8Array.lengthInBytes) // Then, copy the byte contents into the Data buffer From 2941cd28fcda99a306188c19eedd8899ec175112 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 8 Jun 2026 14:08:54 +0200 Subject: [PATCH 55/68] BridgeJS: Support optional @JS struct in imported function signatures Optional @JS structs could not be used as parameters or return values of imported (@JSFunction) signatures: the generator lowered Optional using the non-optional object-id ABI ([isSome, objectId] / a single Int32 return), for which no Optional lowering exists, so the generated thunk did not compile. Bridge optional @JS structs through the stack ABI instead - an isSome discriminator plus the struct fields - exactly like optional arrays and dictionaries. Structs already conform to the stack-based bridging protocols, so the existing _BridgedAsOptional/stack runtime extensions and the JS link's stack handling already support this; only the import-side lowering/lifting in the code generator needed to change. Adds a jsRoundTripOptionalPoint runtime round-trip (some + none) and a SwiftStructImports codegen snapshot. --- .../Sources/BridgeJSCore/ImportTS.swift | 10 +++++- .../MacroSwift/SwiftStructImports.swift | 2 ++ .../SwiftStructImports.json | 34 +++++++++++++++++++ .../SwiftStructImports.swift | 21 ++++++++++++ .../BridgeJSLinkTests/SwiftStructImports.d.ts | 1 + .../BridgeJSLinkTests/SwiftStructImports.js | 19 +++++++++++ .../Generated/BridgeJS.swift | 21 ++++++++++++ .../Generated/JavaScript/BridgeJS.json | 34 +++++++++++++++++++ .../BridgeJSRuntimeTests/ImportAPITests.swift | 7 ++++ .../ImportStructAPIs.swift | 2 ++ Tests/prelude.mjs | 1 + 11 files changed, 151 insertions(+), 1 deletion(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index d491c4058..8ce91b998 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -957,6 +957,10 @@ extension BridgeType { } case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as parameters") + case .nullable(.swiftStruct, _) where context == .importTS: + // Optional `@JS struct`s bridge through the stack (isSome discriminator + fields), + // like optional arrays/dictionaries, rather than the non-optional object-id ABI. + return LoweringParameterInfo(loweredParameters: [("isSome", .i32)]) case .nullable(let wrappedType, _): let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) var params = [("isSome", WasmCoreType.i32)] @@ -1034,10 +1038,14 @@ extension BridgeType { case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as return values") case .nullable(let wrappedType, _): - // jsObject uses stack ABI for optionals — returns void, value goes through stacks + // jsObject and `@JS struct` use the stack ABI for optionals — the thunk returns + // void and the value (plus isSome discriminator) flows through the stacks. if case .jsObject = wrappedType { return LiftingReturnInfo(valueToLift: nil) } + if case .swiftStruct = wrappedType, context == .importTS { + return LiftingReturnInfo(valueToLift: nil) + } let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) case .array, .dictionary: diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStructImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStructImports.swift index b00fd768a..a1eed686a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStructImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStructImports.swift @@ -5,3 +5,5 @@ struct Point { } @JSFunction func translate(_ point: Point, dx: Int, dy: Int) throws(JSException) -> Point + +@JSFunction func roundTripOptional(_ point: Point?) throws(JSException) -> Point? diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json index fc59471bb..a9b0d22bf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.json @@ -100,6 +100,40 @@ "_0" : "Point" } } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "roundTripOptional", + "parameters" : [ + { + "name" : "point", + "type" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Point" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Point" + } + }, + "_1" : "null" + } + } } ], "types" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift index fe79f786c..cec50ffca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift @@ -67,4 +67,25 @@ func _$translate(_ point: Point, _ dx: Int, _ dy: Int) throws(JSException) -> Po throw error } return Point.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_roundTripOptional") +fileprivate func bjs_roundTripOptional_extern(_ point: Int32) -> Void +#else +fileprivate func bjs_roundTripOptional_extern(_ point: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_roundTripOptional(_ point: Int32) -> Void { + return bjs_roundTripOptional_extern(point) +} + +func _$roundTripOptional(_ point: Optional) throws(JSException) -> Optional { + let pointIsSome = point.bridgeJSLowerParameter() + bjs_roundTripOptional(pointIsSome) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn() } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts index 3677f1e44..e97b50fda 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.d.ts @@ -12,6 +12,7 @@ export type Exports = { } export type Imports = { translate(point: Point, dx: number, dy: number): Point; + roundTripOptional(point: Point | null): Point | null; } export function createInstantiator(options: { imports: Imports; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index 0197aefe8..17bf086ff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -226,6 +226,25 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_roundTripOptional"] = function bjs_roundTripOptional(point) { + try { + let optResult; + if (point) { + const struct = structHelpers.Point.lift(); + optResult = struct; + } else { + optResult = null; + } + let ret = imports.roundTripOptional(optResult); + const isSome = ret != null; + if (isSome) { + structHelpers.Point.lower(ret); + } + i32Stack.push(isSome ? 1 : 0); + } catch (error) { + setException(error); + } + } }, setInstance: (i) => { instance = i; diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 3fa4eb9d5..4a94431f2 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -13279,6 +13279,27 @@ func _$jsTranslatePoint(_ point: Point, _ dx: Int, _ dy: Int) throws(JSException return Point.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalPoint") +fileprivate func bjs_jsRoundTripOptionalPoint_extern(_ point: Int32) -> Void +#else +fileprivate func bjs_jsRoundTripOptionalPoint_extern(_ point: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsRoundTripOptionalPoint(_ point: Int32) -> Void { + return bjs_jsRoundTripOptionalPoint_extern(point) +} + +func _$jsRoundTripOptionalPoint(_ point: Optional) throws(JSException) -> Optional { + let pointIsSome = point.bridgeJSLowerParameter() + bjs_jsRoundTripOptionalPoint(pointIsSome) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn() +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_IntegerTypesSupportImports_jsRoundTripInt_static") fileprivate func bjs_IntegerTypesSupportImports_jsRoundTripInt_static_extern(_ v: Int32) -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 94142f470..9ea12bde7 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -19745,6 +19745,40 @@ "_0" : "Point" } } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripOptionalPoint", + "parameters" : [ + { + "name" : "point", + "type" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Point" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "Point" + } + }, + "_1" : "null" + } + } } ], "types" : [ diff --git a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift index 8f02af2ef..38ff2a205 100644 --- a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift @@ -59,6 +59,13 @@ class ImportAPITests: XCTestCase { } } + func testRoundTripOptionalStruct() throws { + let p = try jsRoundTripOptionalPoint(Point(x: 3, y: 4)) + XCTAssertEqual(p?.x, 3) + XCTAssertEqual(p?.y, 4) + XCTAssertNil(try jsRoundTripOptionalPoint(nil)) + } + func ensureThrows(_ f: (Bool) throws(JSException) -> T) throws { do { _ = try f(true) diff --git a/Tests/BridgeJSRuntimeTests/ImportStructAPIs.swift b/Tests/BridgeJSRuntimeTests/ImportStructAPIs.swift index 41929772e..f981a5e01 100644 --- a/Tests/BridgeJSRuntimeTests/ImportStructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/ImportStructAPIs.swift @@ -7,3 +7,5 @@ struct Point { } @JSFunction func jsTranslatePoint(_ point: Point, dx: Int, dy: Int) throws(JSException) -> Point + +@JSFunction func jsRoundTripOptionalPoint(_ point: Point?) throws(JSException) -> Point? diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 2c922dbe2..f9e2f7727 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -141,6 +141,7 @@ export async function setupOptions(options, context) { jsTranslatePoint: (point, dx, dy) => { return { x: (point.x | 0) + (dx | 0), y: (point.y | 0) + (dy | 0) }; }, + jsRoundTripOptionalPoint: (point) => point, roundTripArrayMembers: (value) => { return value; }, From 7d3faa0db7f370da2f01d674270f5ce9d3ef38ba Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 8 Jun 2026 15:29:03 +0200 Subject: [PATCH 56/68] BridgeJS: Support case enums as imported function parameters and returns Case enums (enums without raw values or associated values) already bridged across the export boundary as their Int32 tag, but the TypeScript import path rejected them with "Enum types are not yet supported in TypeScript imports". The JS glue already round-trips the tag in both directions, so enable case enums as imported (@JSFunction) parameters and return values by lowering and lifting that Int32 tag in the import context, matching the export side. Adds a CaseEnumImports round-trip test and an EnumCaseImport codegen snapshot. --- .../Sources/BridgeJSCore/ImportTS.swift | 14 +- .../Inputs/MacroSwift/EnumCaseImport.swift | 12 + .../BridgeJSCodegenTests/EnumCaseImport.json | 139 ++++++++++ .../BridgeJSCodegenTests/EnumCaseImport.swift | 97 +++++++ .../BridgeJSLinkTests/EnumCaseImport.d.ts | 33 +++ .../BridgeJSLinkTests/EnumCaseImport.js | 251 ++++++++++++++++++ .../Generated/BridgeJS.swift | 60 +++++ .../Generated/JavaScript/BridgeJS.json | 63 +++++ .../BridgeJSRuntimeTests/ImportAPITests.swift | 14 + Tests/prelude.mjs | 3 + 10 files changed, 674 insertions(+), 12 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumCaseImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 8ce91b998..02c623918 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -928,12 +928,7 @@ extension BridgeType { return LoweringParameterInfo(loweredParameters: [("objectId", .i32)]) } case .caseEnum: - switch context { - case .importTS: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .exportSwift: - return LoweringParameterInfo(loweredParameters: [("value", .i32)]) - } + return LoweringParameterInfo(loweredParameters: [("value", .i32)]) case .rawValueEnum(_, let rawType): if rawType == .string { return .string @@ -1011,12 +1006,7 @@ extension BridgeType { return LiftingReturnInfo(valueToLift: .i32) } case .caseEnum: - switch context { - case .importTS: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .exportSwift: - return LiftingReturnInfo(valueToLift: .i32) - } + return LiftingReturnInfo(valueToLift: .i32) case .rawValueEnum(_, let rawType): let wasmType = rawType.wasmCoreType ?? .i32 return LiftingReturnInfo(valueToLift: wasmType) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumCaseImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumCaseImport.swift new file mode 100644 index 000000000..a6477be95 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumCaseImport.swift @@ -0,0 +1,12 @@ +@JS enum Signal { + case start + case stop +} + +// Case enums (no raw value) bridge as their `Int32` tag as imported-function +// parameters and return values. +@JSClass struct SignalControls { + @JSFunction func send(_ signal: Signal) throws(JSException) + @JSFunction func current() throws(JSException) -> Signal + @JSFunction static func roundTrip(_ signal: Signal) throws(JSException) -> Signal +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.json new file mode 100644 index 000000000..71bf8679e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.json @@ -0,0 +1,139 @@ +{ + "exported" : { + "classes" : [ + + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "start" + }, + { + "associatedValues" : [ + + ], + "name" : "stop" + } + ], + "emitStyle" : "const", + "name" : "Signal", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Signal", + "tsFullPath" : "Signal" + } + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "imported" : { + "children" : [ + { + "functions" : [ + + ], + "types" : [ + { + "accessLevel" : "internal", + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "send", + "parameters" : [ + { + "name" : "signal", + "type" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "current", + "parameters" : [ + + ], + "returnType" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ], + "name" : "SignalControls", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "roundTrip", + "parameters" : [ + { + "name" : "signal", + "type" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ], + "returnType" : { + "caseEnum" : { + "_0" : "Signal" + } + } + } + ] + } + ] + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ 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 new file mode 100644 index 000000000..3487ad425 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumCaseImport.swift @@ -0,0 +1,97 @@ +extension Signal: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Signal { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Signal { + return Signal(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .start + case 1: + self = .stop + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .start: + return 0 + case .stop: + return 1 + } + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_SignalControls_roundTrip_static") +fileprivate func bjs_SignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 +#else +fileprivate func bjs_SignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_SignalControls_roundTrip_static(_ signal: Int32) -> Int32 { + return bjs_SignalControls_roundTrip_static_extern(signal) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_SignalControls_send") +fileprivate func bjs_SignalControls_send_extern(_ self: Int32, _ signal: Int32) -> Void +#else +fileprivate func bjs_SignalControls_send_extern(_ self: Int32, _ signal: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_SignalControls_send(_ self: Int32, _ signal: Int32) -> Void { + return bjs_SignalControls_send_extern(self, signal) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_SignalControls_current") +fileprivate func bjs_SignalControls_current_extern(_ self: Int32) -> Int32 +#else +fileprivate func bjs_SignalControls_current_extern(_ self: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_SignalControls_current(_ self: Int32) -> Int32 { + return bjs_SignalControls_current_extern(self) +} + +func _$SignalControls_roundTrip(_ signal: Signal) throws(JSException) -> Signal { + let signalValue = signal.bridgeJSLowerParameter() + let ret = bjs_SignalControls_roundTrip_static(signalValue) + if let error = _swift_js_take_exception() { + throw error + } + return Signal.bridgeJSLiftReturn(ret) +} + +func _$SignalControls_send(_ self: JSObject, _ signal: Signal) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let signalValue = signal.bridgeJSLowerParameter() + bjs_SignalControls_send(selfValue, signalValue) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$SignalControls_current(_ self: JSObject) throws(JSException) -> Signal { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_SignalControls_current(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return Signal.bridgeJSLiftReturn(ret) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts new file mode 100644 index 000000000..fe48c9174 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.d.ts @@ -0,0 +1,33 @@ +// 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 SignalValues: { + readonly Start: 0; + readonly Stop: 1; +}; +export type SignalTag = typeof SignalValues[keyof typeof SignalValues]; + +export type SignalObject = typeof SignalValues; + +export interface SignalControls { + send(signal: SignalTag): void; + current(): SignalTag; +} +export type Exports = { + Signal: SignalObject +} +export type Imports = { + SignalControls: { + roundTrip(signal: SignalTag): SignalTag; + } +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => 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 new file mode 100644 index 000000000..e232c7cbb --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js @@ -0,0 +1,251 @@ +// 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 SignalValues = { + Start: 0, + Stop: 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 = {}; + + let _exports = null; + let bjs = null; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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_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) {} + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_SignalControls_roundTrip_static"] = function bjs_SignalControls_roundTrip_static(signal) { + try { + let ret = imports.SignalControls.roundTrip(signal); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_SignalControls_send"] = function bjs_SignalControls_send(self, signal) { + try { + swift.memory.getObject(self).send(signal); + } catch (error) { + setException(error); + } + } + TestModule["bjs_SignalControls_current"] = function bjs_SignalControls_current(self) { + try { + let ret = swift.memory.getObject(self).current(); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + }, + 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const exports = { + Signal: SignalValues, + }; + _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 4a94431f2..e6c2f940b 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -4831,6 +4831,45 @@ public func _bjs_NestedStructGroupB_static_roundtripMetadata() -> Void { #endif } +extension LightColor: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> LightColor { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> LightColor { + return LightColor(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 = .yellow + case 2: + self = .green + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .red: + return 0 + case .yellow: + return 1 + case .green: + return 2 + } + } +} + @_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt") @_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt") public func _bjs_IntegerTypesSupportExports_static_roundTripInt(_ v: Int32) -> Int32 { @@ -13256,6 +13295,27 @@ func _$Animal_getIsCat(_ self: JSObject) throws(JSException) -> Bool { return Bool.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripLightColor") +fileprivate func bjs_jsRoundTripLightColor_extern(_ value: Int32) -> Int32 +#else +fileprivate func bjs_jsRoundTripLightColor_extern(_ value: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsRoundTripLightColor(_ value: Int32) -> Int32 { + return bjs_jsRoundTripLightColor_extern(value) +} + +func _$jsRoundTripLightColor(_ value: LightColor) throws(JSException) -> LightColor { + let valueValue = value.bridgeJSLowerParameter() + let ret = bjs_jsRoundTripLightColor(valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return LightColor.bridgeJSLiftReturn(ret) +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsTranslatePoint") fileprivate func bjs_jsTranslatePoint_extern(_ point: Int32, _ dx: Int32, _ dy: Int32) -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 9ea12bde7..a28843142 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -9254,6 +9254,38 @@ "swiftCallName" : "NestedStructGroupB", "tsFullPath" : "NestedStructGroupB" }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "red" + }, + { + "associatedValues" : [ + + ], + "name" : "yellow" + }, + { + "associatedValues" : [ + + ], + "name" : "green" + } + ], + "emitStyle" : "const", + "name" : "LightColor", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "LightColor", + "tsFullPath" : "LightColor" + }, { "cases" : [ @@ -19698,6 +19730,37 @@ } ] }, + { + "functions" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripLightColor", + "parameters" : [ + { + "name" : "value", + "type" : { + "caseEnum" : { + "_0" : "LightColor" + } + } + } + ], + "returnType" : { + "caseEnum" : { + "_0" : "LightColor" + } + } + } + ], + "types" : [ + + ] + }, { "functions" : [ { diff --git a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift index 38ff2a205..2bb9158b9 100644 --- a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift @@ -1,6 +1,14 @@ import XCTest import JavaScriptKit +@JS enum LightColor { + case red + case yellow + case green +} + +@JSFunction func jsRoundTripLightColor(_ value: LightColor) throws(JSException) -> LightColor + class ImportAPITests: XCTestCase { func testRoundTripVoid() throws { try jsRoundTripVoid() @@ -66,6 +74,12 @@ class ImportAPITests: XCTestCase { XCTAssertNil(try jsRoundTripOptionalPoint(nil)) } + func testRoundTripCaseEnum() throws { + for v in [LightColor.red, .yellow, .green] { + try XCTAssertEqual(jsRoundTripLightColor(v), v) + } + } + func ensureThrows(_ f: (Bool) throws(JSException) -> T) throws { do { _ = try f(true) diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index f9e2f7727..05956d8d3 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -88,6 +88,9 @@ export async function setupOptions(options, context) { "jsRoundTripFeatureFlag": (flag) => { return flag; }, + "jsRoundTripLightColor": (value) => { + return value; + }, "jsEchoJSValue": (v) => { return v; }, From 7aef830177fa58228fa87de89c980cc965abcfa2 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Mon, 8 Jun 2026 17:08:13 +0200 Subject: [PATCH 57/68] BridgeJS: Use a BigInt zero placeholder for Wasm i64 in generated JS A Wasm i64 parameter or return value is represented as a JavaScript BigInt. The generated JS used a plain 0 as the placeholder for the absent case of an optional i64 parameter (isSome ? v : 0) and for the error-path return of an imported thunk, so calling such an export with null (or an imported i64 function throwing) raised "TypeError: Cannot convert 0 to a BigInt". Emit 0n for i64 in both placeholders (jsZeroLiteral and the imported-thunk return placeholder). This was latent because the optional Int64/UInt64 round-trip tests never exercised the none case; add those assertions. --- Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift | 5 ++++- Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift | 5 ++++- .../__Snapshots__/BridgeJSLinkTests/EnumRawType.js | 4 ++-- .../__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js | 4 ++-- .../BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs | 4 ++++ 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 03dfa87a2..ce0ba0cb8 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -3704,7 +3704,10 @@ extension BridgeType { extension WasmCoreType { fileprivate var placeholderValue: String { switch self { - case .i32, .i64, .f32, .f64, .pointer: return "0" + // A Wasm `i64` return is a JavaScript `BigInt`, so the error-path placeholder + // must be a BigInt literal rather than a plain number. + case .i64: return "0n" + case .i32, .f32, .f64, .pointer: return "0" } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 51ef16b20..388d703bd 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -2603,7 +2603,10 @@ fileprivate extension WasmCoreType { var jsZeroLiteral: String { switch self { case .f32, .f64: return "0.0" - case .i32, .i64, .pointer: return "0" + // A Wasm `i64` parameter is passed as a JavaScript `BigInt`, so its zero + // placeholder must be a BigInt literal rather than a plain number. + case .i64: return "0n" + case .i32, .pointer: return "0" } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index b004e3b74..4e4449e06 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -440,7 +440,7 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalFileSize: function bjs_roundTripOptionalFileSize(input) { const isSome = input != null; - instance.exports.bjs_roundTripOptionalFileSize(+isSome, isSome ? input : 0); + instance.exports.bjs_roundTripOptionalFileSize(+isSome, isSome ? input : 0n); const isSome1 = i32Stack.pop(); let optResult; if (isSome1) { @@ -488,7 +488,7 @@ export async function createInstantiator(options, swift) { }, roundTripOptionalSessionId: function bjs_roundTripOptionalSessionId(input) { const isSome = input != null; - instance.exports.bjs_roundTripOptionalSessionId(+isSome, isSome ? input : 0); + instance.exports.bjs_roundTripOptionalSessionId(+isSome, isSome ? input : 0n); const isSome1 = i32Stack.pop(); let optResult; if (isSome1) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js index 4aa424d68..211cbefa3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js @@ -258,7 +258,7 @@ export async function createInstantiator(options, swift) { return ret; } catch (error) { setException(error); - return 0 + return 0n } } TestModule["bjs_roundTripUInt64"] = function bjs_roundTripUInt64(v) { @@ -267,7 +267,7 @@ export async function createInstantiator(options, swift) { return ret; } catch (error) { setException(error); - return 0 + return 0n } } }, diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs index 6576876da..ae445d3f4 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs @@ -80,6 +80,10 @@ export function runJsOptionalSupportTests(rootExports) { assert.equal(exports.roundTripOptionalIntRawValueEnum(HttpStatus.Ok), HttpStatusValues.Ok); assert.equal(exports.roundTripOptionalInt64RawValueEnum(FileSize.Tiny), FileSizeValues.Tiny); assert.equal(exports.roundTripOptionalUInt64RawValueEnum(SessionId.Active), SessionIdValues.Active); + // The `none` case lowers the i64/u64 placeholder as a BigInt (`0n`); a plain `0` + // would throw "Cannot convert 0 to a BigInt" when calling the Wasm export. + assert.equal(exports.roundTripOptionalInt64RawValueEnum(null), null); + assert.equal(exports.roundTripOptionalUInt64RawValueEnum(null), null); assert.equal(exports.roundTripOptionalTSEnum(TSDirection.North), TSDirection.North); assert.equal(exports.roundTripOptionalTSStringEnum(TSTheme.Light), TSTheme.Light); assert.equal(exports.roundTripOptionalNamespacedEnum(Networking.API.Method.Get), Networking.API.Method.Get); From c93a0310de03ad55bf40c8cfd2f51b4022bc4dc1 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 3 Jun 2026 12:56:25 +0200 Subject: [PATCH 58/68] BridgeJS: Support optional @JSClass as exported function parameters --- .../Sources/BridgeJSLink/JSGlueGen.swift | 22 +++++- .../Inputs/MacroSwift/Optionals.swift | 7 ++ .../BridgeJSCodegenTests/Optionals.json | 70 +++++++++++++++++++ .../BridgeJSCodegenTests/Optionals.swift | 22 ++++++ .../BridgeJSLinkTests/Optionals.d.ts | 2 + .../BridgeJSLinkTests/Optionals.js | 42 +++++++++++ .../JavaScriptKit/BridgeJSIntrinsics.swift | 23 ++++++ .../BridgeJSRuntimeTests/ExportAPITests.swift | 4 ++ .../Generated/BridgeJS.swift | 11 +++ .../Generated/JavaScript/BridgeJS.json | 35 ++++++++++ Tests/prelude.mjs | 7 ++ 11 files changed, 243 insertions(+), 2 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 51ef16b20..365d3e3bd 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -762,7 +762,7 @@ struct IntrinsicJSFragment: Sendable { } let innerFragment = - if wrappedType.optionalConvention == .stackABI { + if wrappedType.optionalParameterUsesStackABI { try stackLowerFragment(elementType: wrappedType) } else { try lowerParameter(type: wrappedType) @@ -779,7 +779,7 @@ struct IntrinsicJSFragment: Sendable { kind: JSOptionalKind, innerFragment: IntrinsicJSFragment ) throws -> IntrinsicJSFragment { - let isStackConvention = wrappedType.optionalConvention == .stackABI + let isStackConvention = wrappedType.optionalParameterUsesStackABI return IntrinsicJSFragment( parameters: ["value"], @@ -2696,6 +2696,24 @@ private extension BridgeType { } } + /// Whether an optional of this type pushes its payload onto the bridge stack + /// when passed as a *parameter*. + /// + /// This usually matches `optionalConvention == .stackABI`, but `jsObject` + /// optionals are the exception: their return values travel through the stack + /// while their parameters use the direct `(isSome, objId)` ABI, matching plain + /// `Optional` and exported `@JS class` parameters. + var optionalParameterUsesStackABI: Bool { + switch self { + case .jsObject: + return false + case .nullable(let wrapped, _): + return wrapped.optionalParameterUsesStackABI + default: + return optionalConvention == .stackABI + } + } + var nilSentinel: NilSentinel { switch self { case .swiftProtocol: diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift index 5df48d9c0..ea37f5740 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Optionals.swift @@ -30,6 +30,13 @@ class OptionalPropertyHolder { @JS func testOptionalPropertyRoundtrip(_ holder: OptionalPropertyHolder?) -> OptionalPropertyHolder? +// Exported functions taking an optional jsObject use the direct (isSome, objId) +// parameter ABI; the return value travels through the stack ABI. +@JS func roundTripExportedOptionalJSObject(value: JSObject?) -> JSObject? + +// Exported function taking/returning an optional imported @JSClass (issue #751). +@JS func roundTripExportedOptionalJSClass(value: WithOptionalJSClass?) -> WithOptionalJSClass? + @JS func roundTripString(name: String?) -> String? { return name diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json index 91291c24e..e9d78cbbc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.json @@ -239,6 +239,76 @@ } } }, + { + "abiName" : "bjs_roundTripExportedOptionalJSObject", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripExportedOptionalJSObject", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "jsObject" : { + + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_roundTripExportedOptionalJSClass", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripExportedOptionalJSClass", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "WithOptionalJSClass" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "WithOptionalJSClass" + } + }, + "_1" : "null" + } + } + }, { "abiName" : "bjs_roundTripString", "effects" : { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift index 0a2528340..65380d1e3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Optionals.swift @@ -20,6 +20,28 @@ public func _bjs_testOptionalPropertyRoundtrip(_ holderIsSome: Int32, _ holderVa #endif } +@_expose(wasm, "bjs_roundTripExportedOptionalJSObject") +@_cdecl("bjs_roundTripExportedOptionalJSObject") +public func _bjs_roundTripExportedOptionalJSObject(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripExportedOptionalJSObject(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripExportedOptionalJSClass") +@_cdecl("bjs_roundTripExportedOptionalJSClass") +public func _bjs_roundTripExportedOptionalJSClass(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripExportedOptionalJSClass(value: Optional.bridgeJSLiftParameter(valueIsSome, valueValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundTripString") @_cdecl("bjs_roundTripString") public func _bjs_roundTripString(_ nameIsSome: Int32, _ nameBytes: Int32, _ nameLength: Int32) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts index fb9d68db7..c4a22ac0c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.d.ts @@ -50,6 +50,8 @@ export type Exports = { } roundTripOptionalClass(value: Greeter | null): Greeter | null; testOptionalPropertyRoundtrip(holder: OptionalPropertyHolder | null): OptionalPropertyHolder | null; + roundTripExportedOptionalJSObject(value: any | null): any | null; + roundTripExportedOptionalJSClass(value: WithOptionalJSClass | null): WithOptionalJSClass | null; roundTripString(name: string | null): string | null; roundTripInt(value: number | null): number | null; roundTripInt8(value: number | null): number | null; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index f376c1b24..58dd88780 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -725,6 +725,48 @@ export async function createInstantiator(options, swift) { const optResult = pointer === null ? null : OptionalPropertyHolder.__construct(pointer); return optResult; }, + roundTripExportedOptionalJSObject: function bjs_roundTripExportedOptionalJSObject(value) { + const isSome = value != null; + let result; + if (isSome) { + result = swift.memory.retain(value); + } else { + 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; + }, + roundTripExportedOptionalJSClass: function bjs_roundTripExportedOptionalJSClass(value) { + const isSome = value != null; + let result; + if (isSome) { + result = swift.memory.retain(value); + } else { + 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; + }, roundTripString: function bjs_roundTripString(name) { const isSome = name != null; let result, result1; diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index ff586b45b..955f31ea9 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -1826,6 +1826,29 @@ extension _BridgedAsOptional where Wrapped == JSObject { } } +extension _BridgedAsOptional where Wrapped: _JSBridgedClass { + // `@JSClass` wrappers (`_JSBridgedClass`) bridge an underlying `JSObject`, so an + // optional wrapper mirrors `Optional`: parameters use the direct + // (`isSome`, object id) ABI while returns travel through the bridge stack. + // + // Stack push/pop is provided by the generic `Wrapped: _BridgedSwiftStackType` + // extension; only the direct parameter lift and the export return lowering need + // dedicated implementations here. + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ objectId: Int32) -> Self { + Self( + optional: Optional._bridgeJSLiftParameter( + isSome, + objectId, + liftWrapped: Wrapped.bridgeJSLiftParameter + ) + ) + } + + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + Wrapped.bridgeJSStackPushAsOptional(asOptional) + } +} + extension _BridgedAsOptional where Wrapped: _BridgedSwiftProtocolWrapper { @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ objectId: Int32) -> Self { Self( diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index c6e216203..efad25ca1 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -75,6 +75,10 @@ func runJsWorks() -> Void return try Foo(value) } +@JS func roundTripOptionalImportedClass(v: Foo?) -> Foo? { + return v +} + struct TestError: Error { let message: String } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 3fa4eb9d5..944231b28 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -6940,6 +6940,17 @@ public func _bjs_makeImportedFoo(_ valueBytes: Int32, _ valueLength: Int32) -> I #endif } +@_expose(wasm, "bjs_roundTripOptionalImportedClass") +@_cdecl("bjs_roundTripOptionalImportedClass") +public func _bjs_roundTripOptionalImportedClass(_ vIsSome: Int32, _ vValue: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripOptionalImportedClass(v: Optional.bridgeJSLiftParameter(vIsSome, vValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_throwsSwiftError") @_cdecl("bjs_throwsSwiftError") public func _bjs_throwsSwiftError(_ shouldThrow: Int32) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 94142f470..b29321cf1 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -11917,6 +11917,41 @@ } } }, + { + "abiName" : "bjs_roundTripOptionalImportedClass", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripOptionalImportedClass", + "parameters" : [ + { + "label" : "v", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "Foo" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "jsObject" : { + "_0" : "Foo" + } + }, + "_1" : "null" + } + } + }, { "abiName" : "bjs_throwsSwiftError", "effects" : { diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 2c922dbe2..5091b1dd6 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -301,6 +301,13 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.ok(foo instanceof ImportedFoo); assert.equal(foo.value, "hello"); + // Optional @JSClass directly as an exported function parameter/return value (issue #751) + const optFoo = new ImportedFoo("optional-foo"); + const optFooResult = exports.roundTripOptionalImportedClass(optFoo); + assert.ok(optFooResult instanceof ImportedFoo); + assert.equal(optFooResult.value, "optional-foo"); + assert.equal(exports.roundTripOptionalImportedClass(null), null); + // Test PropertyHolder with various types const testObj = { testProp: "test" }; const sibling = new exports.SimplePropertyHolder(999); From 83098c2bc1dbffe851f64303d880d5f024652265 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 9 Jun 2026 18:30:40 +0200 Subject: [PATCH 59/68] BridgeJS: Pass optional jsObject import parameters via direct ABI --- .../Sources/BridgeJSLink/JSGlueGen.swift | 4 +-- .../BridgeJSLinkTests/Optionals.js | 30 ++++------------ .../Generated/BridgeJS.swift | 21 ++++++++++++ .../Generated/JavaScript/BridgeJS.json | 34 +++++++++++++++++++ .../JavaScript/OptionalSupportTests.mjs | 3 ++ .../OptionalSupportTests.swift | 11 ++++++ 6 files changed, 77 insertions(+), 26 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 365d3e3bd..5ee86a57e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -669,7 +669,7 @@ struct IntrinsicJSFragment: Sendable { } let innerFragment = - if wrappedType.optionalConvention == .stackABI { + if wrappedType.optionalParameterUsesStackABI { try stackLiftFragment(elementType: wrappedType) } else { try liftParameter(type: wrappedType, context: bridgeContext) @@ -686,7 +686,7 @@ struct IntrinsicJSFragment: Sendable { kind: JSOptionalKind, innerFragment: IntrinsicJSFragment ) -> IntrinsicJSFragment { - let isStackConvention = wrappedType.optionalConvention == .stackABI + let isStackConvention = wrappedType.optionalParameterUsesStackABI let absenceLiteral = kind.absenceLiteral let outerParams: [String] diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 58dd88780..d084c8fcf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -387,18 +387,9 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_childOrNull_set"] = function bjs_WithOptionalJSClass_childOrNull_set(self, newValue) { + TestModule["bjs_WithOptionalJSClass_childOrNull_set"] = function bjs_WithOptionalJSClass_childOrNull_set(self, newValueIsSome, newValueObjectId) { try { - let optResult; - if (newValue) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optResult = obj; - } else { - optResult = null; - } - swift.memory.getObject(self).childOrNull = optResult; + swift.memory.getObject(self).childOrNull = newValueIsSome ? swift.memory.getObject(newValueObjectId) : null; } catch (error) { setException(error); } @@ -489,22 +480,13 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_WithOptionalJSClass_roundTripChildOrNull"] = function bjs_WithOptionalJSClass_roundTripChildOrNull(self, value) { + TestModule["bjs_WithOptionalJSClass_roundTripChildOrNull"] = function bjs_WithOptionalJSClass_roundTripChildOrNull(self, valueIsSome, valueObjectId) { try { - let optResult; - if (value) { - const objId = i32Stack.pop(); - const obj = swift.memory.getObject(objId); - swift.memory.release(objId); - optResult = obj; - } else { - optResult = null; - } - let ret = swift.memory.getObject(self).roundTripChildOrNull(optResult); + let ret = swift.memory.getObject(self).roundTripChildOrNull(valueIsSome ? swift.memory.getObject(valueObjectId) : null); const isSome = ret != null; if (isSome) { - const objId1 = swift.memory.retain(ret); - i32Stack.push(objId1); + const objId = swift.memory.retain(ret); + i32Stack.push(objId); } i32Stack.push(isSome ? 1 : 0); } catch (error) { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 944231b28..af8308c88 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -14087,6 +14087,18 @@ fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDic return bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static_extern(v) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalJSObjectNull_static") +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSObjectNull_static_extern(_ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSObjectNull_static_extern(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSObjectNull_static(_ valueIsSome: Int32, _ valueValue: Int32) -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalJSObjectNull_static_extern(valueIsSome, valueValue) +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_runJsOptionalSupportTests_static") fileprivate func bjs_OptionalSupportImports_runJsOptionalSupportTests_static_extern() -> Void @@ -14173,6 +14185,15 @@ func _$OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefin return JSUndefinedOr<[String: String]>.bridgeJSLiftReturn() } +func _$OptionalSupportImports_jsRoundTripOptionalJSObjectNull(_ value: Optional) throws(JSException) -> Optional { + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalJSObjectNull_static(valueIsSome, valueValue) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn() +} + func _$OptionalSupportImports_runJsOptionalSupportTests() throws(JSException) -> Void { bjs_OptionalSupportImports_runJsOptionalSupportTests_static() if let error = _swift_js_take_exception() { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index b29321cf1..4f1038b5e 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -21047,6 +21047,40 @@ } } }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripOptionalJSObjectNull", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "jsObject" : { + + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "jsObject" : { + + } + }, + "_1" : "null" + } + } + }, { "accessLevel" : "internal", "effects" : { diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs index 6576876da..7c2b991ae 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs @@ -46,6 +46,9 @@ export function getImports(importsContext) { jsRoundTripOptionalStringToStringDictionaryUndefined: (v) => { return v === undefined ? undefined : v; }, + jsRoundTripOptionalJSObjectNull: (v) => { + return v ?? null; + }, runJsOptionalSupportTests: () => { const exports = importsContext.getExports(); if (!exports) { throw new Error("No exports!?"); } diff --git a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift index 3b06901db..85eaa04c7 100644 --- a/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift +++ b/Tests/BridgeJSRuntimeTests/OptionalSupportTests.swift @@ -24,6 +24,8 @@ import JavaScriptEventLoop _ v: JSUndefinedOr<[String: String]> ) throws(JSException) -> JSUndefinedOr<[String: String]> + @JSFunction static func jsRoundTripOptionalJSObjectNull(_ value: JSObject?) throws(JSException) -> JSObject? + @JSFunction static func runJsOptionalSupportTests() throws(JSException) } @@ -84,6 +86,15 @@ final class OptionalSupportTests: XCTestCase { func testRoundTripOptionalStringToStringDictionaryUndefined() throws { try roundTripTest(OptionalSupportImports.jsRoundTripOptionalStringToStringDictionaryUndefined, ["key": "value"]) } + + func testRoundTripOptionalJSObjectNull() throws { + try XCTAssertNil(OptionalSupportImports.jsRoundTripOptionalJSObjectNull(nil)) + + let object = JSObject.global.Object.function!.new() + object.testProp = "hello" + let result = try OptionalSupportImports.jsRoundTripOptionalJSObjectNull(object) + XCTAssertEqual(result?.testProp.string, "hello") + } } @JS enum OptionalSupportExports { From 388160c0028ca7c61c6d140b9998a126c70297c4 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 9 Jun 2026 18:54:56 +0200 Subject: [PATCH 60/68] BridgeJS: Support non-ConvertibleToJSValue async exported return types (#758) --- .../Sources/BridgeJSCore/ExportSwift.swift | 149 +++- .../Sources/BridgeJSLink/BridgeJSLink.swift | 67 ++ .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 43 + .../BridgeJSToolTests/DiagnosticsTests.swift | 50 ++ .../Inputs/MacroSwift/Async.swift | 63 ++ .../BridgeJSCodegenTests/Async.json | 461 ++++++++++ .../BridgeJSCodegenTests/Async.swift | 666 ++++++++++++++- .../BridgeJSLinkTests/ArrayTypes.js | 7 + .../BridgeJSLinkTests/Async.d.ts | 34 + .../__Snapshots__/BridgeJSLinkTests/Async.js | 441 ++++++++++ .../BridgeJSLinkTests/AsyncImport.js | 7 + .../BridgeJSLinkTests/AsyncStaticImport.js | 7 + .../BridgeJSLinkTests/DefaultParameters.js | 7 + .../BridgeJSLinkTests/DictionaryTypes.js | 7 + .../BridgeJSLinkTests/EnumAssociatedValue.js | 7 + .../BridgeJSLinkTests/EnumCase.js | 7 + .../BridgeJSLinkTests/EnumCaseImport.js | 7 + .../BridgeJSLinkTests/EnumNamespace.Global.js | 7 + .../BridgeJSLinkTests/EnumNamespace.js | 7 + .../BridgeJSLinkTests/EnumRawType.js | 7 + .../BridgeJSLinkTests/FixedWidthIntegers.js | 7 + .../BridgeJSLinkTests/GlobalGetter.js | 7 + .../BridgeJSLinkTests/GlobalThisImports.js | 7 + .../IdentityModeClass.ConfigPointer.js | 7 + .../IdentityModeClass.PerClass.js | 7 + .../BridgeJSLinkTests/IdentityModeClass.js | 7 + .../BridgeJSLinkTests/ImportArray.js | 7 + .../ImportedTypeInExportedInterface.js | 7 + .../BridgeJSLinkTests/InvalidPropertyNames.js | 7 + .../BridgeJSLinkTests/JSClass.js | 7 + .../JSClassStaticFunctions.js | 7 + .../BridgeJSLinkTests/JSTypedArrayTypes.js | 7 + .../BridgeJSLinkTests/JSValue.js | 7 + .../BridgeJSLinkTests/MixedGlobal.js | 7 + .../BridgeJSLinkTests/MixedModules.js | 7 + .../BridgeJSLinkTests/MixedPrivate.js | 7 + .../BridgeJSLinkTests/Namespaces.Global.js | 7 + .../BridgeJSLinkTests/Namespaces.js | 7 + .../BridgeJSLinkTests/NestedType.js | 7 + .../BridgeJSLinkTests/Optionals.js | 7 + .../BridgeJSLinkTests/PrimitiveParameters.js | 7 + .../BridgeJSLinkTests/PrimitiveReturn.js | 7 + .../BridgeJSLinkTests/PropertyTypes.js | 7 + .../BridgeJSLinkTests/Protocol.js | 7 + .../BridgeJSLinkTests/ProtocolInClosure.js | 7 + .../StaticFunctions.Global.js | 7 + .../BridgeJSLinkTests/StaticFunctions.js | 7 + .../StaticProperties.Global.js | 7 + .../BridgeJSLinkTests/StaticProperties.js | 7 + .../BridgeJSLinkTests/StringParameter.js | 7 + .../BridgeJSLinkTests/StringReturn.js | 7 + .../BridgeJSLinkTests/SwiftClass.js | 7 + .../BridgeJSLinkTests/SwiftClosure.js | 7 + .../BridgeJSLinkTests/SwiftClosureImports.js | 7 + .../BridgeJSLinkTests/SwiftStruct.js | 7 + .../BridgeJSLinkTests/SwiftStructImports.js | 7 + .../SwiftTypedClosureAccess.js | 7 + .../__Snapshots__/BridgeJSLinkTests/Throws.js | 7 + .../BridgeJSLinkTests/UnsafePointer.js | 7 + .../VoidParameterVoidReturn.js | 7 + Plugins/PackageToJS/Templates/instantiate.js | 1 + .../JavaScriptKit/BridgeJSIntrinsics.swift | 64 ++ .../BridgeJSRuntimeTests/ExportAPITests.swift | 24 + .../Generated/BridgeJS.swift | 800 +++++++++++++++++- .../Generated/JavaScript/BridgeJS.json | 783 +++++++++++++++-- .../JavaScript/AsyncImportTests.mjs | 76 ++ Tests/BridgeJSRuntimeTests/StructAPIs.swift | 35 + 67 files changed, 3939 insertions(+), 175 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index b649b244d..c9ef1e6f1 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -90,11 +90,77 @@ public class ExportSwift { decls.append(contentsOf: try renderSingleExportedClass(klass: klass)) } } + + try withSpan("Render Async Promise Helpers") { [self] in + let asyncResolveTypes = skeleton.asyncPromiseResolveReturnTypes + if !asyncResolveTypes.isEmpty { + decls.append(contentsOf: try renderPromiseRejectHelper()) + for type in asyncResolveTypes { + decls.append(contentsOf: try renderPromiseResolveHelper(type)) + } + } + } return withSpan("Format Export Glue") { return decls.map { $0.description }.joined(separator: "\n\n") } } + /// Generates the per-type `Promise_resolve_` settlement helper. + private func renderPromiseResolveHelper(_ type: BridgeType) throws -> [DeclSyntax] { + try renderPromiseSettleHelper( + functionName: "Promise_resolve_\(type.mangleTypeName)", + externName: "promise_resolve_\(moduleName)_\(type.mangleTypeName)", + valueType: type + ) + } + + /// Generates the shared `Promise_reject` settlement helper. + private func renderPromiseRejectHelper() throws -> [DeclSyntax] { + try renderPromiseSettleHelper( + functionName: "Promise_reject", + externName: "promise_reject_\(moduleName)", + valueType: .jsValue + ) + } + + /// Generates a `@JSFunction func (_ promise: JSObject, _ value: T)` and its + /// glue, lowering `value` through the standard imported-parameter ABI. + private func renderPromiseSettleHelper( + functionName: String, + externName: String, + valueType: BridgeType + ) throws -> [DeclSyntax] { + let effects = Effects(isAsync: false, isThrows: true) + // `Void` can't cross the bridge as a parameter, so the void helper takes only the promise. + var parameters = [Parameter(label: nil, name: "promise", type: .jsObject(nil))] + if valueType != .void { + parameters.append(Parameter(label: nil, name: "value", type: valueType)) + } + let builder = try ImportTS.CallJSEmission( + moduleName: "bjs", + abiName: externName, + effects: effects, + returnType: .void, + context: .importTS + ) + for parameter in parameters { + try builder.lowerParameter(param: parameter) + } + try builder.call() + try builder.liftReturnValue() + + let valueParam = valueType == .void ? "" : ", _ value: \(valueType.swiftType)" + let macroDecl: DeclSyntax = + "@JSFunction func \(raw: functionName)(_ promise: JSObject\(raw: valueParam)) throws(JSException)" + let glueDecl = builder.renderThunkDecl( + name: "_$\(functionName)", + parameters: parameters, + returnType: .void, + effects: effects + ) + return [macroDecl, builder.renderImportDecl(), glueDecl] + } + class ExportedThunkBuilder { var body: [CodeBlockItemSyntax] = [] var liftedParameterExprs: [ExprSyntax] = [] @@ -104,8 +170,22 @@ public class ExportSwift { var externDecls: [DeclSyntax] = [] let effects: Effects - init(effects: Effects) { + /// The async return type settled through `_bjs_makePromise`'s `Promise_resolve_` + /// helper. Set for every `async` thunk. + var asyncResolveReturnType: BridgeType? + + /// Stack-using parameter lifts hoisted ahead of the deferred async closure. + var asyncHoistedBindings: [CodeBlockItemSyntax] = [] + + init(effects: Effects, returnType: BridgeType) throws { self.effects = effects + guard effects.isAsync else { return } + guard returnType.isAsyncResolvable else { + throw BridgeJSCoreError( + "Returning '\(returnType.swiftType)' from an async exported function is not yet supported" + ) + } + self.asyncResolveReturnType = returnType } private func append(_ item: CodeBlockItemSyntax) { @@ -200,7 +280,7 @@ public class ExportSwift { } if effects.isAsync, returnType != .void { - return CodeBlockItemSyntax(item: .init(StmtSyntax("return \(raw: callExpr).jsValue"))) + return CodeBlockItemSyntax(item: .init(StmtSyntax("return \(raw: callExpr)"))) } if returnType == .void { @@ -244,6 +324,22 @@ public class ExportSwift { param.type.isStackUsingParameter ? index : nil } + if effects.isAsync { + // Drain stack parameters before the deferred `Task` or the shared stack is corrupted. + for index in stackParamIndices.reversed() { + let param = parameters[index] + let expr = liftedParameterExprs[index] + let varName = "_tmp_\(param.name)" + var binding: CodeBlockItemSyntax = "let \(raw: varName) = \(expr)" + if !asyncHoistedBindings.isEmpty { + binding = binding.with(\.leadingTrivia, .newline) + } + asyncHoistedBindings.append(binding) + liftedParameterExprs[index] = ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier(varName))) + } + return + } + guard stackParamIndices.count > 1 else { return } for index in stackParamIndices.reversed() { @@ -293,8 +389,7 @@ public class ExportSwift { return } if effects.isAsync { - // The return value of async function (T of `(...) async -> T`) is - // handled by the JSPromise.async, so we don't need to do anything here. + // The async return value is lowered by the generated `Promise_resolve_*` helper. return } @@ -328,25 +423,25 @@ public class ExportSwift { } } + /// A throwing async body needs an explicit closure type, otherwise Swift infers + /// `throws(any Error)` instead of `throws(JSException)`. + /// See: https://github.com/swiftlang/swift/issues/76165 + private func asyncThrowsClosureHead(returnSpelling: String?) -> String { + guard effects.isThrows else { return "" } + let returns = returnSpelling.map { " -> \($0)" } ?? "" + return " () async throws(JSException)\(returns) in" + } + func render(abiName: String) -> DeclSyntax { let body: CodeBlockItemListSyntax - if effects.isAsync { - // Explicit closure type annotation needed when throws is present - // so Swift infers throws(JSException) instead of throws(any Error) - // See: https://github.com/swiftlang/swift/issues/76165 - let closureHead: String - if effects.isThrows { - let hasReturn = self.body.contains { $0.description.contains("return ") } - let ret = hasReturn ? " -> JSValue" : "" - closureHead = " () async throws(JSException)\(ret) in" - } else { - closureHead = "" - } + if effects.isAsync, let resolveType = asyncResolveReturnType { + let resolveName = "Promise_resolve_\(resolveType.mangleTypeName)" + let closureHead = asyncThrowsClosureHead(returnSpelling: resolveType.swiftType) body = """ - let ret = JSPromise.async {\(raw: closureHead) + \(CodeBlockItemListSyntax(asyncHoistedBindings)) + return _bjs_makePromise(resolve: \(raw: resolveName), reject: Promise_reject) {\(raw: closureHead) \(CodeBlockItemListSyntax(self.body)) - }.jsObject - return ret.bridgeJSLowerReturn() + } """ } else if effects.isThrows { body = """ @@ -457,7 +552,10 @@ public class ExportSwift { let className = context.className let isStatic = context.isStatic - let getterBuilder = ExportedThunkBuilder(effects: Effects(isAsync: false, isThrows: false, isStatic: isStatic)) + let getterBuilder = try ExportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: false, isStatic: isStatic), + returnType: property.type + ) if !isStatic { try getterBuilder.liftParameter( @@ -476,8 +574,9 @@ public class ExportSwift { // Generate property setter if not readonly if !property.isReadonly { - let setterBuilder = ExportedThunkBuilder( - effects: Effects(isAsync: false, isThrows: false, isStatic: isStatic) + let setterBuilder = try ExportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: false, isStatic: isStatic), + returnType: .void ) // Lift parameters based on property type @@ -507,7 +606,7 @@ public class ExportSwift { } func renderSingleExportedFunction(function: ExportedFunction) throws -> DeclSyntax { - let builder = ExportedThunkBuilder(effects: function.effects) + let builder = try ExportedThunkBuilder(effects: function.effects, returnType: function.returnType) for param in function.parameters { try builder.liftParameter(param: param) } @@ -536,7 +635,7 @@ public class ExportSwift { callName: String, returnType: BridgeType ) throws -> DeclSyntax { - let builder = ExportedThunkBuilder(effects: constructor.effects) + let builder = try ExportedThunkBuilder(effects: constructor.effects, returnType: returnType) for param in constructor.parameters { try builder.liftParameter(param: param) } @@ -550,7 +649,7 @@ public class ExportSwift { ownerTypeName: String, instanceSelfType: BridgeType ) throws -> DeclSyntax { - let builder = ExportedThunkBuilder(effects: method.effects) + let builder = try ExportedThunkBuilder(effects: method.effects, returnType: method.returnType) if !method.effects.isStatic { try builder.liftParameter(param: Parameter(label: nil, name: "_self", type: instanceSelfType)) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index ce0ba0cb8..9a8442435 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -356,6 +356,40 @@ public struct BridgeJSLink { ] } + /// JS const (in the import glue scope) holding the `Symbol` under which a promise's + /// resolve/reject settlers are stashed. + private static let promiseSettlersSymbol = "__bjs_promiseSettlers" + + /// Renders a `bjs[...]` settlement handler that lifts `(promise, value)` and calls the + /// promise's stashed `resolve` / `reject` settler. + private func renderPromiseSettleHandler( + externName: String, + valueType: BridgeType, + settle: String, + into printer: CodeFragmentPrinter + ) throws { + let builder = ImportedThunkBuilder( + effects: Effects(isAsync: false, isThrows: true), + returnType: .void, + intrinsicRegistry: intrinsicRegistry + ) + try builder.liftParameter(param: Parameter(label: nil, name: "promise", type: .jsObject(nil))) + // `Void` can't cross the bridge as a parameter, so the void resolve settles with `undefined`. + let valueArg: String + if valueType == .void { + valueArg = "" + } else { + try builder.liftParameter(param: Parameter(label: nil, name: "value", type: valueType)) + valueArg = builder.parameterForwardings[1] + } + builder.body.write( + "\(builder.parameterForwardings[0])[\(Self.promiseSettlersSymbol)].\(settle)(\(valueArg));" + ) + var lines = builder.renderFunction(name: nil) + lines[0] = "bjs[\"\(externName)\"] = \(lines[0])" + printer.write(lines: lines) + } + private func generateAddImports(needsImportsObject: Bool) throws -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() let allStructs = skeletons.compactMap { $0.exported?.structs }.flatMap { $0 } @@ -526,6 +560,39 @@ public struct BridgeJSLink { } } + // Always provided: the runtime's `_bjs_makePromise` imports it unconditionally. + // The settlers are stored under a Symbol to avoid clashing with promise fields. + printer.write("const \(Self.promiseSettlersSymbol) = Symbol(\"JavaScriptKit.promiseSettlers\");") + printer.write("bjs[\"swift_js_make_promise\"] = function() {") + printer.indent { + printer.write("let resolve, reject;") + printer.write("const promise = new Promise((res, rej) => { resolve = res; reject = rej; });") + printer.write("promise[\(Self.promiseSettlersSymbol)] = { resolve, reject };") + printer.write( + "return \(JSGlueVariableScope.reservedSwift).\(JSGlueVariableScope.reservedMemory).retain(promise);" + ) + } + printer.write("}") + for skeleton in skeletons { + guard let exported = skeleton.exported else { continue } + let asyncResolveTypes = exported.asyncPromiseResolveReturnTypes + guard !asyncResolveTypes.isEmpty else { continue } + for type in asyncResolveTypes { + try renderPromiseSettleHandler( + externName: "promise_resolve_\(skeleton.moduleName)_\(type.mangleTypeName)", + valueType: type, + settle: "resolve", + into: printer + ) + } + try renderPromiseSettleHandler( + externName: "promise_reject_\(skeleton.moduleName)", + valueType: .jsValue, + settle: "reject", + into: printer + ) + } + printer.write("bjs[\"swift_js_return_optional_bool\"] = function(isSome, value) {") printer.indent { printer.write("if (isSome === 0) {") diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 346b7333b..f1e2e80fe 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -1027,6 +1027,30 @@ public struct ExportedSkeleton: Codable { public var isEmpty: Bool { functions.isEmpty && classes.isEmpty && enums.isEmpty && structs.isEmpty && protocols.isEmpty } + + /// Distinct `async` return types needing a `Promise_resolve_` helper, deduplicated + /// by mangled name. Shared by the Swift codegen and JS link. + public var asyncPromiseResolveReturnTypes: [BridgeType] { + var seen = Set() + var result: [BridgeType] = [] + func consider(_ returnType: BridgeType, _ effects: Effects) { + guard effects.isAsync, returnType.isAsyncResolvable, + seen.insert(returnType.mangleTypeName).inserted + else { return } + result.append(returnType) + } + for function in functions { consider(function.returnType, function.effects) } + for klass in classes { + for method in klass.methods { consider(method.returnType, method.effects) } + } + for structDef in structs { + for method in structDef.methods { consider(method.returnType, method.effects) } + } + for enumDef in enums { + for method in enumDef.staticMethods { consider(method.returnType, method.effects) } + } + return result + } } // MARK: - Imported Skeleton @@ -1584,6 +1608,25 @@ extension BridgeType { return false } + /// Whether a value of this type can be passed to a generated `Promise_resolve_` + /// settlement helper, i.e. lowered through the imported-parameter ABI. Every `async` + /// exported return settles through `_bjs_makePromise`; the few types that cannot be lowered + /// (associated-value enums, protocols, namespace enums, and their compositions) are diagnosed. + public var isAsyncResolvable: Bool { + switch self { + case .associatedValueEnum, .swiftProtocol, .namespaceEnum: + return false + case .nullable(let wrapped, _): + return wrapped.isAsyncResolvable + case .array(let element): + return element.isAsyncResolvable + case .dictionary(let value): + return value.isAsyncResolvable + default: + return true + } + } + /// Simplified Swift ABI-style mangled name /// https://github.com/swiftlang/swift/blob/main/docs/ABI/Mangling.rst#types public var mangleTypeName: String { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift index e71a1f84e..82747f74e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift @@ -305,6 +305,56 @@ import Testing #expect(skeleton.exported != nil) } + // MARK: - Async return validation + + @Test + func asyncReturnOfUnsupportedTypeIsDiagnosed() throws { + // An associated-value enum can be neither lowered through the imported-parameter ABI + // nor settled via `_bjs_makePromise`, so an async return of one must be diagnosed. + let source = """ + @JS enum Payload { + case text(String) + case number(Int) + } + @JS func loadPayload() async -> Payload { + .number(1) + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + let exported = try #require(skeleton.exported) + let exportSwift = ExportSwift(progress: .silent, moduleName: skeleton.moduleName, skeleton: exported) + #expect(throws: BridgeJSCoreError.self) { + _ = try exportSwift.finalize() + } + } + + @Test + func asyncReturnOfConvertibleTypeSucceeds() throws { + let source = """ + @JS func loadCount() async -> Int { + 1 + } + """ + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + swiftAPI.addSourceFile(Parser.parse(source: source), inputFilePath: "test.swift") + let skeleton = try swiftAPI.finalize() + let exported = try #require(skeleton.exported) + let exportSwift = ExportSwift(progress: .silent, moduleName: skeleton.moduleName, skeleton: exported) + #expect(try exportSwift.finalize() != nil) + } + @Test func omitsNextLineWhenErrorIsOnLastLine() throws { let source = """ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift index 214331b32..e63bea4ca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift @@ -17,3 +17,66 @@ @JS func asyncRoundTripJSObject(_ v: JSObject) async -> JSObject { return v } + +@JS struct AsyncPoint { + var x: Int + var y: Int +} + +@JS func asyncRoundTripStruct(_ v: AsyncPoint) async -> AsyncPoint { + return v +} + +@JS func asyncRoundTripStructThrows(_ v: AsyncPoint) async throws(JSException) -> AsyncPoint { + return v +} + +@JS func asyncCombineStructs(_ a: AsyncPoint, _ b: AsyncPoint) async -> AsyncPoint { + return AsyncPoint(x: a.x + b.x, y: a.y + b.y) +} + +@JS enum AsyncDirection { + case north + case south +} + +@JS func asyncRoundTripEnum(_ v: AsyncDirection) async -> AsyncDirection { + return v +} + +@JS enum AsyncTheme: String { + case light + case dark +} + +@JS func asyncRoundTripRawEnum(_ v: AsyncTheme) async -> AsyncTheme { + return v +} + +@JS func asyncRoundTripOptionalEnum(_ v: AsyncDirection?) async -> AsyncDirection? { + return v +} + +@JS func asyncRoundTripOptionalRawEnum(_ v: AsyncTheme?) async -> AsyncTheme? { + return v +} + +@JS func asyncRoundTripOptionalStruct(_ v: AsyncPoint?) async -> AsyncPoint? { + return v +} + +@JS func asyncRoundTripStructArray(_ v: [AsyncPoint]) async -> [AsyncPoint] { + return v +} + +@JS func asyncRoundTripEnumArray(_ v: [AsyncDirection]) async -> [AsyncDirection] { + return v +} + +@JS func asyncRoundTripStructDictionary(_ v: [String: AsyncPoint]) async -> [String: AsyncPoint] { + return v +} + +@JS func asyncRoundTripEnumDictionary(_ v: [String: AsyncDirection]) async -> [String: AsyncDirection] { + return v +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json index 27ba89aca..3bd594419 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json @@ -4,7 +4,59 @@ ], "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "north" + }, + { + "associatedValues" : [ + + ], + "name" : "south" + } + ], + "emitStyle" : "const", + "name" : "AsyncDirection", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "AsyncDirection", + "tsFullPath" : "AsyncDirection" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "light" + }, + { + "associatedValues" : [ + ], + "name" : "dark" + } + ], + "emitStyle" : "const", + "name" : "AsyncTheme", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "AsyncTheme", + "tsFullPath" : "AsyncTheme" + } ], "exposeToGlobal" : false, "functions" : [ @@ -180,13 +232,422 @@ } } + }, + { + "abiName" : "bjs_asyncRoundTripStruct", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripStruct", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripStructThrows", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncRoundTripStructThrows", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + }, + { + "abiName" : "bjs_asyncCombineStructs", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncCombineStructs", + "parameters" : [ + { + "label" : "_", + "name" : "a", + "type" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + }, + { + "label" : "_", + "name" : "b", + "type" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripEnum", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + } + } + ], + "returnType" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripRawEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripRawEnum", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "rawValueEnum" : { + "_0" : "AsyncTheme", + "_1" : "String" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "AsyncTheme", + "_1" : "String" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripOptionalEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripOptionalEnum", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripOptionalRawEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripOptionalRawEnum", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "AsyncTheme", + "_1" : "String" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "AsyncTheme", + "_1" : "String" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripOptionalStruct", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripOptionalStruct", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripStructArray", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripStructArray", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "array" : { + "_0" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + } + } + }, + { + "abiName" : "bjs_asyncRoundTripEnumArray", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripEnumArray", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "array" : { + "_0" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + } + } + } + }, + { + "abiName" : "bjs_asyncRoundTripStructDictionary", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripStructDictionary", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "dictionary" : { + "_0" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "swiftStruct" : { + "_0" : "AsyncPoint" + } + } + } + } + }, + { + "abiName" : "bjs_asyncRoundTripEnumDictionary", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripEnumDictionary", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "dictionary" : { + "_0" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "caseEnum" : { + "_0" : "AsyncDirection" + } + } + } + } } ], "protocols" : [ ], "structs" : [ + { + "methods" : [ + ], + "name" : "AsyncPoint", + "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" : "AsyncPoint" + } ] }, "moduleName" : "TestModule", diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift index f5230f213..28e6d8d8f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift @@ -1,11 +1,96 @@ +extension AsyncDirection: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> AsyncDirection { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> AsyncDirection { + return AsyncDirection(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .north + case 1: + self = .south + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .north: + return 0 + case .south: + return 1 + } + } +} + +extension AsyncTheme: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension AsyncPoint: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> AsyncPoint { + let y = Int.bridgeJSStackPop() + let x = Int.bridgeJSStackPop() + return AsyncPoint(x: x, y: y) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.x.bridgeJSStackPush() + self.y.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_AsyncPoint(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_AsyncPoint())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_AsyncPoint") +fileprivate func _bjs_struct_lower_AsyncPoint_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_AsyncPoint_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_AsyncPoint(_ objectId: Int32) -> Void { + return _bjs_struct_lower_AsyncPoint_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_AsyncPoint") +fileprivate func _bjs_struct_lift_AsyncPoint_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_AsyncPoint_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_AsyncPoint() -> Int32 { + return _bjs_struct_lift_AsyncPoint_extern() +} + @_expose(wasm, "bjs_asyncReturnVoid") @_cdecl("bjs_asyncReturnVoid") public func _bjs_asyncReturnVoid() -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { + return _bjs_makePromise(resolve: Promise_resolve_y, reject: Promise_reject) { await asyncReturnVoid() - }.jsObject - return ret.bridgeJSLowerReturn() + } #else fatalError("Only available on WebAssembly") #endif @@ -15,10 +100,9 @@ public func _bjs_asyncReturnVoid() -> Int32 { @_cdecl("bjs_asyncRoundTripInt") public func _bjs_asyncRoundTripInt(_ v: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripInt(_: Int.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Si, reject: Promise_reject) { + return await asyncRoundTripInt(_: Int.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -28,10 +112,9 @@ public func _bjs_asyncRoundTripInt(_ v: Int32) -> Int32 { @_cdecl("bjs_asyncRoundTripString") public func _bjs_asyncRoundTripString(_ vBytes: Int32, _ vLength: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripString(_: String.bridgeJSLiftParameter(vBytes, vLength)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { + return await asyncRoundTripString(_: String.bridgeJSLiftParameter(vBytes, vLength)) + } #else fatalError("Only available on WebAssembly") #endif @@ -41,10 +124,9 @@ public func _bjs_asyncRoundTripString(_ vBytes: Int32, _ vLength: Int32) -> Int3 @_cdecl("bjs_asyncRoundTripBool") public func _bjs_asyncRoundTripBool(_ v: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripBool(_: Bool.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Sb, reject: Promise_reject) { + return await asyncRoundTripBool(_: Bool.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -54,10 +136,9 @@ public func _bjs_asyncRoundTripBool(_ v: Int32) -> Int32 { @_cdecl("bjs_asyncRoundTripFloat") public func _bjs_asyncRoundTripFloat(_ v: Float32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripFloat(_: Float.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Sf, reject: Promise_reject) { + return await asyncRoundTripFloat(_: Float.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -67,10 +148,9 @@ public func _bjs_asyncRoundTripFloat(_ v: Float32) -> Int32 { @_cdecl("bjs_asyncRoundTripDouble") public func _bjs_asyncRoundTripDouble(_ v: Float64) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripDouble(_: Double.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Sd, reject: Promise_reject) { + return await asyncRoundTripDouble(_: Double.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -80,11 +160,543 @@ public func _bjs_asyncRoundTripDouble(_ v: Float64) -> Int32 { @_cdecl("bjs_asyncRoundTripJSObject") public func _bjs_asyncRoundTripJSObject(_ v: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripJSObject(_: JSObject.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_8JSObjectC, reject: Promise_reject) { + return await asyncRoundTripJSObject(_: JSObject.bridgeJSLiftParameter(v)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripStruct") +@_cdecl("bjs_asyncRoundTripStruct") +public func _bjs_asyncRoundTripStruct() -> Int32 { + #if arch(wasm32) + let _tmp_v = AsyncPoint.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_10AsyncPointV, reject: Promise_reject) { + return await asyncRoundTripStruct(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripStructThrows") +@_cdecl("bjs_asyncRoundTripStructThrows") +public func _bjs_asyncRoundTripStructThrows() -> Int32 { + #if arch(wasm32) + let _tmp_v = AsyncPoint.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_10AsyncPointV, reject: Promise_reject) { () async throws(JSException) -> AsyncPoint in + return try await asyncRoundTripStructThrows(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncCombineStructs") +@_cdecl("bjs_asyncCombineStructs") +public func _bjs_asyncCombineStructs() -> Int32 { + #if arch(wasm32) + let _tmp_b = AsyncPoint.bridgeJSLiftParameter() + let _tmp_a = AsyncPoint.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_10AsyncPointV, reject: Promise_reject) { + return await asyncCombineStructs(_: _tmp_a, _: _tmp_b) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripEnum") +@_cdecl("bjs_asyncRoundTripEnum") +public func _bjs_asyncRoundTripEnum(_ v: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_14AsyncDirectionO, reject: Promise_reject) { + return await asyncRoundTripEnum(_: AsyncDirection.bridgeJSLiftParameter(v)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripRawEnum") +@_cdecl("bjs_asyncRoundTripRawEnum") +public func _bjs_asyncRoundTripRawEnum(_ vBytes: Int32, _ vLength: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_10AsyncThemeO, reject: Promise_reject) { + return await asyncRoundTripRawEnum(_: AsyncTheme.bridgeJSLiftParameter(vBytes, vLength)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalEnum") +@_cdecl("bjs_asyncRoundTripOptionalEnum") +public func _bjs_asyncRoundTripOptionalEnum(_ vIsSome: Int32, _ vValue: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_Sq14AsyncDirectionO, reject: Promise_reject) { + return await asyncRoundTripOptionalEnum(_: Optional.bridgeJSLiftParameter(vIsSome, vValue)) + } #else fatalError("Only available on WebAssembly") #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalRawEnum") +@_cdecl("bjs_asyncRoundTripOptionalRawEnum") +public func _bjs_asyncRoundTripOptionalRawEnum(_ vIsSome: Int32, _ vBytes: Int32, _ vLength: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_Sq10AsyncThemeO, reject: Promise_reject) { + return await asyncRoundTripOptionalRawEnum(_: Optional.bridgeJSLiftParameter(vIsSome, vBytes, vLength)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalStruct") +@_cdecl("bjs_asyncRoundTripOptionalStruct") +public func _bjs_asyncRoundTripOptionalStruct() -> Int32 { + #if arch(wasm32) + let _tmp_v = Optional.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_Sq10AsyncPointV, reject: Promise_reject) { + return await asyncRoundTripOptionalStruct(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripStructArray") +@_cdecl("bjs_asyncRoundTripStructArray") +public func _bjs_asyncRoundTripStructArray() -> Int32 { + #if arch(wasm32) + let _tmp_v = [AsyncPoint].bridgeJSStackPop() + return _bjs_makePromise(resolve: Promise_resolve_Sa10AsyncPointV, reject: Promise_reject) { + return await asyncRoundTripStructArray(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripEnumArray") +@_cdecl("bjs_asyncRoundTripEnumArray") +public func _bjs_asyncRoundTripEnumArray() -> Int32 { + #if arch(wasm32) + let _tmp_v = [AsyncDirection].bridgeJSStackPop() + return _bjs_makePromise(resolve: Promise_resolve_Sa14AsyncDirectionO, reject: Promise_reject) { + return await asyncRoundTripEnumArray(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripStructDictionary") +@_cdecl("bjs_asyncRoundTripStructDictionary") +public func _bjs_asyncRoundTripStructDictionary() -> Int32 { + #if arch(wasm32) + let _tmp_v = [String: AsyncPoint].bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_SD10AsyncPointV, reject: Promise_reject) { + return await asyncRoundTripStructDictionary(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripEnumDictionary") +@_cdecl("bjs_asyncRoundTripEnumDictionary") +public func _bjs_asyncRoundTripEnumDictionary() -> Int32 { + #if arch(wasm32) + let _tmp_v = [String: AsyncDirection].bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_SD14AsyncDirectionO, reject: Promise_reject) { + return await asyncRoundTripEnumDictionary(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_reject_TestModule") +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void +#else +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_reject_TestModule(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + return promise_reject_TestModule_extern(promise, valueKind, valuePayload1, valuePayload2) +} + +func _$Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueKind, valuePayload1, valuePayload2) = value.bridgeJSLowerParameter() + promise_reject_TestModule(promiseValue, valueKind, valuePayload1, valuePayload2) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_y(_ promise: JSObject) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_y") +fileprivate func promise_resolve_TestModule_y_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_y_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_y(_ promise: Int32) -> Void { + return promise_resolve_TestModule_y_extern(promise) +} + +func _$Promise_resolve_y(_ promise: JSObject) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + promise_resolve_TestModule_y(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Si(_ promise: JSObject, _ value: Int) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Si") +fileprivate func promise_resolve_TestModule_Si_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Si_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Si(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_Si_extern(promise, value) +} + +func _$Promise_resolve_Si(_ promise: JSObject, _ value: Int) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Si(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_SS") +fileprivate func promise_resolve_TestModule_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_SS(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_TestModule_SS_extern(promise, valueBytes, valueLength) +} + +func _$Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + promise_resolve_TestModule_SS(promiseValue, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sb(_ promise: JSObject, _ value: Bool) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sb") +fileprivate func promise_resolve_TestModule_Sb_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sb_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sb(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_Sb_extern(promise, value) +} + +func _$Promise_resolve_Sb(_ promise: JSObject, _ value: Bool) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sb(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sf(_ promise: JSObject, _ value: Float) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sf") +fileprivate func promise_resolve_TestModule_Sf_extern(_ promise: Int32, _ value: Float32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sf_extern(_ promise: Int32, _ value: Float32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sf(_ promise: Int32, _ value: Float32) -> Void { + return promise_resolve_TestModule_Sf_extern(promise, value) +} + +func _$Promise_resolve_Sf(_ promise: JSObject, _ value: Float) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sf(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sd(_ promise: JSObject, _ value: Double) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sd") +fileprivate func promise_resolve_TestModule_Sd_extern(_ promise: Int32, _ value: Float64) -> Void +#else +fileprivate func promise_resolve_TestModule_Sd_extern(_ promise: Int32, _ value: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sd(_ promise: Int32, _ value: Float64) -> Void { + return promise_resolve_TestModule_Sd_extern(promise, value) +} + +func _$Promise_resolve_Sd(_ promise: JSObject, _ value: Double) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sd(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_8JSObjectC(_ promise: JSObject, _ value: JSObject) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_8JSObjectC") +fileprivate func promise_resolve_TestModule_8JSObjectC_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_8JSObjectC_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_8JSObjectC(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_8JSObjectC_extern(promise, value) +} + +func _$Promise_resolve_8JSObjectC(_ promise: JSObject, _ value: JSObject) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_TestModule_8JSObjectC(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_10AsyncPointV(_ promise: JSObject, _ value: AsyncPoint) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_10AsyncPointV") +fileprivate func promise_resolve_TestModule_10AsyncPointV_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_10AsyncPointV_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_10AsyncPointV(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_10AsyncPointV_extern(promise, value) +} + +func _$Promise_resolve_10AsyncPointV(_ promise: JSObject, _ value: AsyncPoint) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueObjectId = value.bridgeJSLowerParameter() + promise_resolve_TestModule_10AsyncPointV(promiseValue, valueObjectId) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_14AsyncDirectionO(_ promise: JSObject, _ value: AsyncDirection) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_14AsyncDirectionO") +fileprivate func promise_resolve_TestModule_14AsyncDirectionO_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_14AsyncDirectionO_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_14AsyncDirectionO(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_14AsyncDirectionO_extern(promise, value) +} + +func _$Promise_resolve_14AsyncDirectionO(_ promise: JSObject, _ value: AsyncDirection) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_TestModule_14AsyncDirectionO(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_10AsyncThemeO(_ promise: JSObject, _ value: AsyncTheme) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_10AsyncThemeO") +fileprivate func promise_resolve_TestModule_10AsyncThemeO_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_10AsyncThemeO_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_10AsyncThemeO(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_TestModule_10AsyncThemeO_extern(promise, valueBytes, valueLength) +} + +func _$Promise_resolve_10AsyncThemeO(_ promise: JSObject, _ value: AsyncTheme) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + promise_resolve_TestModule_10AsyncThemeO(promiseValue, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq14AsyncDirectionO(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sq14AsyncDirectionO") +fileprivate func promise_resolve_TestModule_Sq14AsyncDirectionO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sq14AsyncDirectionO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sq14AsyncDirectionO(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + return promise_resolve_TestModule_Sq14AsyncDirectionO_extern(promise, valueIsSome, valueValue) +} + +func _$Promise_resolve_Sq14AsyncDirectionO(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sq14AsyncDirectionO(promiseValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq10AsyncThemeO(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sq10AsyncThemeO") +fileprivate func promise_resolve_TestModule_Sq10AsyncThemeO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sq10AsyncThemeO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sq10AsyncThemeO(_ promise: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_TestModule_Sq10AsyncThemeO_extern(promise, valueIsSome, valueBytes, valueLength) +} + +func _$Promise_resolve_Sq10AsyncThemeO(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueIsSome, valueBytes, valueLength) in + promise_resolve_TestModule_Sq10AsyncThemeO(promiseValue, valueIsSome, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq10AsyncPointV(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sq10AsyncPointV") +fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sq10AsyncPointV(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_Sq10AsyncPointV_extern(promise, value) +} + +func _$Promise_resolve_Sq10AsyncPointV(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueIsSome = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sq10AsyncPointV(promiseValue, valueIsSome) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sa10AsyncPointV(_ promise: JSObject, _ value: [AsyncPoint]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sa10AsyncPointV") +fileprivate func promise_resolve_TestModule_Sa10AsyncPointV_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sa10AsyncPointV_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sa10AsyncPointV(_ promise: Int32) -> Void { + return promise_resolve_TestModule_Sa10AsyncPointV_extern(promise) +} + +func _$Promise_resolve_Sa10AsyncPointV(_ promise: JSObject, _ value: [AsyncPoint]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sa10AsyncPointV(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sa14AsyncDirectionO(_ promise: JSObject, _ value: [AsyncDirection]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sa14AsyncDirectionO") +fileprivate func promise_resolve_TestModule_Sa14AsyncDirectionO_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sa14AsyncDirectionO_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sa14AsyncDirectionO(_ promise: Int32) -> Void { + return promise_resolve_TestModule_Sa14AsyncDirectionO_extern(promise) +} + +func _$Promise_resolve_Sa14AsyncDirectionO(_ promise: JSObject, _ value: [AsyncDirection]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sa14AsyncDirectionO(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SD10AsyncPointV(_ promise: JSObject, _ value: [String: AsyncPoint]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_SD10AsyncPointV") +fileprivate func promise_resolve_TestModule_SD10AsyncPointV_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_SD10AsyncPointV_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_SD10AsyncPointV(_ promise: Int32) -> Void { + return promise_resolve_TestModule_SD10AsyncPointV_extern(promise) +} + +func _$Promise_resolve_SD10AsyncPointV(_ promise: JSObject, _ value: [String: AsyncPoint]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_TestModule_SD10AsyncPointV(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SD14AsyncDirectionO(_ promise: JSObject, _ value: [String: AsyncDirection]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_SD14AsyncDirectionO") +fileprivate func promise_resolve_TestModule_SD14AsyncDirectionO_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_SD14AsyncDirectionO_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_SD14AsyncDirectionO(_ promise: Int32) -> Void { + return promise_resolve_TestModule_SD14AsyncDirectionO_extern(promise) +} + +func _$Promise_resolve_SD14AsyncDirectionO(_ promise: JSObject, _ value: [String: AsyncDirection]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_TestModule_SD14AsyncDirectionO(promiseValue) + if let error = _swift_js_take_exception() { throw error } } \ 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 ad0111929..75d961e98 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -138,6 +138,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts index aecab090e..ddf722a3a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts @@ -4,6 +4,26 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. +export const AsyncDirectionValues: { + readonly North: 0; + readonly South: 1; +}; +export type AsyncDirectionTag = typeof AsyncDirectionValues[keyof typeof AsyncDirectionValues]; + +export const AsyncThemeValues: { + readonly Light: "light"; + readonly Dark: "dark"; +}; +export type AsyncThemeTag = typeof AsyncThemeValues[keyof typeof AsyncThemeValues]; + +export interface AsyncPoint { + x: number; + y: number; +} +export type AsyncDirectionObject = typeof AsyncDirectionValues; + +export type AsyncThemeObject = typeof AsyncThemeValues; + export type Exports = { asyncReturnVoid(): Promise; asyncRoundTripInt(v: number): Promise; @@ -12,6 +32,20 @@ export type Exports = { asyncRoundTripFloat(v: number): Promise; asyncRoundTripDouble(v: number): Promise; asyncRoundTripJSObject(v: any): Promise; + asyncRoundTripStruct(v: AsyncPoint): Promise; + asyncRoundTripStructThrows(v: AsyncPoint): Promise; + asyncCombineStructs(a: AsyncPoint, b: AsyncPoint): Promise; + asyncRoundTripEnum(v: AsyncDirectionTag): Promise; + asyncRoundTripRawEnum(v: AsyncThemeTag): Promise; + asyncRoundTripOptionalEnum(v: AsyncDirectionTag | null): Promise; + asyncRoundTripOptionalRawEnum(v: AsyncThemeTag | null): Promise; + asyncRoundTripOptionalStruct(v: AsyncPoint | null): Promise; + asyncRoundTripStructArray(v: AsyncPoint[]): Promise; + asyncRoundTripEnumArray(v: AsyncDirectionTag[]): Promise; + asyncRoundTripStructDictionary(v: Record): Promise>; + asyncRoundTripEnumDictionary(v: Record): Promise>; + AsyncDirection: AsyncDirectionObject + AsyncTheme: AsyncThemeObject } export type Imports = { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index a4c42674e..887102a76 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -4,6 +4,16 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. +export const AsyncDirectionValues = { + North: 0, + South: 1, +}; + +export const AsyncThemeValues = { + Light: "light", + Dark: "dark", +}; + export async function createInstantiator(options, swift) { let instance; let memory; @@ -31,6 +41,106 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + 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_createAsyncPointHelpers = () => ({ + 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 }; + } + }); return { /** @@ -106,6 +216,203 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + bjs["swift_js_struct_lower_AsyncPoint"] = function(objectId) { + structHelpers.AsyncPoint.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_AsyncPoint"] = function() { + const value = structHelpers.AsyncPoint.lift(); + return swift.memory.retain(value); + } + 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["promise_resolve_TestModule_y"] = function(promise) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Si"] = function(promise, value) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(value); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_SS"] = function(promise, valueBytes, valueCount) { + try { + const string = decodeString(valueBytes, valueCount); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(string); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Sb"] = function(promise, value) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(value !== 0); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Sf"] = function(promise, value) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(value); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Sd"] = function(promise, value) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(value); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_8JSObjectC"] = function(promise, value) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(swift.memory.getObject(value)); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_10AsyncPointV"] = function(promise, value) { + try { + const value1 = swift.memory.getObject(value); + swift.memory.release(value); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(value1); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_14AsyncDirectionO"] = function(promise, value) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(value); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_10AsyncThemeO"] = function(promise, valueBytes, valueCount) { + try { + const string = decodeString(valueBytes, valueCount); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(string); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Sq14AsyncDirectionO"] = function(promise, valueIsSome, valueWrappedValue) { + try { + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(valueIsSome ? valueWrappedValue : null); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Sq10AsyncThemeO"] = function(promise, valueIsSome, valueBytes, valueCount) { + try { + let optResult; + if (valueIsSome) { + const string = decodeString(valueBytes, valueCount); + optResult = string; + } else { + optResult = null; + } + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(optResult); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Sq10AsyncPointV"] = function(promise, value) { + try { + let optResult; + if (value) { + const struct = structHelpers.AsyncPoint.lift(); + optResult = struct; + } else { + optResult = null; + } + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(optResult); + } catch (error) { + setException(error); + } + } + 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(); + } + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); + } catch (error) { + setException(error); + } + } + 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 caseId = i32Stack.pop(); + arrayResult.push(caseId); + } + arrayResult.reverse(); + } + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(arrayResult); + } catch (error) { + setException(error); + } + } + 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; + } + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); + } catch (error) { + setException(error); + } + } + 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; + } + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(dictResult); + } catch (error) { + setException(error); + } + } + bjs["promise_reject_TestModule"] = function(promise, valueKind, valuePayload1, valuePayload2) { + try { + const jsValue = __bjs_jsValueLift(valueKind, valuePayload1, valuePayload2); + swift.memory.getObject(promise)[__bjs_promiseSettlers].reject(jsValue); + } catch (error) { + setException(error); + } + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -210,6 +517,9 @@ 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 exports = { asyncReturnVoid: function bjs_asyncReturnVoid() { const ret = instance.exports.bjs_asyncReturnVoid(); @@ -255,6 +565,137 @@ export async function createInstantiator(options, swift) { swift.memory.release(ret); return ret1; }, + asyncRoundTripStruct: function bjs_asyncRoundTripStruct(v) { + structHelpers.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); + const ret = instance.exports.bjs_asyncRoundTripStructThrows(); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }, + asyncCombineStructs: function bjs_asyncCombineStructs(a, b) { + structHelpers.AsyncPoint.lower(a); + structHelpers.AsyncPoint.lower(b); + const ret = instance.exports.bjs_asyncCombineStructs(); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + asyncRoundTripEnum: function bjs_asyncRoundTripEnum(v) { + const ret = instance.exports.bjs_asyncRoundTripEnum(v); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + asyncRoundTripRawEnum: function bjs_asyncRoundTripRawEnum(v) { + const vBytes = textEncoder.encode(v); + const vId = swift.memory.retain(vBytes); + const ret = instance.exports.bjs_asyncRoundTripRawEnum(vId, vBytes.length); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + asyncRoundTripOptionalEnum: function bjs_asyncRoundTripOptionalEnum(v) { + const isSome = v != null; + const ret = instance.exports.bjs_asyncRoundTripOptionalEnum(+isSome, isSome ? v : 0); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + asyncRoundTripOptionalRawEnum: function bjs_asyncRoundTripOptionalRawEnum(v) { + const isSome = v != null; + let result, result1; + if (isSome) { + const vBytes = textEncoder.encode(v); + const vId = swift.memory.retain(vBytes); + result = vId; + result1 = vBytes.length; + } else { + result = 0; + result1 = 0; + } + const ret = instance.exports.bjs_asyncRoundTripOptionalRawEnum(+isSome, result, result1); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + asyncRoundTripOptionalStruct: function bjs_asyncRoundTripOptionalStruct(v) { + const isSome = v != null; + if (isSome) { + structHelpers.AsyncPoint.lower(v); + } + i32Stack.push(+isSome); + 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); + 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 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); + 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 ret = instance.exports.bjs_asyncRoundTripEnumDictionary(); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + AsyncDirection: AsyncDirectionValues, + AsyncTheme: AsyncThemeValues, }; _exports = exports; return exports; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js index fd27e3d67..27e53b8d7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js @@ -221,6 +221,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js index 6b6698377..789379a32 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js @@ -220,6 +220,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index 8f8463bf0..4b13bb633 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -162,6 +162,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.MathOperations.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index d040df41c..2021f1c96 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -154,6 +154,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Counters.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 23819a6e8..d97e4ef11 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -856,6 +856,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index 5272717ec..b4c5870b6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -130,6 +130,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js index e232c7cbb..dc1b3c6b3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCaseImport.js @@ -111,6 +111,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index ecf121aa4..050c16b18 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -150,6 +150,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index 247a11e54..9f2f4122c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -131,6 +131,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 4e4449e06..2ab98b31b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -182,6 +182,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js index 211cbefa3..94bfe89cd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js index f5895589d..174c9b430 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js index 77e8002f8..e8a89c6e4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js index db876ff02..99c0bb4ea 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js index ca958e564..82458b81a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js index ca958e564..82458b81a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 613d4a10b..8ebcbda28 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index ab4b4b34d..710eebe36 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -152,6 +152,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.FooContainer.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js index 59c8be11d..605359fb8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js index f3293ae52..e24b5dac5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js index ef666149b..b936636a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js index b12640234..c5c37a512 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSTypedArrayTypes.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 71e66827e..e8f617e5b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -196,6 +196,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index 6c3ddb555..3abacf371 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index 70f1575b4..a2dc23d68 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index 16ec9433c..7fdf9b4c8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index d698857d3..09a6ace60 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 92b8f5dae..1c9287a08 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index 33b4e60c1..7c2751964 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -145,6 +145,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Player_Stats.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index f376c1b24..c045286ae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js index 97c1a44fe..3957b5482 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js index a140ea232..e624ceb1a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index b8116a32f..6e66102e2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index d992bf75d..ac533b6d4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -163,6 +163,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js index 89f84d29a..102ac6020 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -131,6 +131,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 32a739587..5257c9856 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -150,6 +150,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 16cf2881f..91316a8c4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -150,6 +150,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index b616665ca..f238551a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -111,6 +111,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index f6e1fdbce..c7f9b4955 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -111,6 +111,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js index 885c0980f..994e1710a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js index aab8b67fe..839e194cf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 88f04efe9..5ee56f5bc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index c82bc5b8d..cdd80e90a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -241,6 +241,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Animal.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index cffbdcf67..6fd627dcb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -132,6 +132,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index d55d5c095..aa523be20 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -375,6 +375,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Vector2D.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index 17bf086ff..44b7c5527 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -125,6 +125,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.Point.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js index 2b51ebd3b..f07b00968 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js @@ -131,6 +131,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js index 9c41c3061..d1036cba4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js @@ -106,6 +106,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index 97a00c278..54276025b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -130,6 +130,13 @@ export async function createInstantiator(options, swift) { const value = structHelpers.PointerFields.lift(); return swift.memory.retain(value); } + 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; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js index 2951ef5f8..755165ee1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js @@ -107,6 +107,13 @@ export async function createInstantiator(options, swift) { const copy = memory.buffer.slice(ptr, ptr + byteLen); taStack.push(Array.from(new Ctor(copy))); } + 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; diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 88e322538..36d840099 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -69,6 +69,7 @@ async function createInstantiator(options, swift) { swift_js_pop_i64: unexpectedBjsCall, swift_js_closure_unregister: unexpectedBjsCall, swift_js_push_typed_array: unexpectedBjsCall, + swift_js_make_promise: unexpectedBjsCall, }; }, /** @param {WebAssembly.Instance} instance */ diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index ff586b45b..e39e6f2fa 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -2286,3 +2286,67 @@ extension _BridgedAsOptional { throw error } } + +// MARK: Async Promise Creation + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_make_promise") +private func _swift_js_make_promise_extern() -> Int32 +#else +private func _swift_js_make_promise_extern() -> Int32 { _onlyAvailableOnWasm() } +#endif + +// `@unchecked Sendable` is safe because the Wasm runtime is single-threaded. +private struct _BridgeJSMakePromiseContext: @unchecked Sendable { + let promise: JSObject + let resolve: (JSObject, T) throws(JSException) -> Void + let reject: (JSObject, JSValue) throws(JSException) -> Void + let body: () async throws(JSException) -> T +} + +/// Returns a `Promise` synchronously and settles it from a `Task` via the generated +/// `resolve` / `reject` thunks, which this library cannot name directly. +@_spi(BridgeJS) public func _bjs_makePromise( + resolve: @escaping (JSObject, T) throws(JSException) -> Void, + reject: @escaping (JSObject, JSValue) throws(JSException) -> Void, + _ body: @escaping () async throws(JSException) -> T +) -> Int32 { + let promise = JSObject(id: JavaScriptObjectRef(bitPattern: _swift_js_make_promise_extern())) + let context = _BridgeJSMakePromiseContext(promise: promise, resolve: resolve, reject: reject, body: body) + Task { + do throws(JSException) { + let value = try await context.body() + try context.resolve(context.promise, value) + } catch { + try? context.reject(context.promise, error.thrownValue) + } + } + return promise.bridgeJSLowerReturn() +} + +private struct _BridgeJSMakeVoidPromiseContext: @unchecked Sendable { + let promise: JSObject + let resolve: (JSObject) throws(JSException) -> Void + let reject: (JSObject, JSValue) throws(JSException) -> Void + let body: () async throws(JSException) -> Void +} + +/// `Void`-returning overload: a `Void` value can't cross the bridge as a parameter, so the +/// generated `resolve` thunk takes only the promise and settles it with `undefined`. +@_spi(BridgeJS) public func _bjs_makePromise( + resolve: @escaping (JSObject) throws(JSException) -> Void, + reject: @escaping (JSObject, JSValue) throws(JSException) -> Void, + _ body: @escaping () async throws(JSException) -> Void +) -> Int32 { + let promise = JSObject(id: JavaScriptObjectRef(bitPattern: _swift_js_make_promise_extern())) + let context = _BridgeJSMakeVoidPromiseContext(promise: promise, resolve: resolve, reject: reject, body: body) + Task { + do throws(JSException) { + try await context.body() + try context.resolve(context.promise) + } catch { + try? context.reject(context.promise, error.thrownValue) + } + } + return promise.bridgeJSLowerReturn() +} diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index c6e216203..1529a051b 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -174,6 +174,10 @@ extension Greeter { return a + b } + @JS func asyncMakePoint(x: Int, y: Int) async -> PublicPoint { + return PublicPoint(x: x, y: y) + } + deinit { Self.onDeinit() } @@ -302,6 +306,26 @@ extension StaticCalculator { return .light } +@JS func asyncRoundTripTheme(_ v: Theme) async -> Theme { v } + +@JS func asyncRoundTripDirection(_ v: Direction) async -> Direction { v } + +@JS func asyncRoundTripOptionalTheme(_ v: Theme?) async -> Theme? { v } + +@JS func asyncRoundTripOptionalDirection(_ v: Direction?) async -> Direction? { v } + +@JS func asyncRoundTripDirectionArray(_ v: [Direction]) async -> [Direction] { v } + +@JS func asyncRoundTripDirectionDict(_ v: [String: Direction]) async -> [String: Direction] { v } + +@JS func asyncRoundTripThemeArray(_ v: [Theme]) async -> [Theme] { v } + +@JS func asyncRoundTripThemeDict(_ v: [String: Theme]) async -> [String: Theme] { v } + +@JS func asyncRoundTripFileSize(_ v: FileSize) async -> FileSize { v } + +@JS func asyncRoundTripOptionalFileSize(_ v: FileSize?) async -> FileSize? { v } + @JS func setHttpStatus(_ status: HttpStatus) -> HttpStatus { return status } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index e6c2f940b..3fd09d496 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -7182,10 +7182,9 @@ public func _bjs_throwsWithJSObjectResult() -> Int32 { @_cdecl("bjs_asyncRoundTripVoid") public func _bjs_asyncRoundTripVoid() -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { + return _bjs_makePromise(resolve: Promise_resolve_y, reject: Promise_reject) { await asyncRoundTripVoid() - }.jsObject - return ret.bridgeJSLowerReturn() + } #else fatalError("Only available on WebAssembly") #endif @@ -7195,10 +7194,9 @@ public func _bjs_asyncRoundTripVoid() -> Int32 { @_cdecl("bjs_asyncRoundTripInt") public func _bjs_asyncRoundTripInt(_ v: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripInt(v: Int.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Si, reject: Promise_reject) { + return await asyncRoundTripInt(v: Int.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -7208,10 +7206,9 @@ public func _bjs_asyncRoundTripInt(_ v: Int32) -> Int32 { @_cdecl("bjs_asyncRoundTripFloat") public func _bjs_asyncRoundTripFloat(_ v: Float32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripFloat(v: Float.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Sf, reject: Promise_reject) { + return await asyncRoundTripFloat(v: Float.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -7221,10 +7218,9 @@ public func _bjs_asyncRoundTripFloat(_ v: Float32) -> Int32 { @_cdecl("bjs_asyncRoundTripDouble") public func _bjs_asyncRoundTripDouble(_ v: Float64) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripDouble(v: Double.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Sd, reject: Promise_reject) { + return await asyncRoundTripDouble(v: Double.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -7234,10 +7230,9 @@ public func _bjs_asyncRoundTripDouble(_ v: Float64) -> Int32 { @_cdecl("bjs_asyncRoundTripBool") public func _bjs_asyncRoundTripBool(_ v: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripBool(v: Bool.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_Sb, reject: Promise_reject) { + return await asyncRoundTripBool(v: Bool.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -7247,10 +7242,9 @@ public func _bjs_asyncRoundTripBool(_ v: Int32) -> Int32 { @_cdecl("bjs_asyncRoundTripString") public func _bjs_asyncRoundTripString(_ vBytes: Int32, _ vLength: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripString(v: String.bridgeJSLiftParameter(vBytes, vLength)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { + return await asyncRoundTripString(v: String.bridgeJSLiftParameter(vBytes, vLength)) + } #else fatalError("Only available on WebAssembly") #endif @@ -7260,10 +7254,9 @@ public func _bjs_asyncRoundTripString(_ vBytes: Int32, _ vLength: Int32) -> Int3 @_cdecl("bjs_asyncRoundTripSwiftHeapObject") public func _bjs_asyncRoundTripSwiftHeapObject(_ v: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripSwiftHeapObject(v: Greeter.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_7GreeterC, reject: Promise_reject) { + return await asyncRoundTripSwiftHeapObject(v: Greeter.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -7273,10 +7266,9 @@ public func _bjs_asyncRoundTripSwiftHeapObject(_ v: UnsafeMutableRawPointer) -> @_cdecl("bjs_asyncRoundTripJSObject") public func _bjs_asyncRoundTripJSObject(_ v: Int32) -> Int32 { #if arch(wasm32) - let ret = JSPromise.async { - return await asyncRoundTripJSObject(v: JSObject.bridgeJSLiftParameter(v)).jsValue - }.jsObject - return ret.bridgeJSLowerReturn() + return _bjs_makePromise(resolve: Promise_resolve_8JSObjectC, reject: Promise_reject) { + return await asyncRoundTripJSObject(v: JSObject.bridgeJSLiftParameter(v)) + } #else fatalError("Only available on WebAssembly") #endif @@ -7402,6 +7394,130 @@ public func _bjs_getTheme() -> Void { #endif } +@_expose(wasm, "bjs_asyncRoundTripTheme") +@_cdecl("bjs_asyncRoundTripTheme") +public func _bjs_asyncRoundTripTheme(_ vBytes: Int32, _ vLength: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_5ThemeO, reject: Promise_reject) { + return await asyncRoundTripTheme(_: Theme.bridgeJSLiftParameter(vBytes, vLength)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripDirection") +@_cdecl("bjs_asyncRoundTripDirection") +public func _bjs_asyncRoundTripDirection(_ v: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_9DirectionO, reject: Promise_reject) { + return await asyncRoundTripDirection(_: Direction.bridgeJSLiftParameter(v)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalTheme") +@_cdecl("bjs_asyncRoundTripOptionalTheme") +public func _bjs_asyncRoundTripOptionalTheme(_ vIsSome: Int32, _ vBytes: Int32, _ vLength: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_Sq5ThemeO, reject: Promise_reject) { + return await asyncRoundTripOptionalTheme(_: Optional.bridgeJSLiftParameter(vIsSome, vBytes, vLength)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalDirection") +@_cdecl("bjs_asyncRoundTripOptionalDirection") +public func _bjs_asyncRoundTripOptionalDirection(_ vIsSome: Int32, _ vValue: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_Sq9DirectionO, reject: Promise_reject) { + return await asyncRoundTripOptionalDirection(_: Optional.bridgeJSLiftParameter(vIsSome, vValue)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripDirectionArray") +@_cdecl("bjs_asyncRoundTripDirectionArray") +public func _bjs_asyncRoundTripDirectionArray() -> Int32 { + #if arch(wasm32) + let _tmp_v = [Direction].bridgeJSStackPop() + return _bjs_makePromise(resolve: Promise_resolve_Sa9DirectionO, reject: Promise_reject) { + return await asyncRoundTripDirectionArray(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripDirectionDict") +@_cdecl("bjs_asyncRoundTripDirectionDict") +public func _bjs_asyncRoundTripDirectionDict() -> Int32 { + #if arch(wasm32) + let _tmp_v = [String: Direction].bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_SD9DirectionO, reject: Promise_reject) { + return await asyncRoundTripDirectionDict(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripThemeArray") +@_cdecl("bjs_asyncRoundTripThemeArray") +public func _bjs_asyncRoundTripThemeArray() -> Int32 { + #if arch(wasm32) + let _tmp_v = [Theme].bridgeJSStackPop() + return _bjs_makePromise(resolve: Promise_resolve_Sa5ThemeO, reject: Promise_reject) { + return await asyncRoundTripThemeArray(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripThemeDict") +@_cdecl("bjs_asyncRoundTripThemeDict") +public func _bjs_asyncRoundTripThemeDict() -> Int32 { + #if arch(wasm32) + let _tmp_v = [String: Theme].bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_SD5ThemeO, reject: Promise_reject) { + return await asyncRoundTripThemeDict(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripFileSize") +@_cdecl("bjs_asyncRoundTripFileSize") +public func _bjs_asyncRoundTripFileSize(_ v: Int64) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_8FileSizeO, reject: Promise_reject) { + return await asyncRoundTripFileSize(_: FileSize.bridgeJSLiftParameter(v)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalFileSize") +@_cdecl("bjs_asyncRoundTripOptionalFileSize") +public func _bjs_asyncRoundTripOptionalFileSize(_ vIsSome: Int32, _ vValue: Int64) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_Sq8FileSizeO, reject: Promise_reject) { + return await asyncRoundTripOptionalFileSize(_: Optional.bridgeJSLiftParameter(vIsSome, vValue)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_setHttpStatus") @_cdecl("bjs_setHttpStatus") public func _bjs_setHttpStatus(_ status: Int32) -> Int32 { @@ -8050,6 +8166,110 @@ public func _bjs_roundTripPublicPoint() -> Void { #endif } +@_expose(wasm, "bjs_asyncRoundTripPublicPoint") +@_cdecl("bjs_asyncRoundTripPublicPoint") +public func _bjs_asyncRoundTripPublicPoint() -> Int32 { + #if arch(wasm32) + let _tmp_point = PublicPoint.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_11PublicPointV, reject: Promise_reject) { + return await asyncRoundTripPublicPoint(_: _tmp_point) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripPublicPointThrows") +@_cdecl("bjs_asyncRoundTripPublicPointThrows") +public func _bjs_asyncRoundTripPublicPointThrows() -> Int32 { + #if arch(wasm32) + let _tmp_point = PublicPoint.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_11PublicPointV, reject: Promise_reject) { () async throws(JSException) -> PublicPoint in + return try await asyncRoundTripPublicPointThrows(_: _tmp_point) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncStructOrThrow") +@_cdecl("bjs_asyncStructOrThrow") +public func _bjs_asyncStructOrThrow(_ shouldThrow: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_11PublicPointV, reject: Promise_reject) { () async throws(JSException) -> PublicPoint in + return try await asyncStructOrThrow(_: Bool.bridgeJSLiftParameter(shouldThrow)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncCombinePublicPoints") +@_cdecl("bjs_asyncCombinePublicPoints") +public func _bjs_asyncCombinePublicPoints() -> Int32 { + #if arch(wasm32) + let _tmp_b = PublicPoint.bridgeJSLiftParameter() + let _tmp_a = PublicPoint.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_11PublicPointV, reject: Promise_reject) { + return await asyncCombinePublicPoints(_: _tmp_a, _: _tmp_b) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripContact") +@_cdecl("bjs_asyncRoundTripContact") +public func _bjs_asyncRoundTripContact() -> Int32 { + #if arch(wasm32) + let _tmp_contact = Contact.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_7ContactV, reject: Promise_reject) { + return await asyncRoundTripContact(_: _tmp_contact) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripPublicPointArray") +@_cdecl("bjs_asyncRoundTripPublicPointArray") +public func _bjs_asyncRoundTripPublicPointArray() -> Int32 { + #if arch(wasm32) + let _tmp_points = [PublicPoint].bridgeJSStackPop() + return _bjs_makePromise(resolve: Promise_resolve_Sa11PublicPointV, reject: Promise_reject) { + return await asyncRoundTripPublicPointArray(_: _tmp_points) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalPublicPoint") +@_cdecl("bjs_asyncRoundTripOptionalPublicPoint") +public func _bjs_asyncRoundTripOptionalPublicPoint() -> Int32 { + #if arch(wasm32) + let _tmp_point = Optional.bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_Sq11PublicPointV, reject: Promise_reject) { + return await asyncRoundTripOptionalPublicPoint(_: _tmp_point) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripPublicPointDict") +@_cdecl("bjs_asyncRoundTripPublicPointDict") +public func _bjs_asyncRoundTripPublicPointDict() -> Int32 { + #if arch(wasm32) + let _tmp_points = [String: PublicPoint].bridgeJSLiftParameter() + return _bjs_makePromise(resolve: Promise_resolve_SD11PublicPointV, reject: Promise_reject) { + return await asyncRoundTripPublicPointDict(_: _tmp_points) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundTripContact") @_cdecl("bjs_roundTripContact") public func _bjs_roundTripContact() -> Void { @@ -8659,6 +8879,18 @@ public func _bjs_Calculator_add(_ _self: UnsafeMutableRawPointer, _ a: Int32, _ #endif } +@_expose(wasm, "bjs_Calculator_asyncMakePoint") +@_cdecl("bjs_Calculator_asyncMakePoint") +public func _bjs_Calculator_asyncMakePoint(_ _self: UnsafeMutableRawPointer, _ x: Int32, _ y: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_11PublicPointV, reject: Promise_reject) { + return await Calculator.bridgeJSLiftParameter(_self).asyncMakePoint(x: Int.bridgeJSLiftParameter(x), y: Int.bridgeJSLiftParameter(y)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Calculator_deinit") @_cdecl("bjs_Calculator_deinit") public func _bjs_Calculator_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { @@ -11139,6 +11371,512 @@ fileprivate func _bjs_LeakCheck_wrap_extern(_ pointer: UnsafeMutableRawPointer) return _bjs_LeakCheck_wrap_extern(pointer) } +@JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_reject_BridgeJSRuntimeTests") +fileprivate func promise_reject_BridgeJSRuntimeTests_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void +#else +fileprivate func promise_reject_BridgeJSRuntimeTests_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_reject_BridgeJSRuntimeTests(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + return promise_reject_BridgeJSRuntimeTests_extern(promise, valueKind, valuePayload1, valuePayload2) +} + +func _$Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueKind, valuePayload1, valuePayload2) = value.bridgeJSLowerParameter() + promise_reject_BridgeJSRuntimeTests(promiseValue, valueKind, valuePayload1, valuePayload2) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_y(_ promise: JSObject) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_y") +fileprivate func promise_resolve_BridgeJSRuntimeTests_y_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_y_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_y(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_y_extern(promise) +} + +func _$Promise_resolve_y(_ promise: JSObject) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_y(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Si(_ promise: JSObject, _ value: Int) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Si") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Si_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Si_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Si(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Si_extern(promise, value) +} + +func _$Promise_resolve_Si(_ promise: JSObject, _ value: Int) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Si(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sf(_ promise: JSObject, _ value: Float) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sf") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sf_extern(_ promise: Int32, _ value: Float32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sf_extern(_ promise: Int32, _ value: Float32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sf(_ promise: Int32, _ value: Float32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sf_extern(promise, value) +} + +func _$Promise_resolve_Sf(_ promise: JSObject, _ value: Float) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sf(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sd(_ promise: JSObject, _ value: Double) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sd") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sd_extern(_ promise: Int32, _ value: Float64) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sd_extern(_ promise: Int32, _ value: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sd(_ promise: Int32, _ value: Float64) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sd_extern(promise, value) +} + +func _$Promise_resolve_Sd(_ promise: JSObject, _ value: Double) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sd(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sb(_ promise: JSObject, _ value: Bool) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sb") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sb_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sb_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sb(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sb_extern(promise, value) +} + +func _$Promise_resolve_Sb(_ promise: JSObject, _ value: Bool) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sb(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_SS") +fileprivate func promise_resolve_BridgeJSRuntimeTests_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_SS(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_SS_extern(promise, valueBytes, valueLength) +} + +func _$Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + promise_resolve_BridgeJSRuntimeTests_SS(promiseValue, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_7GreeterC(_ promise: JSObject, _ value: Greeter) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_7GreeterC") +fileprivate func promise_resolve_BridgeJSRuntimeTests_7GreeterC_extern(_ promise: Int32, _ value: UnsafeMutableRawPointer) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_7GreeterC_extern(_ promise: Int32, _ value: UnsafeMutableRawPointer) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_7GreeterC(_ promise: Int32, _ value: UnsafeMutableRawPointer) -> Void { + return promise_resolve_BridgeJSRuntimeTests_7GreeterC_extern(promise, value) +} + +func _$Promise_resolve_7GreeterC(_ promise: JSObject, _ value: Greeter) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valuePointer = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_7GreeterC(promiseValue, valuePointer) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_8JSObjectC(_ promise: JSObject, _ value: JSObject) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_8JSObjectC") +fileprivate func promise_resolve_BridgeJSRuntimeTests_8JSObjectC_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_8JSObjectC_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_8JSObjectC(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_8JSObjectC_extern(promise, value) +} + +func _$Promise_resolve_8JSObjectC(_ promise: JSObject, _ value: JSObject) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_8JSObjectC(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_5ThemeO(_ promise: JSObject, _ value: Theme) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_5ThemeO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_5ThemeO_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_5ThemeO_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_5ThemeO(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_5ThemeO_extern(promise, valueBytes, valueLength) +} + +func _$Promise_resolve_5ThemeO(_ promise: JSObject, _ value: Theme) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + promise_resolve_BridgeJSRuntimeTests_5ThemeO(promiseValue, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_9DirectionO(_ promise: JSObject, _ value: Direction) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_9DirectionO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_9DirectionO_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_9DirectionO_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_9DirectionO(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_9DirectionO_extern(promise, value) +} + +func _$Promise_resolve_9DirectionO(_ promise: JSObject, _ value: Direction) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_9DirectionO(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq5ThemeO(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sq5ThemeO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq5ThemeO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq5ThemeO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq5ThemeO(_ promise: Int32, _ valueIsSome: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sq5ThemeO_extern(promise, valueIsSome, valueBytes, valueLength) +} + +func _$Promise_resolve_Sq5ThemeO(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueIsSome, valueBytes, valueLength) in + promise_resolve_BridgeJSRuntimeTests_Sq5ThemeO(promiseValue, valueIsSome, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq9DirectionO(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sq9DirectionO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq9DirectionO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq9DirectionO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq9DirectionO(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sq9DirectionO_extern(promise, valueIsSome, valueValue) +} + +func _$Promise_resolve_Sq9DirectionO(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sq9DirectionO(promiseValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sa9DirectionO(_ promise: JSObject, _ value: [Direction]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sa9DirectionO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa9DirectionO_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa9DirectionO_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa9DirectionO(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sa9DirectionO_extern(promise) +} + +func _$Promise_resolve_Sa9DirectionO(_ promise: JSObject, _ value: [Direction]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sa9DirectionO(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SD9DirectionO(_ promise: JSObject, _ value: [String: Direction]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_SD9DirectionO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_SD9DirectionO_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_SD9DirectionO_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_SD9DirectionO(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_SD9DirectionO_extern(promise) +} + +func _$Promise_resolve_SD9DirectionO(_ promise: JSObject, _ value: [String: Direction]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_SD9DirectionO(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sa5ThemeO(_ promise: JSObject, _ value: [Theme]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sa5ThemeO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa5ThemeO_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa5ThemeO_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa5ThemeO(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sa5ThemeO_extern(promise) +} + +func _$Promise_resolve_Sa5ThemeO(_ promise: JSObject, _ value: [Theme]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sa5ThemeO(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SD5ThemeO(_ promise: JSObject, _ value: [String: Theme]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_SD5ThemeO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_SD5ThemeO_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_SD5ThemeO_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_SD5ThemeO(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_SD5ThemeO_extern(promise) +} + +func _$Promise_resolve_SD5ThemeO(_ promise: JSObject, _ value: [String: Theme]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_SD5ThemeO(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_8FileSizeO(_ promise: JSObject, _ value: FileSize) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_8FileSizeO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_8FileSizeO_extern(_ promise: Int32, _ value: Int64) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_8FileSizeO_extern(_ promise: Int32, _ value: Int64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_8FileSizeO(_ promise: Int32, _ value: Int64) -> Void { + return promise_resolve_BridgeJSRuntimeTests_8FileSizeO_extern(promise, value) +} + +func _$Promise_resolve_8FileSizeO(_ promise: JSObject, _ value: FileSize) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueValue = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_8FileSizeO(promiseValue, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq8FileSizeO(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sq8FileSizeO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq8FileSizeO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int64) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq8FileSizeO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq8FileSizeO(_ promise: Int32, _ valueIsSome: Int32, _ valueValue: Int64) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sq8FileSizeO_extern(promise, valueIsSome, valueValue) +} + +func _$Promise_resolve_Sq8FileSizeO(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueIsSome, valueValue) = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sq8FileSizeO(promiseValue, valueIsSome, valueValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_11PublicPointV(_ promise: JSObject, _ value: PublicPoint) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_11PublicPointV") +fileprivate func promise_resolve_BridgeJSRuntimeTests_11PublicPointV_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_11PublicPointV_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_11PublicPointV(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_11PublicPointV_extern(promise, value) +} + +func _$Promise_resolve_11PublicPointV(_ promise: JSObject, _ value: PublicPoint) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueObjectId = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_11PublicPointV(promiseValue, valueObjectId) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_7ContactV(_ promise: JSObject, _ value: Contact) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_7ContactV") +fileprivate func promise_resolve_BridgeJSRuntimeTests_7ContactV_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_7ContactV_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_7ContactV(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_7ContactV_extern(promise, value) +} + +func _$Promise_resolve_7ContactV(_ promise: JSObject, _ value: Contact) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueObjectId = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_7ContactV(promiseValue, valueObjectId) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sa11PublicPointV(_ promise: JSObject, _ value: [PublicPoint]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sa11PublicPointV") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa11PublicPointV_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa11PublicPointV_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sa11PublicPointV(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sa11PublicPointV_extern(promise) +} + +func _$Promise_resolve_Sa11PublicPointV(_ promise: JSObject, _ value: [PublicPoint]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sa11PublicPointV(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq11PublicPointV(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(promise, value) +} + +func _$Promise_resolve_Sq11PublicPointV(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueIsSome = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV(promiseValue, valueIsSome) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SD11PublicPointV(_ promise: JSObject, _ value: [String: PublicPoint]) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_SD11PublicPointV") +fileprivate func promise_resolve_BridgeJSRuntimeTests_SD11PublicPointV_extern(_ promise: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_SD11PublicPointV_extern(_ promise: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_SD11PublicPointV(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_SD11PublicPointV_extern(promise) +} + +func _$Promise_resolve_SD11PublicPointV(_ promise: JSObject, _ value: [String: PublicPoint]) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_SD11PublicPointV(promiseValue) + if let error = _swift_js_take_exception() { throw error } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ArrayElementObject_init") fileprivate func bjs_ArrayElementObject_init_extern(_ idBytes: Int32, _ idLength: Int32) -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index a28843142..7be4d110e 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -908,6 +908,46 @@ } } } + }, + { + "abiName" : "bjs_Calculator_asyncMakePoint", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncMakePoint", + "parameters" : [ + { + "label" : "x", + "name" : "x", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "label" : "y", + "name" : "y", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } } ], "name" : "Calculator", @@ -12569,233 +12609,557 @@ } }, { - "abiName" : "bjs_setHttpStatus", + "abiName" : "bjs_asyncRoundTripTheme", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "setHttpStatus", + "name" : "asyncRoundTripTheme", "parameters" : [ { "label" : "_", - "name" : "status", + "name" : "v", "type" : { "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" + "_0" : "Theme", + "_1" : "String" } } } ], "returnType" : { "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" - } - } - }, - { - "abiName" : "bjs_getHttpStatus", - "effects" : { - "isAsync" : false, - "isStatic" : false, - "isThrows" : false - }, - "name" : "getHttpStatus", - "parameters" : [ - - ], - "returnType" : { - "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" + "_0" : "Theme", + "_1" : "String" } } }, { - "abiName" : "bjs_setFileSize", + "abiName" : "bjs_asyncRoundTripDirection", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "setFileSize", + "name" : "asyncRoundTripDirection", "parameters" : [ { "label" : "_", - "name" : "size", + "name" : "v", "type" : { - "rawValueEnum" : { - "_0" : "FileSize", - "_1" : "Int64" + "caseEnum" : { + "_0" : "Direction" } } } ], "returnType" : { - "rawValueEnum" : { - "_0" : "FileSize", - "_1" : "Int64" + "caseEnum" : { + "_0" : "Direction" } } }, { - "abiName" : "bjs_getFileSize", + "abiName" : "bjs_asyncRoundTripOptionalTheme", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "getFileSize", + "name" : "asyncRoundTripOptionalTheme", "parameters" : [ - + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + }, + "_1" : "null" + } + } + } ], "returnType" : { - "rawValueEnum" : { - "_0" : "FileSize", - "_1" : "Int64" + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + }, + "_1" : "null" } } }, { - "abiName" : "bjs_setSessionId", + "abiName" : "bjs_asyncRoundTripOptionalDirection", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "setSessionId", + "name" : "asyncRoundTripOptionalDirection", "parameters" : [ { "label" : "_", - "name" : "session", + "name" : "v", "type" : { - "rawValueEnum" : { - "_0" : "SessionId", - "_1" : "UInt64" + "nullable" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + }, + "_1" : "null" } } } ], "returnType" : { - "rawValueEnum" : { - "_0" : "SessionId", - "_1" : "UInt64" + "nullable" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + }, + "_1" : "null" } } }, { - "abiName" : "bjs_getSessionId", + "abiName" : "bjs_asyncRoundTripDirectionArray", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "getSessionId", + "name" : "asyncRoundTripDirectionArray", "parameters" : [ - + { + "label" : "_", + "name" : "v", + "type" : { + "array" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + } ], "returnType" : { - "rawValueEnum" : { - "_0" : "SessionId", - "_1" : "UInt64" + "array" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } } } }, { - "abiName" : "bjs_processTheme", + "abiName" : "bjs_asyncRoundTripDirectionDict", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "processTheme", + "name" : "asyncRoundTripDirectionDict", "parameters" : [ { "label" : "_", - "name" : "theme", + "name" : "v", "type" : { - "rawValueEnum" : { - "_0" : "Theme", - "_1" : "String" + "dictionary" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } } } } ], "returnType" : { - "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" + "dictionary" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } } } }, { - "abiName" : "bjs_setTSDirection", + "abiName" : "bjs_asyncRoundTripThemeArray", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "setTSDirection", + "name" : "asyncRoundTripThemeArray", "parameters" : [ { "label" : "_", - "name" : "direction", + "name" : "v", "type" : { - "caseEnum" : { - "_0" : "TSDirection" + "array" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } } } } ], "returnType" : { - "caseEnum" : { - "_0" : "TSDirection" + "array" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } } } }, { - "abiName" : "bjs_getTSDirection", + "abiName" : "bjs_asyncRoundTripThemeDict", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "getTSDirection", + "name" : "asyncRoundTripThemeDict", "parameters" : [ - + { + "label" : "_", + "name" : "v", + "type" : { + "dictionary" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + } ], "returnType" : { - "caseEnum" : { - "_0" : "TSDirection" + "dictionary" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } } } }, { - "abiName" : "bjs_setTSTheme", + "abiName" : "bjs_asyncRoundTripFileSize", "effects" : { - "isAsync" : false, + "isAsync" : true, "isStatic" : false, "isThrows" : false }, - "name" : "setTSTheme", + "name" : "asyncRoundTripFileSize", "parameters" : [ { "label" : "_", - "name" : "theme", + "name" : "v", "type" : { "rawValueEnum" : { - "_0" : "TSTheme", - "_1" : "String" + "_0" : "FileSize", + "_1" : "Int64" } } } ], "returnType" : { "rawValueEnum" : { - "_0" : "TSTheme", - "_1" : "String" + "_0" : "FileSize", + "_1" : "Int64" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripOptionalFileSize", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripOptionalFileSize", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_setHttpStatus", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setHttpStatus", + "parameters" : [ + { + "label" : "_", + "name" : "status", + "type" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + }, + { + "abiName" : "bjs_getHttpStatus", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getHttpStatus", + "parameters" : [ + + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + }, + { + "abiName" : "bjs_setFileSize", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setFileSize", + "parameters" : [ + { + "label" : "_", + "name" : "size", + "type" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + } + }, + { + "abiName" : "bjs_getFileSize", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getFileSize", + "parameters" : [ + + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "FileSize", + "_1" : "Int64" + } + } + }, + { + "abiName" : "bjs_setSessionId", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setSessionId", + "parameters" : [ + { + "label" : "_", + "name" : "session", + "type" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + } + }, + { + "abiName" : "bjs_getSessionId", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getSessionId", + "parameters" : [ + + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "SessionId", + "_1" : "UInt64" + } + } + }, + { + "abiName" : "bjs_processTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processTheme", + "parameters" : [ + { + "label" : "_", + "name" : "theme", + "type" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + }, + { + "abiName" : "bjs_setTSDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setTSDirection", + "parameters" : [ + { + "label" : "_", + "name" : "direction", + "type" : { + "caseEnum" : { + "_0" : "TSDirection" + } + } + } + ], + "returnType" : { + "caseEnum" : { + "_0" : "TSDirection" + } + } + }, + { + "abiName" : "bjs_getTSDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getTSDirection", + "parameters" : [ + + ], + "returnType" : { + "caseEnum" : { + "_0" : "TSDirection" + } + } + }, + { + "abiName" : "bjs_setTSTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setTSTheme", + "parameters" : [ + { + "label" : "_", + "name" : "theme", + "type" : { + "rawValueEnum" : { + "_0" : "TSTheme", + "_1" : "String" + } + } + } + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "TSTheme", + "_1" : "String" } } }, @@ -14360,6 +14724,241 @@ } } }, + { + "abiName" : "bjs_asyncRoundTripPublicPoint", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripPublicPoint", + "parameters" : [ + { + "label" : "_", + "name" : "point", + "type" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripPublicPointThrows", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncRoundTripPublicPointThrows", + "parameters" : [ + { + "label" : "_", + "name" : "point", + "type" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + }, + { + "abiName" : "bjs_asyncStructOrThrow", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncStructOrThrow", + "parameters" : [ + { + "label" : "_", + "name" : "shouldThrow", + "type" : { + "bool" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + }, + { + "abiName" : "bjs_asyncCombinePublicPoints", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncCombinePublicPoints", + "parameters" : [ + { + "label" : "_", + "name" : "a", + "type" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + }, + { + "label" : "_", + "name" : "b", + "type" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripContact", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripContact", + "parameters" : [ + { + "label" : "_", + "name" : "contact", + "type" : { + "swiftStruct" : { + "_0" : "Contact" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Contact" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripPublicPointArray", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripPublicPointArray", + "parameters" : [ + { + "label" : "_", + "name" : "points", + "type" : { + "array" : { + "_0" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + } + } + } + ], + "returnType" : { + "array" : { + "_0" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + } + } + }, + { + "abiName" : "bjs_asyncRoundTripOptionalPublicPoint", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripOptionalPublicPoint", + "parameters" : [ + { + "label" : "_", + "name" : "point", + "type" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + }, + "_1" : "null" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripPublicPointDict", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripPublicPointDict", + "parameters" : [ + { + "label" : "_", + "name" : "points", + "type" : { + "dictionary" : { + "_0" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + } + } + } + ], + "returnType" : { + "dictionary" : { + "_0" : { + "swiftStruct" : { + "_0" : "PublicPoint" + } + } + } + } + }, { "abiName" : "bjs_roundTripContact", "effects" : { diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs index f64531d4a..eca2b209c 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs @@ -1,6 +1,7 @@ // @ts-check import assert from 'node:assert'; +import { ThemeValues, DirectionValues, FileSizeValues } from '../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.js'; /** * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["AsyncImportImports"]} @@ -43,4 +44,79 @@ export function getImports(importsContext) { /** @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ export async function runAsyncWorksTests(exports) { await exports.asyncRoundTripVoid(); + + const asyncPoint = { x: 7, y: 11 }; + assert.deepEqual(await exports.asyncRoundTripPublicPoint(asyncPoint), asyncPoint); + assert.deepEqual(await exports.asyncRoundTripPublicPointThrows(asyncPoint), asyncPoint); + + const [c1, c2] = await Promise.all([ + exports.asyncRoundTripPublicPoint({ x: 1, y: 2 }), + exports.asyncRoundTripPublicPoint({ x: 3, y: 4 }), + ]); + assert.deepEqual(c1, { x: 1, y: 2 }); + assert.deepEqual(c2, { x: 3, y: 4 }); + + assert.deepEqual(await exports.asyncCombinePublicPoints({ x: 1, y: 2 }, { x: 10, y: 20 }), { x: 11, y: 22 }); + + assert.deepEqual(await exports.asyncStructOrThrow(false), { x: 1, y: 2 }); + await assert.rejects( + () => exports.asyncStructOrThrow(true), + (error) => error instanceof Error && error.message === "async struct failure" + ); + + const richContact = { + name: "Alice", + age: 30, + address: { street: "123 Main St", city: "NYC", zipCode: 10001 }, + email: "alice@test.com", + secondaryAddress: { street: "456 Oak Ave", city: "LA", zipCode: null }, + }; + assert.deepEqual(await exports.asyncRoundTripContact(richContact), richContact); + + const calc = exports.createCalculator(); + assert.deepEqual(await calc.asyncMakePoint(3, 4), { x: 3, y: 4 }); + calc.release(); + + assert.equal(await exports.asyncRoundTripTheme(ThemeValues.Dark), ThemeValues.Dark); + assert.equal(await exports.asyncRoundTripDirection(DirectionValues.East), DirectionValues.East); + + assert.deepEqual( + await exports.asyncRoundTripPublicPointArray([{ x: 1, y: 2 }, { x: 3, y: 4 }]), + [{ x: 1, y: 2 }, { x: 3, y: 4 }] + ); + + assert.equal(await exports.asyncRoundTripOptionalTheme(ThemeValues.Light), ThemeValues.Light); + assert.equal(await exports.asyncRoundTripOptionalTheme(null), null); + assert.equal(await exports.asyncRoundTripOptionalDirection(DirectionValues.South), DirectionValues.South); + assert.equal(await exports.asyncRoundTripOptionalDirection(null), null); + + assert.deepEqual(await exports.asyncRoundTripOptionalPublicPoint({ x: 5, y: 6 }), { x: 5, y: 6 }); + assert.equal(await exports.asyncRoundTripOptionalPublicPoint(null), null); + + assert.deepEqual( + await exports.asyncRoundTripPublicPointDict({ a: { x: 1, y: 2 }, b: { x: 3, y: 4 } }), + { a: { x: 1, y: 2 }, b: { x: 3, y: 4 } } + ); + + assert.deepEqual( + await exports.asyncRoundTripDirectionArray([DirectionValues.North, DirectionValues.East]), + [DirectionValues.North, DirectionValues.East] + ); + assert.deepEqual( + await exports.asyncRoundTripDirectionDict({ a: DirectionValues.North, b: DirectionValues.South }), + { a: DirectionValues.North, b: DirectionValues.South } + ); + + assert.deepEqual( + await exports.asyncRoundTripThemeArray([ThemeValues.Light, ThemeValues.Dark]), + [ThemeValues.Light, ThemeValues.Dark] + ); + assert.deepEqual( + await exports.asyncRoundTripThemeDict({ a: ThemeValues.Light, b: ThemeValues.Auto }), + { a: ThemeValues.Light, b: ThemeValues.Auto } + ); + + assert.equal(await exports.asyncRoundTripFileSize(FileSizeValues.Large), FileSizeValues.Large); + assert.equal(await exports.asyncRoundTripOptionalFileSize(FileSizeValues.Tiny), FileSizeValues.Tiny); + assert.equal(await exports.asyncRoundTripOptionalFileSize(null), null); } diff --git a/Tests/BridgeJSRuntimeTests/StructAPIs.swift b/Tests/BridgeJSRuntimeTests/StructAPIs.swift index daa7ad1e2..c2216c808 100644 --- a/Tests/BridgeJSRuntimeTests/StructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/StructAPIs.swift @@ -210,6 +210,41 @@ extension Vector2D { point } +@JS public func asyncRoundTripPublicPoint(_ point: PublicPoint) async -> PublicPoint { + point +} + +@JS public func asyncRoundTripPublicPointThrows(_ point: PublicPoint) async throws(JSException) -> PublicPoint { + point +} + +@JS public func asyncStructOrThrow(_ shouldThrow: Bool) async throws(JSException) -> PublicPoint { + if shouldThrow { + throw JSException(JSError(message: "async struct failure").jsValue) + } + return PublicPoint(x: 1, y: 2) +} + +@JS public func asyncCombinePublicPoints(_ a: PublicPoint, _ b: PublicPoint) async -> PublicPoint { + PublicPoint(x: a.x + b.x, y: a.y + b.y) +} + +@JS func asyncRoundTripContact(_ contact: Contact) async -> Contact { + contact +} + +@JS public func asyncRoundTripPublicPointArray(_ points: [PublicPoint]) async -> [PublicPoint] { + points +} + +@JS public func asyncRoundTripOptionalPublicPoint(_ point: PublicPoint?) async -> PublicPoint? { + point +} + +@JS public func asyncRoundTripPublicPointDict(_ points: [String: PublicPoint]) async -> [String: PublicPoint] { + points +} + @JS func roundTripContact(_ contact: Contact) -> Contact { return contact } From 453b841f4fd78e6001c576f524b5bc597a9373bd Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 9 Jun 2026 21:13:15 +0100 Subject: [PATCH 61/68] Fix error descriptions Embedded Swift compatibility (#759) The BridgeJS generator emits `JSError(message: String(describing: error))` for throwing `@JS` exports, but `String.init(describing:)` is unavailable in Embedded Swift, so embedded Wasm builds of any package with a throwing export fail. The caught error is statically a `JSException` with a stored `description`, so the generated glue now uses `error.description` for identical output. Snapshots regenerated. --- .../PlayBridgeJS/Generated/BridgeJS.swift | 2 +- .../Sources/BridgeJSCore/ExportSwift.swift | 2 +- .../EnumNamespace.Global.swift | 2 +- .../BridgeJSCodegenTests/EnumNamespace.swift | 2 +- .../ImportedTypeInExportedInterface.swift | 2 +- .../BridgeJSCodegenTests/Throws.swift | 2 +- .../Generated/BridgeJS.swift | 18 +++++++++--------- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift index 920f2cc2f..37b024346 100644 --- a/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift +++ b/Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift @@ -188,7 +188,7 @@ public func _bjs_PlayBridgeJS_updateDetailed(_ _self: UnsafeMutableRawPointer, _ _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index c9ef1e6f1..440960237 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -453,7 +453,7 @@ public class ExportSwift { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift index 5bde4ff93..4f588f6c7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.Global.swift @@ -117,7 +117,7 @@ public func _bjs_Services_Graph_GraphOperations_static_validate(_ graphId: Int32 _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift index 5bde4ff93..4f588f6c7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumNamespace.swift @@ -117,7 +117,7 @@ public func _bjs_Services_Graph_GraphOperations_static_validate(_ graphId: Int32 _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift index f3c3f2fc1..62f9a3b68 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportedTypeInExportedInterface.swift @@ -59,7 +59,7 @@ public func _bjs_makeFoo() -> Int32 { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.swift index 37f6d9c96..91787a642 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Throws.swift @@ -10,7 +10,7 @@ public func _bjs_throwsSomething() -> Void { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index c20946b39..497fa3355 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -6967,7 +6967,7 @@ public func _bjs_makeImportedFoo(_ valueBytes: Int32, _ valueLength: Int32) -> I _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7002,7 +7002,7 @@ public func _bjs_throwsSwiftError(_ shouldThrow: Int32) -> Void { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7027,7 +7027,7 @@ public func _bjs_throwsWithIntResult() -> Int32 { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7052,7 +7052,7 @@ public func _bjs_throwsWithStringResult() -> Void { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7077,7 +7077,7 @@ public func _bjs_throwsWithBoolResult() -> Int32 { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7102,7 +7102,7 @@ public func _bjs_throwsWithFloatResult() -> Float32 { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7127,7 +7127,7 @@ public func _bjs_throwsWithDoubleResult() -> Float64 { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7152,7 +7152,7 @@ public func _bjs_throwsWithSwiftHeapObjectResult() -> UnsafeMutableRawPointer { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } @@ -7177,7 +7177,7 @@ public func _bjs_throwsWithJSObjectResult() -> Int32 { _swift_js_throw(Int32(bitPattern: $0.id)) } } else { - let jsError = JSError(message: String(describing: error)) + let jsError = JSError(message: error.description) withExtendedLifetime(jsError.jsObject) { _swift_js_throw(Int32(bitPattern: $0.id)) } From 1f2fe86b7fa10f10bd8f00f9a24e323d05171497 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 10 Jun 2026 13:55:21 +0200 Subject: [PATCH 62/68] BridgeJS: Fix reject path of zero-parameter async throwing exports --- .../Sources/BridgeJSCore/ExportSwift.swift | 34 +++++++++-- .../Inputs/MacroSwift/Async.swift | 4 ++ .../BridgeJSCodegenTests/Async.json | 17 ++++++ .../BridgeJSCodegenTests/Async.swift | 14 +++++ .../BridgeJSLinkTests/Async.d.ts | 1 + .../__Snapshots__/BridgeJSLinkTests/Async.js | 12 ++++ .../BridgeJSRuntimeTests/ExportAPITests.swift | 4 ++ .../Generated/BridgeJS.swift | 58 ++++++++++++------- .../Generated/JavaScript/BridgeJS.json | 17 ++++++ .../JavaScript/AsyncImportTests.mjs | 5 ++ 10 files changed, 139 insertions(+), 27 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 440960237..90c572b9d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -426,21 +426,45 @@ public class ExportSwift { /// A throwing async body needs an explicit closure type, otherwise Swift infers /// `throws(any Error)` instead of `throws(JSException)`. /// See: https://github.com/swiftlang/swift/issues/76165 - private func asyncThrowsClosureHead(returnSpelling: String?) -> String { + private func asyncThrowsClosureHead(returnSpelling: String?, forcesCapture: Bool) -> String { guard effects.isThrows else { return "" } let returns = returnSpelling.map { " -> \($0)" } ?? "" - return " () async throws(JSException)\(returns) in" + let capture = forcesCapture ? "[__bjs_capture] " : "" + return " \(capture)() async throws(JSException)\(returns) in" + } + + /// A captureless throwing async body closure lowers via `thin_to_thick_function`, + /// which miscompiles typed-error calls on wasm32. Forcing a capture that the body + /// reads turns the closure into a partial apply with a context, avoiding the + /// broken convention. An unread capture list entry is dropped by capture analysis, + /// so the body must also read the captured value. + /// See: https://github.com/swiftlang/swift/issues/89320 + private var asyncThrowsBodyForcesCapture: Bool { + effects.isThrows && abiParameterSignatures.isEmpty && asyncHoistedBindings.isEmpty } func render(abiName: String) -> DeclSyntax { let body: CodeBlockItemListSyntax if effects.isAsync, let resolveType = asyncResolveReturnType { let resolveName = "Promise_resolve_\(resolveType.mangleTypeName)" - let closureHead = asyncThrowsClosureHead(returnSpelling: resolveType.swiftType) + let forcesCapture = asyncThrowsBodyForcesCapture + let closureHead = asyncThrowsClosureHead( + returnSpelling: resolveType.swiftType, + forcesCapture: forcesCapture + ) + var hoistedBindings = asyncHoistedBindings + var bodyItems = self.body + if forcesCapture { + hoistedBindings.append("let __bjs_capture = 0") + if !bodyItems.isEmpty { + bodyItems[0] = bodyItems[0].with(\.leadingTrivia, .newline) + } + bodyItems.insert("_ = __bjs_capture", at: 0) + } body = """ - \(CodeBlockItemListSyntax(asyncHoistedBindings)) + \(CodeBlockItemListSyntax(hoistedBindings)) return _bjs_makePromise(resolve: \(raw: resolveName), reject: Promise_reject) {\(raw: closureHead) - \(CodeBlockItemListSyntax(self.body)) + \(CodeBlockItemListSyntax(bodyItems)) } """ } else if effects.isThrows { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift index e63bea4ca..742d96ed2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Async.swift @@ -31,6 +31,10 @@ return v } +@JS func asyncThrowsZeroArg() async throws(JSException) -> String { + return "ok" +} + @JS func asyncCombineStructs(_ a: AsyncPoint, _ b: AsyncPoint) async -> AsyncPoint { return AsyncPoint(x: a.x + b.x, y: a.y + b.y) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json index 3bd594419..8684291f0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.json @@ -283,6 +283,23 @@ } } }, + { + "abiName" : "bjs_asyncThrowsZeroArg", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "asyncThrowsZeroArg", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, { "abiName" : "bjs_asyncCombineStructs", "effects" : { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift index 28e6d8d8f..661fbd3a5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift @@ -194,6 +194,20 @@ public func _bjs_asyncRoundTripStructThrows() -> Int32 { #endif } +@_expose(wasm, "bjs_asyncThrowsZeroArg") +@_cdecl("bjs_asyncThrowsZeroArg") +public func _bjs_asyncThrowsZeroArg() -> Int32 { + #if arch(wasm32) + let __bjs_capture = 0 + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { [__bjs_capture] () async throws(JSException) -> String in + _ = __bjs_capture + return try await asyncThrowsZeroArg() + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_asyncCombineStructs") @_cdecl("bjs_asyncCombineStructs") public func _bjs_asyncCombineStructs() -> Int32 { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts index ddf722a3a..507a96d4a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.d.ts @@ -34,6 +34,7 @@ export type Exports = { asyncRoundTripJSObject(v: any): Promise; asyncRoundTripStruct(v: AsyncPoint): Promise; asyncRoundTripStructThrows(v: AsyncPoint): Promise; + asyncThrowsZeroArg(): Promise; asyncCombineStructs(a: AsyncPoint, b: AsyncPoint): Promise; asyncRoundTripEnum(v: AsyncDirectionTag): Promise; asyncRoundTripRawEnum(v: AsyncThemeTag): Promise; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 887102a76..9319cdd7e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -585,6 +585,18 @@ export async function createInstantiator(options, swift) { } return ret1; }, + asyncThrowsZeroArg: function bjs_asyncThrowsZeroArg() { + const ret = instance.exports.bjs_asyncThrowsZeroArg(); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }, asyncCombineStructs: function bjs_asyncCombineStructs(a, b) { structHelpers.AsyncPoint.lower(a); structHelpers.AsyncPoint.lower(b); diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 79a931930..a0453b8f8 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -96,6 +96,10 @@ struct TestError: Error { @JS func throwsWithSwiftHeapObjectResult() throws(JSException) -> Greeter { return Greeter(name: "Test") } @JS func throwsWithJSObjectResult() throws(JSException) -> JSObject { return JSObject() } +@JS func zeroArgAsyncThrows() async throws(JSException) -> String { + throw JSException(JSError(message: "ZeroArgAsyncThrowsError").jsValue) +} + @JS func asyncRoundTripVoid() async -> Void { return } @JS func asyncRoundTripInt(v: Int) async -> Int { return v } @JS func asyncRoundTripFloat(v: Float) async -> Float { return v } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 497fa3355..78bac8952 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -7189,6 +7189,20 @@ public func _bjs_throwsWithJSObjectResult() -> Int32 { #endif } +@_expose(wasm, "bjs_zeroArgAsyncThrows") +@_cdecl("bjs_zeroArgAsyncThrows") +public func _bjs_zeroArgAsyncThrows() -> Int32 { + #if arch(wasm32) + let __bjs_capture = 0 + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { [__bjs_capture] () async throws(JSException) -> String in + _ = __bjs_capture + return try await zeroArgAsyncThrows() + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_asyncRoundTripVoid") @_cdecl("bjs_asyncRoundTripVoid") public func _bjs_asyncRoundTripVoid() -> Int32 { @@ -11403,6 +11417,28 @@ func _$Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) if let error = _swift_js_take_exception() { throw error } } +@JSFunction func Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_SS") +fileprivate func promise_resolve_BridgeJSRuntimeTests_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_SS(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_SS_extern(promise, valueBytes, valueLength) +} + +func _$Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + promise_resolve_BridgeJSRuntimeTests_SS(promiseValue, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + @JSFunction func Promise_resolve_y(_ promise: JSObject) throws(JSException) #if arch(wasm32) @@ -11507,28 +11543,6 @@ func _$Promise_resolve_Sb(_ promise: JSObject, _ value: Bool) throws(JSException if let error = _swift_js_take_exception() { throw error } } -@JSFunction func Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) - -#if arch(wasm32) -@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_SS") -fileprivate func promise_resolve_BridgeJSRuntimeTests_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void -#else -fileprivate func promise_resolve_BridgeJSRuntimeTests_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { - fatalError("Only available on WebAssembly") -} -#endif -@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_SS(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { - return promise_resolve_BridgeJSRuntimeTests_SS_extern(promise, valueBytes, valueLength) -} - -func _$Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) -> Void { - let promiseValue = promise.bridgeJSLowerParameter() - value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in - promise_resolve_BridgeJSRuntimeTests_SS(promiseValue, valueBytes, valueLength) - } - if let error = _swift_js_take_exception() { throw error } -} - @JSFunction func Promise_resolve_7GreeterC(_ promise: JSObject, _ value: Greeter) throws(JSException) #if arch(wasm32) diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index d77883980..6535e9fc1 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -12171,6 +12171,23 @@ } } }, + { + "abiName" : "bjs_zeroArgAsyncThrows", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "zeroArgAsyncThrows", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, { "abiName" : "bjs_asyncRoundTripVoid", "effects" : { diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs index eca2b209c..1a767b184 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs @@ -64,6 +64,11 @@ export async function runAsyncWorksTests(exports) { (error) => error instanceof Error && error.message === "async struct failure" ); + await assert.rejects( + () => exports.zeroArgAsyncThrows(), + (error) => error instanceof Error && error.message === "ZeroArgAsyncThrowsError" + ); + const richContact = { name: "Alice", age: 30, From 8291fb97970c54656b2f51feccc09973913fd328 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 11 Jun 2026 00:44:34 +0100 Subject: [PATCH 63/68] [codex] Drop Swift 6.1/6.2 support and raise MSSV to 6.3 (#762) * drop swift 6.1 * fix ci matrix * Detach async JS bridge tasks * Stabilize identity GC test * Revert detached async bridge tasks * Use Swift 6.2.4 in CI * Use Swift 6.2.3 in CI * Drop Swift 6.2 from CI * Document minimum Swift version * Add MSSV section to README * Fix async closure test formatting * Move tracing override to 24.04 matrix entry --- .github/workflows/test.yml | 17 +- Examples/Embedded/README.md | 2 +- Package@swift-6.1.swift | 222 ------------------ Plugins/PackageToJS/Tests/ExampleTests.swift | 7 - README.md | 4 + Sources/JavaScriptEventLoop/JSRemote.swift | 8 +- Sources/JavaScriptEventLoop/JSSending.swift | 17 +- .../JavaScriptEventLoop.swift | 6 +- .../WebWorkerTaskExecutor.swift | 6 +- .../FundamentalObjects/JSObject.swift | 10 +- Sources/JavaScriptKit/ThreadLocal.swift | 2 +- .../IdentityModeTests.swift | 4 +- .../JSClosure+AsyncTests.swift | 6 +- .../WebWorkerDedicatedExecutorTests.swift | 2 +- .../WebWorkerTaskExecutorTests.swift | 2 +- 15 files changed, 35 insertions(+), 280 deletions(-) delete mode 100644 Package@swift-6.1.swift diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index baba9c79b..58b2eb647 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,18 +12,13 @@ jobs: strategy: matrix: entry: - - os: ubuntu-22.04 - toolchain: - download-url: https://download.swift.org/swift-6.1-release/ubuntu2204/swift-6.1-RELEASE/swift-6.1-RELEASE-ubuntu22.04.tar.gz - wasi-backend: Node - target: "wasm32-unknown-wasi" - env: | - JAVASCRIPTKIT_DISABLE_TRACING_TRAIT=1 - os: ubuntu-24.04 toolchain: download-url: https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a/swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a-ubuntu24.04.tar.gz wasi-backend: Node target: "wasm32-unknown-wasip1" + env: | + JAVASCRIPTKIT_DISABLE_TRACING_TRAIT=1 - os: ubuntu-24.04 toolchain: download-url: https://download.swift.org/swift-6.3-branch/ubuntu2404/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-03-05-a/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-03-05-a-ubuntu24.04.tar.gz @@ -77,10 +72,6 @@ jobs: strategy: matrix: entry: - - image: "swift:6.1.2" - swift-syntax-version: "601.0.0" - - image: "swift:6.2" - swift-syntax-version: "602.0.0" - image: "swift:6.3" swift-syntax-version: "603.0.0" runs-on: ubuntu-latest @@ -110,7 +101,7 @@ jobs: matrix: include: - os: macos-15 - xcode: Xcode_16.4 + xcode: Xcode_26.0.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v6 @@ -134,7 +125,7 @@ jobs: format: runs-on: ubuntu-latest container: - image: swift:6.1.2 + image: swift:6.3 steps: - uses: actions/checkout@v6 - run: ./Utilities/format.swift diff --git a/Examples/Embedded/README.md b/Examples/Embedded/README.md index e99d659ff..97e2490b7 100644 --- a/Examples/Embedded/README.md +++ b/Examples/Embedded/README.md @@ -1,6 +1,6 @@ # Embedded example -Requires a recent DEVELOPMENT-SNAPSHOT toolchain. (tested with swift-6.1-DEVELOPMENT-SNAPSHOT-2025-02-21-a) +Requires a recent DEVELOPMENT-SNAPSHOT toolchain. ```sh $ ./build.sh diff --git a/Package@swift-6.1.swift b/Package@swift-6.1.swift deleted file mode 100644 index fe98ec529..000000000 --- a/Package@swift-6.1.swift +++ /dev/null @@ -1,222 +0,0 @@ -// swift-tools-version:6.1 - -import CompilerPluginSupport -import PackageDescription - -// NOTE: needed for embedded customizations, ideally this will not be necessary at all in the future, or can be replaced with traits -let shouldBuildForEmbedded = Context.environment["JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM"].flatMap(Bool.init) ?? false -let useLegacyResourceBundling = - Context.environment["JAVASCRIPTKIT_USE_LEGACY_RESOURCE_BUNDLING"].flatMap(Bool.init) ?? false - -let testingLinkerFlags: [LinkerSetting] = [ - .unsafeFlags( - [ - "-Xlinker", "--stack-first", - "-Xlinker", "--global-base=524288", - "-Xlinker", "-z", - "-Xlinker", "stack-size=524288", - ], - .when(platforms: [.wasi]) - ) -] - -let package = Package( - name: "JavaScriptKit", - platforms: [ - .macOS(.v13), - .iOS(.v13), - .tvOS(.v13), - .watchOS(.v6), - .macCatalyst(.v13), - ], - products: [ - .library(name: "JavaScriptKit", targets: ["JavaScriptKit"]), - .library(name: "JavaScriptEventLoop", targets: ["JavaScriptEventLoop"]), - .library(name: "JavaScriptBigIntSupport", targets: ["JavaScriptBigIntSupport"]), - .library(name: "JavaScriptFoundationCompat", targets: ["JavaScriptFoundationCompat"]), - .library(name: "JavaScriptEventLoopTestSupport", targets: ["JavaScriptEventLoopTestSupport"]), - .plugin(name: "PackageToJS", targets: ["PackageToJS"]), - .plugin(name: "BridgeJS", targets: ["BridgeJS"]), - .plugin(name: "BridgeJSCommandPlugin", targets: ["BridgeJSCommandPlugin"]), - ], - dependencies: [ - .package(url: "https://github.com/swiftlang/swift-syntax", "600.0.0"..<"603.0.0") - ], - targets: [ - .target( - name: "JavaScriptKit", - dependencies: ["_CJavaScriptKit", "BridgeJSMacros"], - exclude: useLegacyResourceBundling ? [] : ["Runtime"], - resources: useLegacyResourceBundling ? [.copy("Runtime")] : [], - cSettings: shouldBuildForEmbedded - ? [ - .unsafeFlags(["-fdeclspec"]) - ] : nil, - swiftSettings: [ - .enableExperimentalFeature("Extern") - ] - + (shouldBuildForEmbedded - ? [ - .enableExperimentalFeature("Embedded"), - .unsafeFlags(["-Xfrontend", "-emit-empty-object-file"]), - ] : []) - ), - .target(name: "_CJavaScriptKit"), - .macro( - name: "BridgeJSMacros", - dependencies: [ - .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), - .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), - ] - ), - - .testTarget( - name: "JavaScriptKitTests", - dependencies: ["JavaScriptKit"], - swiftSettings: [ - .enableExperimentalFeature("Extern") - ], - linkerSettings: testingLinkerFlags - ), - - .target( - name: "JavaScriptBigIntSupport", - dependencies: ["_CJavaScriptBigIntSupport", "JavaScriptKit"], - swiftSettings: shouldBuildForEmbedded - ? [ - .enableExperimentalFeature("Embedded"), - .unsafeFlags(["-Xfrontend", "-emit-empty-object-file"]), - ] : [] - ), - .target(name: "_CJavaScriptBigIntSupport", dependencies: ["_CJavaScriptKit"]), - .testTarget( - name: "JavaScriptBigIntSupportTests", - dependencies: ["JavaScriptBigIntSupport", "JavaScriptKit"], - linkerSettings: testingLinkerFlags - ), - - .target( - name: "JavaScriptEventLoop", - dependencies: ["JavaScriptKit", "_CJavaScriptEventLoop"], - swiftSettings: shouldBuildForEmbedded - ? [ - .enableExperimentalFeature("Embedded"), - .unsafeFlags(["-Xfrontend", "-emit-empty-object-file"]), - ] : [] - ), - .target(name: "_CJavaScriptEventLoop"), - .testTarget( - name: "JavaScriptEventLoopTests", - dependencies: [ - "JavaScriptEventLoop", - "JavaScriptKit", - "JavaScriptEventLoopTestSupport", - ], - swiftSettings: [ - .enableExperimentalFeature("Extern") - ], - linkerSettings: testingLinkerFlags - ), - .target( - name: "JavaScriptEventLoopTestSupport", - dependencies: [ - "_CJavaScriptEventLoopTestSupport", - "JavaScriptEventLoop", - ] - ), - .target(name: "_CJavaScriptEventLoopTestSupport"), - .testTarget( - name: "JavaScriptEventLoopTestSupportTests", - dependencies: [ - "JavaScriptKit", - "JavaScriptEventLoopTestSupport", - ], - linkerSettings: testingLinkerFlags - ), - .target( - name: "JavaScriptFoundationCompat", - dependencies: [ - "JavaScriptKit" - ] - ), - .testTarget( - name: "JavaScriptFoundationCompatTests", - dependencies: [ - "JavaScriptFoundationCompat" - ], - linkerSettings: testingLinkerFlags - ), - .plugin( - name: "PackageToJS", - capability: .command( - intent: .custom(verb: "js", description: "Convert a Swift package to a JavaScript package") - ), - path: "Plugins/PackageToJS/Sources" - ), - .plugin( - name: "BridgeJS", - capability: .buildTool(), - dependencies: ["BridgeJSTool"], - path: "Plugins/BridgeJS/Sources/BridgeJSBuildPlugin" - ), - .plugin( - name: "BridgeJSCommandPlugin", - capability: .command( - intent: .custom(verb: "bridge-js", description: "Generate bridging code"), - permissions: [.writeToPackageDirectory(reason: "Generate bridging code")] - ), - dependencies: ["BridgeJSTool"], - path: "Plugins/BridgeJS/Sources/BridgeJSCommandPlugin" - ), - .executableTarget( - name: "BridgeJSTool", - dependencies: [ - .product(name: "SwiftParser", package: "swift-syntax"), - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftBasicFormat", package: "swift-syntax"), - .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), - ], - exclude: ["TS2Swift/JavaScript", "README.md"] - ), - .testTarget( - name: "BridgeJSRuntimeTests", - dependencies: ["JavaScriptKit", "JavaScriptEventLoop"], - exclude: [ - "bridge-js.config.json", - "bridge-js.d.ts", - "bridge-js.global.d.ts", - "Generated/JavaScript", - "JavaScript", - ], - swiftSettings: [ - .enableExperimentalFeature("Extern") - ], - linkerSettings: testingLinkerFlags - ), - .testTarget( - name: "BridgeJSGlobalTests", - dependencies: ["JavaScriptKit", "JavaScriptEventLoop"], - exclude: [ - "bridge-js.config.json", - "bridge-js.d.ts", - "Generated/JavaScript", - ], - swiftSettings: [ - .enableExperimentalFeature("Extern") - ], - linkerSettings: testingLinkerFlags - ), - .testTarget( - name: "BridgeJSIdentityTests", - dependencies: ["JavaScriptKit", "JavaScriptEventLoop"], - exclude: [ - "bridge-js.config.json", - "Generated/JavaScript", - ], - swiftSettings: [ - .enableExperimentalFeature("Extern") - ], - linkerSettings: testingLinkerFlags - ), - ] -) diff --git a/Plugins/PackageToJS/Tests/ExampleTests.swift b/Plugins/PackageToJS/Tests/ExampleTests.swift index d26832771..1f5bedcdc 100644 --- a/Plugins/PackageToJS/Tests/ExampleTests.swift +++ b/Plugins/PackageToJS/Tests/ExampleTests.swift @@ -297,7 +297,6 @@ extension Trait where Self == ConditionTrait { } } - #if compiler(>=6.1) @Test(.requireSwiftSDK) func testingWithCoverage() throws { let swiftSDKID = try #require(Self.getSwiftSDKID()) @@ -325,7 +324,6 @@ extension Trait where Self == ConditionTrait { } } } - #endif #endif // compiler(>=6.3) @Test(.requireSwiftSDK(triple: "wasm32-unknown-wasip1-threads")) @@ -379,7 +377,6 @@ extension Trait where Self == ConditionTrait { } } - #if compiler(>=6.1) // TODO: Remove triple restriction once swift-testing is shipped in p1-threads SDK @Test(.requireSwiftSDK(triple: "wasm32-unknown-wasi")) func continuationLeakInTest_SwiftTesting() throws { @@ -391,8 +388,6 @@ extension Trait where Self == ConditionTrait { try runSwift(["package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test"], [:]) } } - #endif - @Test(.requireSwiftSDK) func playwrightOnPageLoad_XCTest() throws { let swiftSDKID = try #require(Self.getSwiftSDKID()) @@ -413,7 +408,6 @@ extension Trait where Self == ConditionTrait { } } - #if compiler(>=6.1) // TODO: Remove triple restriction once swift-testing is shipped in p1-threads SDK @Test(.requireSwiftSDK(triple: "wasm32-unknown-wasi")) func playwrightOnPageLoad_SwiftTesting() throws { @@ -434,5 +428,4 @@ extension Trait where Self == ConditionTrait { ) } } - #endif } diff --git a/README.md b/README.md index 03129c3e2..88c1332a2 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,10 @@ Use the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/) Check out the [examples](https://github.com/swiftwasm/JavaScriptKit/tree/main/Examples) for more detailed usage patterns. +## Minimum Supported Swift Version (MSSV) + +The minimum supported Swift version is 6.3. + ## Contributing Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to the project. diff --git a/Sources/JavaScriptEventLoop/JSRemote.swift b/Sources/JavaScriptEventLoop/JSRemote.swift index 4f488d7b8..b85b4991c 100644 --- a/Sources/JavaScriptEventLoop/JSRemote.swift +++ b/Sources/JavaScriptEventLoop/JSRemote.swift @@ -62,7 +62,7 @@ extension JSRemote where T == JSObject { /// /// - Parameter object: The JavaScript object to reference remotely. public init(_ object: JSObject) { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) self.init(sourceObject: object, sourceTid: object.ownerTid) #else self.init(sourceObject: object, sourceTid: -1) @@ -92,7 +92,7 @@ extension JSRemote where T == JSObject { public func withJSObject( _ body: @Sendable @escaping (JSObject) throws(E) -> R ) async throws(E) -> sending R { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) if storage.sourceTid == swjs_get_worker_thread_id_cached() { return try body(storage.sourceObject) } @@ -137,13 +137,11 @@ private final class _JSRemoteContext: @unchecked Sendable { } } -#if compiler(>=6.1) @_expose(wasm, "swjs_invoke_remote_jsobject_body") @_cdecl("swjs_invoke_remote_jsobject_body") -#endif @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) func _swjs_invoke_remote_jsobject_body(_ contextPtr: UnsafeRawPointer?) -> Bool { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) guard let contextPtr else { return true } let context = Unmanaged<_JSRemoteContext>.fromOpaque(contextPtr).takeRetainedValue() diff --git a/Sources/JavaScriptEventLoop/JSSending.swift b/Sources/JavaScriptEventLoop/JSSending.swift index fb2fb1ddf..613abdd8a 100644 --- a/Sources/JavaScriptEventLoop/JSSending.swift +++ b/Sources/JavaScriptEventLoop/JSSending.swift @@ -105,7 +105,7 @@ extension JSSending where T == JSObject { construct: { $0 }, deconstruct: { $0 }, getSourceTid: { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) return $0.ownerTid #else _ = $0 @@ -258,7 +258,7 @@ extension JSSending { file: StaticString = #file, line: UInt = #line ) async throws -> T { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) let idInDestination = try await withCheckedThrowingContinuation { continuation in let context = _JSSendingContext(continuation: continuation) let idInSource = self.storage.idInSource @@ -278,8 +278,6 @@ extension JSSending { } #endif - // 6.0 and below can't compile the following without a compiler crash. - #if compiler(>=6.1) /// Receives multiple `JSSending` instances from a thread in a single operation. /// /// This method is more efficient than receiving multiple objects individually, as it @@ -317,7 +315,7 @@ extension JSSending { file: StaticString = #file, line: UInt = #line ) async throws -> (repeat each U) where T == (repeat each U) { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) var sendingObjects: [JavaScriptObjectRef] = [] var transferringObjects: [JavaScriptObjectRef] = [] var sourceTid: Int32? @@ -363,7 +361,6 @@ extension JSSending { return try await (repeat (each sendings).receive()) #endif } - #endif // compiler(>=6.1) } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) @@ -404,13 +401,11 @@ public struct JSSendingError: Error, CustomStringConvertible { /// - object: The `JSObject` to be received. /// - contextPtr: A pointer to the `_JSSendingContext` instance. // swift-format-ignore -#if compiler(>=6.1) // @_expose and @_extern are only available in Swift 6.1+ @_expose(wasm, "swjs_receive_response") @_cdecl("swjs_receive_response") -#endif @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) func _swjs_receive_response(_ object: JavaScriptObjectRef, _ contextPtr: UnsafeRawPointer?) { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) guard let contextPtr = contextPtr else { return } let context = Unmanaged<_JSSendingContext>.fromOpaque(contextPtr).takeRetainedValue() context.continuation.resume(returning: object) @@ -424,13 +419,11 @@ func _swjs_receive_response(_ object: JavaScriptObjectRef, _ contextPtr: UnsafeR /// - error: The error to be received. /// - contextPtr: A pointer to the `_JSSendingContext` instance. // swift-format-ignore -#if compiler(>=6.1) // @_expose and @_extern are only available in Swift 6.1+ @_expose(wasm, "swjs_receive_error") @_cdecl("swjs_receive_error") -#endif @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) func _swjs_receive_error(_ error: JavaScriptObjectRef, _ contextPtr: UnsafeRawPointer?) { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) guard let contextPtr = contextPtr else { return } let context = Unmanaged<_JSSendingContext>.fromOpaque(contextPtr).takeRetainedValue() context.continuation.resume(throwing: JSException(JSObject(id: error).jsValue)) diff --git a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift index 5fc267ddc..ead6157bf 100644 --- a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift +++ b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift @@ -65,7 +65,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { return _shared } - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) // In multi-threaded environment, we have an event loop executor per // thread (per Web Worker). A job enqueued in one thread should be // executed in the same thread under this global executor. @@ -129,7 +129,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { _Concurrency._createExecutors(factory: JavaScriptEventLoop.self) } #else - // For Swift 6.1 and below, or Embedded Swift, we need to install + // For Embedded Swift, we need to install // the global executor by hook API. The ExecutorFactory mechanism // does not work in Embedded Swift because ExecutorImpl.swift is // excluded from the embedded Concurrency library. @@ -151,7 +151,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { } internal func unsafeEnqueue(_ job: UnownedJob) { - #if canImport(wasi_pthread) && compiler(>=6.1) && _runtime(_multithreaded) + #if canImport(wasi_pthread) && _runtime(_multithreaded) guard swjs_get_worker_thread_id_cached() == SWJS_MAIN_THREAD_ID else { // Notify the main thread to execute the job when a job is // enqueued from a Web Worker thread but without an executor preference. diff --git a/Sources/JavaScriptEventLoop/WebWorkerTaskExecutor.swift b/Sources/JavaScriptEventLoop/WebWorkerTaskExecutor.swift index b827ad980..b6bfb9c5f 100644 --- a/Sources/JavaScriptEventLoop/WebWorkerTaskExecutor.swift +++ b/Sources/JavaScriptEventLoop/WebWorkerTaskExecutor.swift @@ -385,7 +385,7 @@ public final class WebWorkerTaskExecutor: TaskExecutor { } func start(timeout: Duration, checkInterval: Duration) async throws { - #if canImport(wasi_pthread) && compiler(>=6.1) && _runtime(_multithreaded) + #if canImport(wasi_pthread) && _runtime(_multithreaded) class Context: @unchecked Sendable { let executor: WebWorkerTaskExecutor.Executor let worker: Worker @@ -610,9 +610,7 @@ public final class WebWorkerTaskExecutor: TaskExecutor { /// Enqueue a job scheduled from a Web Worker thread to the main thread. /// This function is called when a job is enqueued from a Web Worker thread. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -#if compiler(>=6.1) // @_expose and @_extern are only available in Swift 6.1+ @_expose(wasm, "swjs_enqueue_main_job_from_worker") -#endif func _swjs_enqueue_main_job_from_worker(_ job: UnownedJob) { WebWorkerTaskExecutor.traceStatsIncrement(\.receiveJobFromWorkerThread) JavaScriptEventLoop.shared.enqueue(ExecutorJob(job)) @@ -621,9 +619,7 @@ func _swjs_enqueue_main_job_from_worker(_ job: UnownedJob) { /// Wake up the worker thread. /// This function is called when a job is enqueued from the main thread to a worker thread. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -#if compiler(>=6.1) // @_expose and @_extern are only available in Swift 6.1+ @_expose(wasm, "swjs_wake_worker_thread") -#endif func _swjs_wake_worker_thread() { WebWorkerTaskExecutor.Worker.currentThread!.wakeUpFromOtherThread() } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift index 1b6facada..7bc799c64 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift @@ -22,7 +22,7 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { @usableFromInline internal var _id: JavaScriptObjectRef - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) package let ownerTid: Int32 #endif @@ -35,7 +35,7 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { @_spi(BridgeJS) public init(id: JavaScriptObjectRef) { self._id = id - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) self.ownerTid = swjs_get_worker_thread_id_cached() #endif } @@ -61,7 +61,7 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { /// is a programmer error and will result in a runtime assertion failure because JavaScript /// object spaces are not shared across threads backed by Web Workers. private func assertOnOwnerThread(hint: @autoclosure () -> String) { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) precondition( ownerTid == swjs_get_worker_thread_id_cached(), "JSObject is being accessed from a thread other than the owner thread: \(hint())" @@ -71,7 +71,7 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { /// Asserts that the two objects being compared are owned by the same thread. private static func assertSameOwnerThread(lhs: JSObject, rhs: JSObject, hint: @autoclosure () -> String) { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) precondition( lhs.ownerTid == rhs.ownerTid, "JSObject is being accessed from a thread other than the owner thread: \(hint())" @@ -282,7 +282,7 @@ public class JSObject: Equatable, ExpressibleByDictionaryLiteral { }) deinit { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) if ownerTid != swjs_get_worker_thread_id_cached() { // If the object is not owned by the current thread swjs_release_remote(ownerTid, id) diff --git a/Sources/JavaScriptKit/ThreadLocal.swift b/Sources/JavaScriptKit/ThreadLocal.swift index 12bf78773..4c8bac75f 100644 --- a/Sources/JavaScriptKit/ThreadLocal.swift +++ b/Sources/JavaScriptKit/ThreadLocal.swift @@ -17,7 +17,7 @@ import Glibc /// The value is stored in a thread-local variable, which is a separate copy for each thread. @propertyWrapper final class ThreadLocal: Sendable { - #if compiler(>=6.1) && _runtime(_multithreaded) + #if _runtime(_multithreaded) /// The wrapped value stored in the thread-local storage. /// The initial value is `nil` for each thread. var wrappedValue: Value? { diff --git a/Tests/BridgeJSIdentityTests/IdentityModeTests.swift b/Tests/BridgeJSIdentityTests/IdentityModeTests.swift index 0aa036163..dacf85800 100644 --- a/Tests/BridgeJSIdentityTests/IdentityModeTests.swift +++ b/Tests/BridgeJSIdentityTests/IdentityModeTests.swift @@ -38,7 +38,9 @@ final class IdentityModeTests: XCTestCase { // let FinalizationRegistry fire and call deinit. for _ in 0..<100 { try gc() - try await Task.sleep(for: .milliseconds(0)) + // Give the JS runtime an actual turn so FinalizationRegistry callbacks + // can run before we check the Swift weak reference. + try await Task.sleep(for: .milliseconds(1)) if weakSubject == nil { break } diff --git a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift index db093e549..e3c19a8e4 100644 --- a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift +++ b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift @@ -72,7 +72,7 @@ class JSClosureAsyncTests: XCTestCase { )!.value() XCTAssertEqual(result, 42.0) } - + func testAsyncOneshotClosureWithPriority() async throws { let priority = UnsafeSendableBox(nil) let closure = JSOneshotClosure.async(priority: .high) { _ in @@ -83,7 +83,7 @@ class JSClosureAsyncTests: XCTestCase { XCTAssertEqual(result, 42.0) XCTAssertEqual(priority.value, .high) } - + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) func testAsyncOneshotClosureWithTaskExecutor() async throws { let executor = AnyTaskExecutor() @@ -93,7 +93,7 @@ class JSClosureAsyncTests: XCTestCase { let result = try await JSPromise(from: closure.function!())!.value() XCTAssertEqual(result, 42.0) } - + @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) func testAsyncOneshotClosureWithTaskExecutorPreference() async throws { let executor = AnyTaskExecutor() diff --git a/Tests/JavaScriptEventLoopTests/WebWorkerDedicatedExecutorTests.swift b/Tests/JavaScriptEventLoopTests/WebWorkerDedicatedExecutorTests.swift index aae8c2cea..b1dee1f3b 100644 --- a/Tests/JavaScriptEventLoopTests/WebWorkerDedicatedExecutorTests.swift +++ b/Tests/JavaScriptEventLoopTests/WebWorkerDedicatedExecutorTests.swift @@ -1,4 +1,4 @@ -#if compiler(>=6.1) && _runtime(_multithreaded) +#if _runtime(_multithreaded) import XCTest @testable import JavaScriptEventLoop diff --git a/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift b/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift index 69b3390dc..a40a039bd 100644 --- a/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift +++ b/Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift @@ -1,4 +1,4 @@ -#if compiler(>=6.1) && _runtime(_multithreaded) +#if _runtime(_multithreaded) import Synchronization import XCTest import _CJavaScriptKit // For swjs_get_worker_thread_id From 6f4009c27b9cab8fa47d032dc03dfc370fbd9970 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 11 Jun 2026 08:02:25 +0100 Subject: [PATCH 64/68] [codex] update to latest development snapshot toolchain (#763) * Use latest snapshot toolchain * Use native build system for examples * Use native build system in PackageToJS tests * Fix build-examples CI hang * Apply formatter output * Match formatter whitespace --- .github/workflows/test.yml | 12 ++-- Examples/ActorOnWebWorker/build.sh | 2 +- Examples/Basic/build.sh | 2 +- Examples/Embedded/build.sh | 2 +- Examples/Multithreading/build.sh | 2 +- Examples/OffscrenCanvas/build.sh | 2 +- Examples/PlayBridgeJS/build.sh | 2 +- Makefile | 2 +- Plugins/PackageToJS/Tests/ExampleTests.swift | 64 ++++++++++++++----- .../JavaScriptEventLoop+ExecutorFactory.swift | 13 ---- Utilities/build-examples.sh | 14 ++-- 11 files changed, 68 insertions(+), 49 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 58b2eb647..ef72ca352 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: entry: - os: ubuntu-24.04 toolchain: - download-url: https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a/swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a-ubuntu24.04.tar.gz + download-url: https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a-ubuntu24.04.tar.gz wasi-backend: Node target: "wasm32-unknown-wasip1" env: | @@ -26,7 +26,7 @@ jobs: target: "wasm32-unknown-wasip1" - os: ubuntu-22.04 toolchain: - download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a/swift-DEVELOPMENT-SNAPSHOT-2025-12-01-a-ubuntu22.04.tar.gz + download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a-ubuntu22.04.tar.gz wasi-backend: Node target: "wasm32-unknown-wasip1-threads" @@ -143,7 +143,7 @@ jobs: - uses: actions/checkout@v6 - uses: ./.github/actions/install-swift with: - download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2025-09-14-a/swift-DEVELOPMENT-SNAPSHOT-2025-09-14-a-ubuntu22.04.tar.gz + download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a-ubuntu22.04.tar.gz - run: make bootstrap - run: ./Utilities/bridge-js-generate.sh - name: Check if BridgeJS generated files are up-to-date @@ -160,16 +160,14 @@ jobs: - uses: actions/checkout@v6 - uses: ./.github/actions/install-swift with: - download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-03-09-a/swift-DEVELOPMENT-SNAPSHOT-2026-03-09-a-ubuntu22.04.tar.gz + download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a/swift-DEVELOPMENT-SNAPSHOT-2026-05-27-a-ubuntu22.04.tar.gz - uses: swiftwasm/setup-swiftwasm@v2 id: setup-wasm32-unknown-wasip1 with: { target: wasm32-unknown-wasip1 } - uses: swiftwasm/setup-swiftwasm@v2 id: setup-wasm32-unknown-wasip1-threads with: { target: wasm32-unknown-wasip1-threads } - - run: | - swift --version - ./Utilities/build-examples.sh + - run: ./Utilities/build-examples.sh env: SWIFT_SDK_ID_wasm32_unknown_wasip1_threads: ${{ steps.setup-wasm32-unknown-wasip1-threads.outputs.swift-sdk-id }} SWIFT_SDK_ID_wasm32_unknown_wasip1: ${{ steps.setup-wasm32-unknown-wasip1.outputs.swift-sdk-id }} diff --git a/Examples/ActorOnWebWorker/build.sh b/Examples/ActorOnWebWorker/build.sh index 4def77883..66c10a2c4 100755 --- a/Examples/ActorOnWebWorker/build.sh +++ b/Examples/ActorOnWebWorker/build.sh @@ -1,5 +1,5 @@ #!/bin/bash set -euxo pipefail -swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" \ +swift package --build-system native --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" \ plugin --allow-writing-to-package-directory \ js --use-cdn --output ./Bundle -c release diff --git a/Examples/Basic/build.sh b/Examples/Basic/build.sh index 2351f4e2d..07f436c4b 100755 --- a/Examples/Basic/build.sh +++ b/Examples/Basic/build.sh @@ -1,3 +1,3 @@ #!/bin/bash set -euxo pipefail -swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1}}" js --use-cdn -c "${1:-debug}" +swift package --build-system native --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1}}" js --use-cdn -c "${1:-debug}" diff --git a/Examples/Embedded/build.sh b/Examples/Embedded/build.sh index d756d8d1e..486f3581d 100755 --- a/Examples/Embedded/build.sh +++ b/Examples/Embedded/build.sh @@ -1,5 +1,5 @@ #!/bin/bash set -euxo pipefail package_dir="$(cd "$(dirname "$0")" && pwd)" -swift package --package-path "$package_dir" \ +swift package --build-system native --package-path "$package_dir" \ --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1}}-embedded" js -c release diff --git a/Examples/Multithreading/build.sh b/Examples/Multithreading/build.sh index 4def77883..66c10a2c4 100755 --- a/Examples/Multithreading/build.sh +++ b/Examples/Multithreading/build.sh @@ -1,5 +1,5 @@ #!/bin/bash set -euxo pipefail -swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" \ +swift package --build-system native --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" \ plugin --allow-writing-to-package-directory \ js --use-cdn --output ./Bundle -c release diff --git a/Examples/OffscrenCanvas/build.sh b/Examples/OffscrenCanvas/build.sh index 4def77883..66c10a2c4 100755 --- a/Examples/OffscrenCanvas/build.sh +++ b/Examples/OffscrenCanvas/build.sh @@ -1,5 +1,5 @@ #!/bin/bash set -euxo pipefail -swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" \ +swift package --build-system native --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" \ plugin --allow-writing-to-package-directory \ js --use-cdn --output ./Bundle -c release diff --git a/Examples/PlayBridgeJS/build.sh b/Examples/PlayBridgeJS/build.sh index 31c07896c..eb444a899 100755 --- a/Examples/PlayBridgeJS/build.sh +++ b/Examples/PlayBridgeJS/build.sh @@ -1,5 +1,5 @@ #!/bin/bash set -euxo pipefail -swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1}}" \ +swift package --build-system native --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1}}" \ plugin --allow-writing-to-package-directory \ js --use-cdn --output ./Bundle -c "${1:-debug}" diff --git a/Makefile b/Makefile index 270eb9b36..4b174e347 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ unittest: echo "SWIFT_SDK_ID is not set. Run 'swift sdk list' and pass a matching SDK, e.g. 'make unittest SWIFT_SDK_ID='."; \ exit 2; \ } - swift package --swift-sdk "$(SWIFT_SDK_ID)" \ + swift package --build-system native --swift-sdk "$(SWIFT_SDK_ID)" \ $(TRACING_ARGS) \ --disable-sandbox \ js test --prelude ./Tests/prelude.mjs -Xnode --expose-gc diff --git a/Plugins/PackageToJS/Tests/ExampleTests.swift b/Plugins/PackageToJS/Tests/ExampleTests.swift index 1f5bedcdc..d131b329a 100644 --- a/Plugins/PackageToJS/Tests/ExampleTests.swift +++ b/Plugins/PackageToJS/Tests/ExampleTests.swift @@ -246,11 +246,26 @@ extension Trait where Self == ConditionTrait { func basic() throws { let swiftSDKID = try #require(Self.getSwiftSDKID()) try withPackage(at: "Examples/Basic") { packageDir, _, runSwift in - try runSwift(["package", "--swift-sdk", swiftSDKID, "js"], [:]) - try runSwift(["package", "--swift-sdk", swiftSDKID, "js", "--debug-info-format", "dwarf"], [:]) - try runSwift(["package", "--swift-sdk", swiftSDKID, "js", "--debug-info-format", "name"], [:]) + try runSwift(["package", "--build-system", "native", "--swift-sdk", swiftSDKID, "js"], [:]) try runSwift( - ["package", "--swift-sdk", swiftSDKID, "-Xswiftc", "-DJAVASCRIPTKIT_WITHOUT_WEAKREFS", "js"], + [ + "package", "--build-system", "native", "--swift-sdk", swiftSDKID, "js", "--debug-info-format", + "dwarf", + ], + [:] + ) + try runSwift( + [ + "package", "--build-system", "native", "--swift-sdk", swiftSDKID, "js", "--debug-info-format", + "name", + ], + [:] + ) + try runSwift( + [ + "package", "--build-system", "native", "--swift-sdk", swiftSDKID, "-Xswiftc", + "-DJAVASCRIPTKIT_WITHOUT_WEAKREFS", "js", + ], [:] ) } @@ -266,7 +281,10 @@ extension Trait where Self == ConditionTrait { try runProcess(which("npm"), ["install"], [:]) try runProcess(which("npx"), ["playwright", "install", "chromium-headless-shell"], [:]) - try runSwift(["package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test"], [:]) + try runSwift( + ["package", "--build-system", "native", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test"], + [:] + ) try withTemporaryDirectory(body: { tempDir, _ in let scriptContent = """ const fs = require('fs'); @@ -278,7 +296,8 @@ extension Trait where Self == ConditionTrait { let scriptPath = tempDir.appending(path: "script.js") try runSwift( [ - "package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", + "package", "--build-system", "native", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", + "test", "-Xnode=--require=\(scriptPath.path)", ], [:] @@ -291,7 +310,10 @@ extension Trait where Self == ConditionTrait { ) }) try runSwift( - ["package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", "--environment", "browser"], + [ + "package", "--build-system", "native", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", + "--environment", "browser", + ], [:] ) } @@ -303,7 +325,10 @@ extension Trait where Self == ConditionTrait { let swiftPath = try #require(Self.getSwiftPath()) try withPackage(at: "Examples/Testing") { packageDir, runProcess, runSwift in try runSwift( - ["package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", "--enable-code-coverage"], + [ + "package", "--build-system", "native", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", + "--enable-code-coverage", + ], [ "LLVM_PROFDATA_PATH": URL(fileURLWithPath: swiftPath).appending(path: "llvm-profdata").path ] @@ -330,7 +355,7 @@ extension Trait where Self == ConditionTrait { func multithreading() throws { let swiftSDKID = try #require(Self.getSwiftSDKID()) try withPackage(at: "Examples/Multithreading") { packageDir, _, runSwift in - try runSwift(["package", "--swift-sdk", swiftSDKID, "js"], [:]) + try runSwift(["package", "--build-system", "native", "--swift-sdk", swiftSDKID, "js"], [:]) } } @@ -338,7 +363,7 @@ extension Trait where Self == ConditionTrait { func offscreenCanvas() throws { let swiftSDKID = try #require(Self.getSwiftSDKID()) try withPackage(at: "Examples/OffscrenCanvas") { packageDir, _, runSwift in - try runSwift(["package", "--swift-sdk", swiftSDKID, "js"], [:]) + try runSwift(["package", "--build-system", "native", "--swift-sdk", swiftSDKID, "js"], [:]) } } @@ -346,7 +371,7 @@ extension Trait where Self == ConditionTrait { func actorOnWebWorker() throws { let swiftSDKID = try #require(Self.getSwiftSDKID()) try withPackage(at: "Examples/ActorOnWebWorker") { packageDir, _, runSwift in - try runSwift(["package", "--swift-sdk", swiftSDKID, "js"], [:]) + try runSwift(["package", "--build-system", "native", "--swift-sdk", swiftSDKID, "js"], [:]) } } @@ -357,7 +382,7 @@ extension Trait where Self == ConditionTrait { let swiftSDKID = try #require(Self.getEmbeddedSwiftSDKID()) try withPackage(at: "Examples/Embedded") { packageDir, _, runSwift in try runSwift( - ["package", "--swift-sdk", swiftSDKID, "js", "-c", "release"], + ["package", "--build-system", "native", "--swift-sdk", swiftSDKID, "js", "-c", "release"], [ "JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM": "true" ] @@ -373,7 +398,10 @@ extension Trait where Self == ConditionTrait { at: "Plugins/PackageToJS/Fixtures/ContinuationLeakInTest/XCTest", assertTerminationStatus: { $0 != 0 } ) { packageDir, _, runSwift in - try runSwift(["package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test"], [:]) + try runSwift( + ["package", "--build-system", "native", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test"], + [:] + ) } } @@ -385,7 +413,10 @@ extension Trait where Self == ConditionTrait { at: "Plugins/PackageToJS/Fixtures/ContinuationLeakInTest/SwiftTesting", assertTerminationStatus: { $0 != 0 } ) { packageDir, _, runSwift in - try runSwift(["package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test"], [:]) + try runSwift( + ["package", "--build-system", "native", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test"], + [:] + ) } } @Test(.requireSwiftSDK) @@ -400,7 +431,7 @@ extension Trait where Self == ConditionTrait { try runSwift( ["package", "--disable-sandbox"] + Self.stackSizeLinkerFlags + [ - "--swift-sdk", swiftSDKID, "js", "test", "--environment", "browser", + "--build-system", "native", "--swift-sdk", swiftSDKID, "js", "test", "--environment", "browser", "--playwright-expose", "../expose.js", ], [:] @@ -421,7 +452,8 @@ extension Trait where Self == ConditionTrait { try runSwift( [ - "package", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", "--environment", "browser", + "package", "--build-system", "native", "--disable-sandbox", "--swift-sdk", swiftSDKID, "js", "test", + "--environment", "browser", "--playwright-expose", "../expose.js", ], [:] diff --git a/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift b/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift index 0d2010016..17aedca3b 100644 --- a/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift +++ b/Sources/JavaScriptEventLoop/JavaScriptEventLoop+ExecutorFactory.swift @@ -57,25 +57,12 @@ extension JavaScriptEventLoop: SchedulingExecutor { #endif // #if compiler(>=6.4) (Embedded) #else // #if hasFeature(Embedded) let duration: Duration - // Handle clocks we know if let _ = clock as? ContinuousClock { duration = delay as! ContinuousClock.Duration } else if let _ = clock as? SuspendingClock { duration = delay as! SuspendingClock.Duration } else { - #if compiler(>=6.4) - // Hand-off the scheduling work to Clock implementation for unknown clocks. - // Clock.enqueue is only available in the development branch (6.4+). - clock.enqueue( - job, - on: self, - at: clock.now.advanced(by: delay), - tolerance: tolerance - ) - return - #else fatalError("Unsupported clock type; only ContinuousClock and SuspendingClock are supported") - #endif // #if compiler(>=6.4) (non-Embedded) } let milliseconds = Self.delayInMilliseconds(from: duration) self.enqueue( diff --git a/Utilities/build-examples.sh b/Utilities/build-examples.sh index bc84e6943..77e923322 100755 --- a/Utilities/build-examples.sh +++ b/Utilities/build-examples.sh @@ -6,12 +6,14 @@ EXCLUDED_EXAMPLES=() for example in Examples/*; do skip_example=false - for excluded in "${EXCLUDED_EXAMPLES[@]}"; do - if [[ "$example" == *"$excluded"* ]]; then - skip_example=true - break - fi - done + if ((${#EXCLUDED_EXAMPLES[@]})); then + for excluded in "${EXCLUDED_EXAMPLES[@]}"; do + if [[ "$example" == *"$excluded"* ]]; then + skip_example=true + break + fi + done + fi if [ "$skip_example" = true ]; then echo "Skipping $example" continue From 3396b5eeda2a979679996bdeeddcf43ad3d26eff Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Thu, 11 Jun 2026 08:05:42 +0100 Subject: [PATCH 65/68] [codex] BridgeJS: support associated-value enums in import and async paths (#764) * BridgeJS: support associated-value enums in import and async paths * Format Swift sources * Match Swift 6.1 formatter output --- .../Sources/BridgeJSCore/ImportTS.swift | 14 +- .../Sources/BridgeJSLink/JSGlueGen.swift | 44 +- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 4 +- .../BridgeJSToolTests/DiagnosticsTests.swift | 13 +- .../MacroSwift/AsyncAssociatedValueEnum.swift | 13 + .../EnumAssociatedValueImport.swift | 14 + .../AsyncAssociatedValueEnum.json | 129 ++++++ .../AsyncAssociatedValueEnum.swift | 116 +++++ .../EnumAssociatedValueImport.json | 194 ++++++++ .../EnumAssociatedValueImport.swift | 112 +++++ .../AsyncAssociatedValueEnum.d.ts | 33 ++ .../AsyncAssociatedValueEnum.js | 414 ++++++++++++++++++ .../EnumAssociatedValueImport.d.ts | 39 ++ .../EnumAssociatedValueImport.js | 323 ++++++++++++++ .../AsyncImportTests.swift | 35 ++ .../BridgeJSRuntimeTests/ExportAPITests.swift | 10 + .../Generated/BridgeJS.swift | 364 +++++++++++++++ .../Generated/JavaScript/BridgeJS.json | 317 ++++++++++++++ .../BridgeJSRuntimeTests/ImportAPITests.swift | 35 ++ .../JavaScript/AsyncImportTests.mjs | 19 +- Tests/prelude.mjs | 6 + 21 files changed, 2196 insertions(+), 52 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncAssociatedValueEnum.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumAssociatedValueImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 02c623918..a6a73b8f7 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -936,12 +936,7 @@ extension BridgeType { let wasmType = rawType.wasmCoreType ?? .i32 return LoweringParameterInfo(loweredParameters: [("value", wasmType)]) case .associatedValueEnum: - switch context { - case .importTS: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .exportSwift: - return LoweringParameterInfo(loweredParameters: [("caseId", .i32)]) - } + return LoweringParameterInfo(loweredParameters: [("caseId", .i32)]) case .swiftStruct: switch context { case .importTS: @@ -1011,12 +1006,7 @@ extension BridgeType { let wasmType = rawType.wasmCoreType ?? .i32 return LiftingReturnInfo(valueToLift: wasmType) case .associatedValueEnum: - switch context { - case .importTS: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .exportSwift: - return LiftingReturnInfo(valueToLift: .i32) - } + return LiftingReturnInfo(valueToLift: .i32) case .swiftStruct: switch context { case .importTS: diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index aed01da5a..ac2144bbc 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -1422,27 +1422,19 @@ struct IntrinsicJSFragment: Sendable { return try .optionalLiftParameter(wrappedType: wrappedType, kind: kind, context: context) case .rawValueEnum(_, .string): return .stringLiftParameter case .associatedValueEnum(let fullName): - switch context { - case .importTS: - throw BridgeJSLinkError( - message: - "Associated value enums are not supported to be passed as parameters to imported JS functions: \(fullName)" - ) - case .exportSwift: - let base = fullName.components(separatedBy: ".").last ?? fullName - return IntrinsicJSFragment( - parameters: ["caseId"], - printCode: { arguments, context in - let (scope, printer) = (context.scope, context.printer) - let caseId = arguments[0] - let resultVar = scope.variable("enumValue") - printer.write( - "const \(resultVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(caseId));" - ) - return [resultVar] - } - ) - } + let base = fullName.components(separatedBy: ".").last ?? fullName + return IntrinsicJSFragment( + parameters: ["caseId"], + printCode: { arguments, context in + let (scope, printer) = (context.scope, context.printer) + let caseId = arguments[0] + let resultVar = scope.variable("enumValue") + printer.write( + "const \(resultVar) = \(JSGlueVariableScope.reservedEnumHelpers).\(base).lift(\(caseId));" + ) + return [resultVar] + } + ) case .swiftStruct(let fullName): switch context { case .importTS: @@ -1502,15 +1494,7 @@ struct IntrinsicJSFragment: Sendable { return try .optionalLowerReturn(wrappedType: wrappedType, kind: kind) case .rawValueEnum(_, .string): return .stringLowerReturn case .associatedValueEnum(let fullName): - switch context { - case .importTS: - throw BridgeJSLinkError( - message: - "Associated value enums are not supported to be returned from imported JS functions: \(fullName)" - ) - case .exportSwift: - return associatedValueLowerReturn(fullName: fullName) - } + return associatedValueLowerReturn(fullName: fullName) case .swiftStruct(let fullName): switch context { case .importTS: diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index f1e2e80fe..830132481 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -1611,10 +1611,10 @@ extension BridgeType { /// Whether a value of this type can be passed to a generated `Promise_resolve_` /// settlement helper, i.e. lowered through the imported-parameter ABI. Every `async` /// exported return settles through `_bjs_makePromise`; the few types that cannot be lowered - /// (associated-value enums, protocols, namespace enums, and their compositions) are diagnosed. + /// (protocols, namespace enums, and their compositions) are diagnosed. public var isAsyncResolvable: Bool { switch self { - case .associatedValueEnum, .swiftProtocol, .namespaceEnum: + case .swiftProtocol, .namespaceEnum: return false case .nullable(let wrapped, _): return wrapped.isAsyncResolvable diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift index 82747f74e..ae12b6566 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift @@ -309,15 +309,14 @@ import Testing @Test func asyncReturnOfUnsupportedTypeIsDiagnosed() throws { - // An associated-value enum can be neither lowered through the imported-parameter ABI - // nor settled via `_bjs_makePromise`, so an async return of one must be diagnosed. + // Protocol existentials still can't be lowered through the imported-parameter ABI, so + // an async return of one must still be diagnosed. let source = """ - @JS enum Payload { - case text(String) - case number(Int) + @JS protocol PayloadDelegate { + func notify() } - @JS func loadPayload() async -> Payload { - .number(1) + @JS func loadPayload() async -> PayloadDelegate { + fatalError() } """ let swiftAPI = SwiftToSkeleton( diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncAssociatedValueEnum.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncAssociatedValueEnum.swift new file mode 100644 index 000000000..662e01fce --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/AsyncAssociatedValueEnum.swift @@ -0,0 +1,13 @@ +@JS enum AsyncPayloadResult { + case success(String) + case failure(Int) + case idle +} + +@JS func asyncRoundTripAssociatedValueEnum(_ value: AsyncPayloadResult) async -> AsyncPayloadResult { + return value +} + +@JS func asyncRoundTripOptionalAssociatedValueEnum(_ value: AsyncPayloadResult?) async -> AsyncPayloadResult? { + return value +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumAssociatedValueImport.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumAssociatedValueImport.swift new file mode 100644 index 000000000..aa404b72c --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/EnumAssociatedValueImport.swift @@ -0,0 +1,14 @@ +@JS enum PayloadSignal { + case start(String) + case stop(Int) + case idle +} + +// Associated-value enums bridge as their `Int32` case ID plus stack payload in imported +// function parameters and return values. +@JSClass struct PayloadSignalControls { + @JSFunction func send(_ signal: PayloadSignal) throws(JSException) + @JSFunction func current() throws(JSException) -> PayloadSignal + @JSFunction static func roundTrip(_ signal: PayloadSignal) throws(JSException) -> PayloadSignal + @JSFunction func roundTripOptional(_ signal: PayloadSignal?) throws(JSException) -> PayloadSignal? +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.json new file mode 100644 index 000000000..6b0d70453 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.json @@ -0,0 +1,129 @@ +{ + "exported" : { + "classes" : [ + + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + + ], + "name" : "idle" + } + ], + "emitStyle" : "const", + "name" : "AsyncPayloadResult", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "AsyncPayloadResult", + "tsFullPath" : "AsyncPayloadResult" + } + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_asyncRoundTripAssociatedValueEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripAssociatedValueEnum", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripOptionalAssociatedValueEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripOptionalAssociatedValueEnum", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + }, + "_1" : "null" + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ 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 new file mode 100644 index 000000000..7ceb8cfe3 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/AsyncAssociatedValueEnum.swift @@ -0,0 +1,116 @@ +extension AsyncPayloadResult: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> AsyncPayloadResult { + switch caseId { + case 0: + return .success(String.bridgeJSStackPop()) + case 1: + return .failure(Int.bridgeJSStackPop()) + case 2: + return .idle + default: + fatalError("Unknown AsyncPayloadResult case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .success(let param0): + param0.bridgeJSStackPush() + return Int32(0) + case .failure(let param0): + param0.bridgeJSStackPush() + return Int32(1) + case .idle: + return Int32(2) + } + } +} + +@_expose(wasm, "bjs_asyncRoundTripAssociatedValueEnum") +@_cdecl("bjs_asyncRoundTripAssociatedValueEnum") +public func _bjs_asyncRoundTripAssociatedValueEnum(_ value: Int32) -> Int32 { + #if arch(wasm32) + let _tmp_value = AsyncPayloadResult.bridgeJSLiftParameter(value) + return _bjs_makePromise(resolve: Promise_resolve_18AsyncPayloadResultO, reject: Promise_reject) { + return await asyncRoundTripAssociatedValueEnum(_: _tmp_value) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalAssociatedValueEnum") +@_cdecl("bjs_asyncRoundTripOptionalAssociatedValueEnum") +public func _bjs_asyncRoundTripOptionalAssociatedValueEnum(_ valueIsSome: Int32, _ valueCaseId: Int32) -> Int32 { + #if arch(wasm32) + let _tmp_value = Optional.bridgeJSLiftParameter(valueIsSome, valueCaseId) + return _bjs_makePromise(resolve: Promise_resolve_Sq18AsyncPayloadResultO, reject: Promise_reject) { + return await asyncRoundTripOptionalAssociatedValueEnum(_: _tmp_value) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_reject_TestModule") +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void +#else +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_reject_TestModule(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + return promise_reject_TestModule_extern(promise, valueKind, valuePayload1, valuePayload2) +} + +func _$Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueKind, valuePayload1, valuePayload2) = value.bridgeJSLowerParameter() + promise_reject_TestModule(promiseValue, valueKind, valuePayload1, valuePayload2) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_18AsyncPayloadResultO(_ promise: JSObject, _ value: AsyncPayloadResult) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_18AsyncPayloadResultO") +fileprivate func promise_resolve_TestModule_18AsyncPayloadResultO_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_18AsyncPayloadResultO_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_18AsyncPayloadResultO(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_18AsyncPayloadResultO_extern(promise, value) +} + +func _$Promise_resolve_18AsyncPayloadResultO(_ promise: JSObject, _ value: AsyncPayloadResult) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueCaseId = value.bridgeJSLowerParameter() + promise_resolve_TestModule_18AsyncPayloadResultO(promiseValue, valueCaseId) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq18AsyncPayloadResultO(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_Sq18AsyncPayloadResultO") +fileprivate func promise_resolve_TestModule_Sq18AsyncPayloadResultO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueCaseId: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_Sq18AsyncPayloadResultO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueCaseId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_Sq18AsyncPayloadResultO(_ promise: Int32, _ valueIsSome: Int32, _ valueCaseId: Int32) -> Void { + return promise_resolve_TestModule_Sq18AsyncPayloadResultO_extern(promise, valueIsSome, valueCaseId) +} + +func _$Promise_resolve_Sq18AsyncPayloadResultO(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueIsSome, valueCaseId) = value.bridgeJSLowerParameter() + promise_resolve_TestModule_Sq18AsyncPayloadResultO(promiseValue, valueIsSome, valueCaseId) + if let error = _swift_js_take_exception() { throw error } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.json new file mode 100644 index 000000000..23cb1b0f0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.json @@ -0,0 +1,194 @@ +{ + "exported" : { + "classes" : [ + + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "start" + }, + { + "associatedValues" : [ + { + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "stop" + }, + { + "associatedValues" : [ + + ], + "name" : "idle" + } + ], + "emitStyle" : "const", + "name" : "PayloadSignal", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "PayloadSignal", + "tsFullPath" : "PayloadSignal" + } + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "imported" : { + "children" : [ + { + "functions" : [ + + ], + "types" : [ + { + "accessLevel" : "internal", + "getters" : [ + + ], + "methods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "send", + "parameters" : [ + { + "name" : "signal", + "type" : { + "associatedValueEnum" : { + "_0" : "PayloadSignal" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "current", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "PayloadSignal" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "roundTripOptional", + "parameters" : [ + { + "name" : "signal", + "type" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "PayloadSignal" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "PayloadSignal" + } + }, + "_1" : "null" + } + } + } + ], + "name" : "PayloadSignalControls", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "roundTrip", + "parameters" : [ + { + "name" : "signal", + "type" : { + "associatedValueEnum" : { + "_0" : "PayloadSignal" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "PayloadSignal" + } + } + } + ] + } + ] + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ 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 new file mode 100644 index 000000000..5e1db5c72 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/EnumAssociatedValueImport.swift @@ -0,0 +1,112 @@ +extension PayloadSignal: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> PayloadSignal { + switch caseId { + case 0: + return .start(String.bridgeJSStackPop()) + case 1: + return .stop(Int.bridgeJSStackPop()) + case 2: + return .idle + default: + fatalError("Unknown PayloadSignal case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .start(let param0): + param0.bridgeJSStackPush() + return Int32(0) + case .stop(let param0): + param0.bridgeJSStackPush() + return Int32(1) + case .idle: + return Int32(2) + } + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_PayloadSignalControls_roundTrip_static") +fileprivate func bjs_PayloadSignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 +#else +fileprivate func bjs_PayloadSignalControls_roundTrip_static_extern(_ signal: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_PayloadSignalControls_roundTrip_static(_ signal: Int32) -> Int32 { + return bjs_PayloadSignalControls_roundTrip_static_extern(signal) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_PayloadSignalControls_send") +fileprivate func bjs_PayloadSignalControls_send_extern(_ self: Int32, _ signal: Int32) -> Void +#else +fileprivate func bjs_PayloadSignalControls_send_extern(_ self: Int32, _ signal: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_PayloadSignalControls_send(_ self: Int32, _ signal: Int32) -> Void { + return bjs_PayloadSignalControls_send_extern(self, signal) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_PayloadSignalControls_current") +fileprivate func bjs_PayloadSignalControls_current_extern(_ self: Int32) -> Int32 +#else +fileprivate func bjs_PayloadSignalControls_current_extern(_ self: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_PayloadSignalControls_current(_ self: Int32) -> Int32 { + return bjs_PayloadSignalControls_current_extern(self) +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_PayloadSignalControls_roundTripOptional") +fileprivate func bjs_PayloadSignalControls_roundTripOptional_extern(_ self: Int32, _ signalIsSome: Int32, _ signalCaseId: Int32) -> Int32 +#else +fileprivate func bjs_PayloadSignalControls_roundTripOptional_extern(_ self: Int32, _ signalIsSome: Int32, _ signalCaseId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_PayloadSignalControls_roundTripOptional(_ self: Int32, _ signalIsSome: Int32, _ signalCaseId: Int32) -> Int32 { + return bjs_PayloadSignalControls_roundTripOptional_extern(self, signalIsSome, signalCaseId) +} + +func _$PayloadSignalControls_roundTrip(_ signal: PayloadSignal) throws(JSException) -> PayloadSignal { + let signalCaseId = signal.bridgeJSLowerParameter() + let ret = bjs_PayloadSignalControls_roundTrip_static(signalCaseId) + if let error = _swift_js_take_exception() { + throw error + } + return PayloadSignal.bridgeJSLiftReturn(ret) +} + +func _$PayloadSignalControls_send(_ self: JSObject, _ signal: PayloadSignal) throws(JSException) -> Void { + let selfValue = self.bridgeJSLowerParameter() + let signalCaseId = signal.bridgeJSLowerParameter() + bjs_PayloadSignalControls_send(selfValue, signalCaseId) + if let error = _swift_js_take_exception() { + throw error + } +} + +func _$PayloadSignalControls_current(_ self: JSObject) throws(JSException) -> PayloadSignal { + let selfValue = self.bridgeJSLowerParameter() + let ret = bjs_PayloadSignalControls_current(selfValue) + if let error = _swift_js_take_exception() { + throw error + } + return PayloadSignal.bridgeJSLiftReturn(ret) +} + +func _$PayloadSignalControls_roundTripOptional(_ self: JSObject, _ signal: Optional) throws(JSException) -> Optional { + let selfValue = self.bridgeJSLowerParameter() + let (signalIsSome, signalCaseId) = signal.bridgeJSLowerParameter() + let ret = bjs_PayloadSignalControls_roundTripOptional(selfValue, signalIsSome, signalCaseId) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn(ret) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts new file mode 100644 index 000000000..d25336ef7 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.d.ts @@ -0,0 +1,33 @@ +// 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 AsyncPayloadResultValues: { + readonly Tag: { + readonly Success: 0; + readonly Failure: 1; + readonly Idle: 2; + }; +}; + +export type AsyncPayloadResultTag = + { tag: typeof AsyncPayloadResultValues.Tag.Success; param0: string } | { tag: typeof AsyncPayloadResultValues.Tag.Failure; param0: number } | { tag: typeof AsyncPayloadResultValues.Tag.Idle } + +export type AsyncPayloadResultObject = typeof AsyncPayloadResultValues; + +export type Exports = { + asyncRoundTripAssociatedValueEnum(value: AsyncPayloadResultTag): Promise; + asyncRoundTripOptionalAssociatedValueEnum(value: AsyncPayloadResultTag | null): Promise; + AsyncPayloadResult: AsyncPayloadResultObject +} +export type Imports = { +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => 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 new file mode 100644 index 000000000..69e4a4928 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncAssociatedValueEnum.js @@ -0,0 +1,414 @@ +// 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 AsyncPayloadResultValues = { + Tag: { + Success: 0, + Failure: 1, + Idle: 2, + }, +}; +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 = {}; + + let _exports = null; + let bjs = null; + 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_createAsyncPayloadResultValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case AsyncPayloadResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return AsyncPayloadResultValues.Tag.Success; + } + case AsyncPayloadResultValues.Tag.Failure: { + i32Stack.push((value.param0 | 0)); + return AsyncPayloadResultValues.Tag.Failure; + } + case AsyncPayloadResultValues.Tag.Idle: { + return AsyncPayloadResultValues.Tag.Idle; + } + default: throw new Error("Unknown AsyncPayloadResultValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case AsyncPayloadResultValues.Tag.Success: { + const string = strStack.pop(); + return { tag: AsyncPayloadResultValues.Tag.Success, param0: string }; + } + case AsyncPayloadResultValues.Tag.Failure: { + const int = i32Stack.pop(); + return { tag: AsyncPayloadResultValues.Tag.Failure, param0: int }; + } + case AsyncPayloadResultValues.Tag.Idle: return { tag: AsyncPayloadResultValues.Tag.Idle }; + default: throw new Error("Unknown AsyncPayloadResultValues tag returned from Swift: " + String(tag)); + } + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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))); + } + 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["promise_resolve_TestModule_18AsyncPayloadResultO"] = function(promise, value) { + try { + const enumValue = enumHelpers.AsyncPayloadResult.lift(value); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(enumValue); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_Sq18AsyncPayloadResultO"] = function(promise, valueIsSome, valueCaseId) { + try { + let optResult; + if (valueIsSome) { + const enumValue = enumHelpers.AsyncPayloadResult.lift(valueCaseId); + optResult = enumValue; + } else { + optResult = null; + } + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(optResult); + } catch (error) { + setException(error); + } + } + bjs["promise_reject_TestModule"] = function(promise, valueKind, valuePayload1, valuePayload2) { + try { + const jsValue = __bjs_jsValueLift(valueKind, valuePayload1, valuePayload2); + swift.memory.getObject(promise)[__bjs_promiseSettlers].reject(jsValue); + } catch (error) { + setException(error); + } + } + 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) {} + }, + 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const AsyncPayloadResultHelpers = __bjs_createAsyncPayloadResultValuesHelpers(); + enumHelpers.AsyncPayloadResult = AsyncPayloadResultHelpers; + + const exports = { + asyncRoundTripAssociatedValueEnum: function bjs_asyncRoundTripAssociatedValueEnum(value) { + const valueCaseId = enumHelpers.AsyncPayloadResult.lower(value); + const ret = instance.exports.bjs_asyncRoundTripAssociatedValueEnum(valueCaseId); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + asyncRoundTripOptionalAssociatedValueEnum: function bjs_asyncRoundTripOptionalAssociatedValueEnum(value) { + const isSome = value != null; + let result; + if (isSome) { + const valueCaseId = enumHelpers.AsyncPayloadResult.lower(value); + result = valueCaseId; + } else { + result = 0; + } + const ret = instance.exports.bjs_asyncRoundTripOptionalAssociatedValueEnum(+isSome, result); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }, + AsyncPayloadResult: AsyncPayloadResultValues, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts new file mode 100644 index 000000000..d29256af4 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.d.ts @@ -0,0 +1,39 @@ +// 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 PayloadSignalValues: { + readonly Tag: { + readonly Start: 0; + readonly Stop: 1; + readonly Idle: 2; + }; +}; + +export type PayloadSignalTag = + { tag: typeof PayloadSignalValues.Tag.Start; param0: string } | { tag: typeof PayloadSignalValues.Tag.Stop; param0: number } | { tag: typeof PayloadSignalValues.Tag.Idle } + +export type PayloadSignalObject = typeof PayloadSignalValues; + +export interface PayloadSignalControls { + send(signal: PayloadSignalTag): void; + current(): PayloadSignalTag; + roundTripOptional(signal: PayloadSignalTag | null): PayloadSignalTag | null; +} +export type Exports = { + PayloadSignal: PayloadSignalObject +} +export type Imports = { + PayloadSignalControls: { + roundTrip(signal: PayloadSignalTag): PayloadSignalTag; + } +} +export function createInstantiator(options: { + imports: Imports; +}, swift: any): Promise<{ + addImports: (importObject: WebAssembly.Imports) => void; + setInstance: (instance: WebAssembly.Instance) => 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 new file mode 100644 index 000000000..1688dc94d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValueImport.js @@ -0,0 +1,323 @@ +// 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 PayloadSignalValues = { + Tag: { + Start: 0, + Stop: 1, + Idle: 2, + }, +}; +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 = {}; + + let _exports = null; + let bjs = null; + const __bjs_createPayloadSignalValuesHelpers = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case PayloadSignalValues.Tag.Start: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + return PayloadSignalValues.Tag.Start; + } + case PayloadSignalValues.Tag.Stop: { + i32Stack.push((value.param0 | 0)); + return PayloadSignalValues.Tag.Stop; + } + case PayloadSignalValues.Tag.Idle: { + return PayloadSignalValues.Tag.Idle; + } + default: throw new Error("Unknown PayloadSignalValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case PayloadSignalValues.Tag.Start: { + const string = strStack.pop(); + return { tag: PayloadSignalValues.Tag.Start, param0: string }; + } + case PayloadSignalValues.Tag.Stop: { + const int = i32Stack.pop(); + return { tag: PayloadSignalValues.Tag.Stop, param0: int }; + } + case PayloadSignalValues.Tag.Idle: return { tag: PayloadSignalValues.Tag.Idle }; + default: throw new Error("Unknown PayloadSignalValues tag returned from Swift: " + String(tag)); + } + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + 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); + 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, len); + 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))); + } + 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) {} + const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_PayloadSignalControls_roundTrip_static"] = function bjs_PayloadSignalControls_roundTrip_static(signal) { + try { + const enumValue = enumHelpers.PayloadSignal.lift(signal); + let ret = imports.PayloadSignalControls.roundTrip(enumValue); + const caseId = enumHelpers.PayloadSignal.lower(ret); + return caseId; + } catch (error) { + setException(error); + } + } + TestModule["bjs_PayloadSignalControls_send"] = function bjs_PayloadSignalControls_send(self, signal) { + try { + const enumValue = enumHelpers.PayloadSignal.lift(signal); + swift.memory.getObject(self).send(enumValue); + } catch (error) { + setException(error); + } + } + TestModule["bjs_PayloadSignalControls_current"] = function bjs_PayloadSignalControls_current(self) { + try { + let ret = swift.memory.getObject(self).current(); + const caseId = enumHelpers.PayloadSignal.lower(ret); + return caseId; + } catch (error) { + setException(error); + } + } + TestModule["bjs_PayloadSignalControls_roundTripOptional"] = function bjs_PayloadSignalControls_roundTripOptional(self, signalIsSome, signalCaseId) { + try { + let optResult; + if (signalIsSome) { + const enumValue = enumHelpers.PayloadSignal.lift(signalCaseId); + optResult = enumValue; + } else { + optResult = null; + } + let ret = swift.memory.getObject(self).roundTripOptional(optResult); + const isSome = ret != null; + if (isSome) { + const caseId = enumHelpers.PayloadSignal.lower(ret); + return caseId; + } else { + return -1; + } + } 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) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const PayloadSignalHelpers = __bjs_createPayloadSignalValuesHelpers(); + enumHelpers.PayloadSignal = PayloadSignalHelpers; + + const exports = { + PayloadSignal: PayloadSignalValues, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/AsyncImportTests.swift b/Tests/BridgeJSRuntimeTests/AsyncImportTests.swift index 041f251f4..a092d111c 100644 --- a/Tests/BridgeJSRuntimeTests/AsyncImportTests.swift +++ b/Tests/BridgeJSRuntimeTests/AsyncImportTests.swift @@ -1,6 +1,12 @@ import Testing import JavaScriptKit +@JS enum AsyncImportedPayloadResult: Equatable { + case success(String) + case failure(Int) + case idle +} + @JSClass struct AsyncImportImports { @JSFunction static func jsAsyncRoundTripVoid() async throws(JSException) @JSFunction static func jsAsyncRoundTripNumber(_ v: Double) async throws(JSException) -> Double @@ -12,6 +18,12 @@ import JavaScriptKit @JSFunction static func jsAsyncRoundTripIntArray(_ values: [Double]) async throws(JSException) -> [Double] @JSFunction static func jsAsyncRoundTripStringArray(_ values: [String]) async throws(JSException) -> [String] @JSFunction static func jsAsyncRoundTripFeatureFlag(_ v: FeatureFlag) async throws(JSException) -> FeatureFlag + @JSFunction static func jsAsyncRoundTripAssociatedValueEnum( + _ v: AsyncImportedPayloadResult + ) async throws(JSException) -> AsyncImportedPayloadResult + @JSFunction static func jsAsyncRoundTripOptionalAssociatedValueEnum( + _ v: AsyncImportedPayloadResult? + ) async throws(JSException) -> AsyncImportedPayloadResult? } @Suite struct AsyncImportTests { @@ -69,6 +81,29 @@ import JavaScriptKit try #expect(await AsyncImportImports.jsAsyncRoundTripFeatureFlag(v) == v) } + @Test func asyncRoundTripAssociatedValueEnum() async throws { + let values: [AsyncImportedPayloadResult] = [ + .success("ok"), + .failure(7), + .idle, + ] + for value in values { + try #expect(await AsyncImportImports.jsAsyncRoundTripAssociatedValueEnum(value) == value) + } + } + + @Test func asyncRoundTripOptionalAssociatedValueEnum() async throws { + let values: [AsyncImportedPayloadResult?] = [ + .some(.success("ok")), + .some(.failure(7)), + .some(.idle), + nil, + ] + for value in values { + try #expect(await AsyncImportImports.jsAsyncRoundTripOptionalAssociatedValueEnum(value) == value) + } + } + // MARK: - Structured return type @Test func fetchWeatherData() async throws { diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index a0453b8f8..282b7cc60 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -334,6 +334,16 @@ extension StaticCalculator { @JS func asyncRoundTripOptionalFileSize(_ v: FileSize?) async -> FileSize? { v } +@JS enum AsyncPayloadResult: Equatable { + case success(String) + case failure(Int) + case idle +} + +@JS func asyncRoundTripAssociatedValueEnum(_ v: AsyncPayloadResult) async -> AsyncPayloadResult { v } + +@JS func asyncRoundTripOptionalAssociatedValueEnum(_ v: AsyncPayloadResult?) async -> AsyncPayloadResult? { v } + @JS func setHttpStatus(_ status: HttpStatus) -> HttpStatus { return status } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 78bac8952..c02cb72f7 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -1924,6 +1924,67 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11 #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending AsyncImportedPayloadResult) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0CaseId = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y(callbackValue, param0CaseId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending AsyncImportedPayloadResult) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending AsyncImportedPayloadResult) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending AsyncImportedPayloadResult) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(AsyncImportedPayloadResult.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void @@ -2352,6 +2413,67 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSd #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0CaseId: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0CaseId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y(_ callback: Int32, _ param0IsSome: Int32, _ param0CaseId: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y_extern(callback, param0IsSome, param0CaseId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Optional) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0CaseId) = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y(callbackValue, param0IsSome, param0CaseId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Optional) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Optional) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSq26AsyncImportedPayloadResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0CaseId: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Optional) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Optional.bridgeJSLiftParameter(param0IsSome, param0CaseId)) + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSqSS_y_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void @@ -3816,6 +3938,34 @@ public func _bjs_ArraySupportExports_static_multiOptionalArraySecond() -> Void { #endif } +extension AsyncImportedPayloadResult: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> AsyncImportedPayloadResult { + switch caseId { + case 0: + return .success(String.bridgeJSStackPop()) + case 1: + return .failure(Int.bridgeJSStackPop()) + case 2: + return .idle + default: + fatalError("Unknown AsyncImportedPayloadResult case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .success(let param0): + param0.bridgeJSStackPush() + return Int32(0) + case .failure(let param0): + param0.bridgeJSStackPush() + return Int32(1) + case .idle: + return Int32(2) + } + } +} + @_expose(wasm, "bjs_DefaultArgumentExports_static_testStringDefault") @_cdecl("bjs_DefaultArgumentExports_static_testStringDefault") public func _bjs_DefaultArgumentExports_static_testStringDefault(_ messageBytes: Int32, _ messageLength: Int32) -> Void { @@ -4127,6 +4277,34 @@ extension TSDirection: _BridgedSwiftCaseEnum { extension TSTheme: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { } +extension AsyncPayloadResult: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> AsyncPayloadResult { + switch caseId { + case 0: + return .success(String.bridgeJSStackPop()) + case 1: + return .failure(Int.bridgeJSStackPop()) + case 2: + return .idle + default: + fatalError("Unknown AsyncPayloadResult case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .success(let param0): + param0.bridgeJSStackPush() + return Int32(0) + case .failure(let param0): + param0.bridgeJSStackPush() + return Int32(1) + case .idle: + return Int32(2) + } + } +} + @_expose(wasm, "bjs_Utils_StringUtils_static_uppercase") @_cdecl("bjs_Utils_StringUtils_static_uppercase") public func _bjs_Utils_StringUtils_static_uppercase(_ textBytes: Int32, _ textLength: Int32) -> Void { @@ -4870,6 +5048,34 @@ extension LightColor: _BridgedSwiftCaseEnum { } } +extension ImportedPayloadSignal: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> ImportedPayloadSignal { + switch caseId { + case 0: + return .start(String.bridgeJSStackPop()) + case 1: + return .stop(Int.bridgeJSStackPop()) + case 2: + return .idle + default: + fatalError("Unknown ImportedPayloadSignal case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .start(let param0): + param0.bridgeJSStackPush() + return Int32(0) + case .stop(let param0): + param0.bridgeJSStackPush() + return Int32(1) + case .idle: + return Int32(2) + } + } +} + @_expose(wasm, "bjs_IntegerTypesSupportExports_static_roundTripInt") @_cdecl("bjs_IntegerTypesSupportExports_static_roundTripInt") public func _bjs_IntegerTypesSupportExports_static_roundTripInt(_ v: Int32) -> Int32 { @@ -7543,6 +7749,32 @@ public func _bjs_asyncRoundTripOptionalFileSize(_ vIsSome: Int32, _ vValue: Int6 #endif } +@_expose(wasm, "bjs_asyncRoundTripAssociatedValueEnum") +@_cdecl("bjs_asyncRoundTripAssociatedValueEnum") +public func _bjs_asyncRoundTripAssociatedValueEnum(_ v: Int32) -> Int32 { + #if arch(wasm32) + let _tmp_v = AsyncPayloadResult.bridgeJSLiftParameter(v) + return _bjs_makePromise(resolve: Promise_resolve_18AsyncPayloadResultO, reject: Promise_reject) { + return await asyncRoundTripAssociatedValueEnum(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_asyncRoundTripOptionalAssociatedValueEnum") +@_cdecl("bjs_asyncRoundTripOptionalAssociatedValueEnum") +public func _bjs_asyncRoundTripOptionalAssociatedValueEnum(_ vIsSome: Int32, _ vCaseId: Int32) -> Int32 { + #if arch(wasm32) + let _tmp_v = Optional.bridgeJSLiftParameter(vIsSome, vCaseId) + return _bjs_makePromise(resolve: Promise_resolve_Sq18AsyncPayloadResultO, reject: Promise_reject) { + return await asyncRoundTripOptionalAssociatedValueEnum(_: _tmp_v) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_setHttpStatus") @_cdecl("bjs_setHttpStatus") public func _bjs_setHttpStatus(_ status: Int32) -> Int32 { @@ -11797,6 +12029,48 @@ func _$Promise_resolve_Sq8FileSizeO(_ promise: JSObject, _ value: Optional Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_18AsyncPayloadResultO_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_18AsyncPayloadResultO(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_18AsyncPayloadResultO_extern(promise, value) +} + +func _$Promise_resolve_18AsyncPayloadResultO(_ promise: JSObject, _ value: AsyncPayloadResult) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueCaseId = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_18AsyncPayloadResultO(promiseValue, valueCaseId) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_Sq18AsyncPayloadResultO(_ promise: JSObject, _ value: Optional) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sq18AsyncPayloadResultO") +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq18AsyncPayloadResultO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueCaseId: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq18AsyncPayloadResultO_extern(_ promise: Int32, _ valueIsSome: Int32, _ valueCaseId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq18AsyncPayloadResultO(_ promise: Int32, _ valueIsSome: Int32, _ valueCaseId: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sq18AsyncPayloadResultO_extern(promise, valueIsSome, valueCaseId) +} + +func _$Promise_resolve_Sq18AsyncPayloadResultO(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueIsSome, valueCaseId) = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_Sq18AsyncPayloadResultO(promiseValue, valueIsSome, valueCaseId) + if let error = _swift_js_take_exception() { throw error } +} + @JSFunction func Promise_resolve_11PublicPointV(_ promise: JSObject, _ value: PublicPoint) throws(JSException) #if arch(wasm32) @@ -12421,6 +12695,30 @@ fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static_exter return bjs_AsyncImportImports_jsAsyncRoundTripFeatureFlag_static_extern(resolveRef, rejectRef, vBytes, vLength) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripAssociatedValueEnum_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripAssociatedValueEnum_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripAssociatedValueEnum_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripAssociatedValueEnum_static(_ resolveRef: Int32, _ rejectRef: Int32, _ v: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripAssociatedValueEnum_static_extern(resolveRef, rejectRef, v) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum_static") +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vCaseId: Int32) -> Void +#else +fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum_static_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vCaseId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum_static(_ resolveRef: Int32, _ rejectRef: Int32, _ vIsSome: Int32, _ vCaseId: Int32) -> Void { + return bjs_AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum_static_extern(resolveRef, rejectRef, vIsSome, vCaseId) +} + func _$AsyncImportImports_jsAsyncRoundTripVoid() async throws(JSException) -> Void { try await _bjs_awaitPromise(makeResolveClosure: { JSTypedClosure<() -> Void>($0) @@ -12542,6 +12840,30 @@ func _$AsyncImportImports_jsAsyncRoundTripFeatureFlag(_ v: FeatureFlag) async th return resolved } +func _$AsyncImportImports_jsAsyncRoundTripAssociatedValueEnum(_ v: AsyncImportedPayloadResult) async throws(JSException) -> AsyncImportedPayloadResult { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending AsyncImportedPayloadResult) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let vCaseId = v.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripAssociatedValueEnum_static(resolveRef, rejectRef, vCaseId) + } + return resolved +} + +func _$AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum(_ v: Optional) async throws(JSException) -> Optional { + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Optional) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let (vIsSome, vCaseId) = v.bridgeJSLowerParameter() + bjs_AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum_static(resolveRef, rejectRef, vIsSome, vCaseId) + } + return resolved +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ClosureSupportImports_jsApplyVoid_static") fileprivate func bjs_ClosureSupportImports_jsApplyVoid_static_extern(_ callback: Int32) -> Void @@ -14079,6 +14401,48 @@ func _$jsRoundTripLightColor(_ value: LightColor) throws(JSException) -> LightCo return LightColor.bridgeJSLiftReturn(ret) } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripImportedPayloadSignal") +fileprivate func bjs_jsRoundTripImportedPayloadSignal_extern(_ value: Int32) -> Int32 +#else +fileprivate func bjs_jsRoundTripImportedPayloadSignal_extern(_ value: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsRoundTripImportedPayloadSignal(_ value: Int32) -> Int32 { + return bjs_jsRoundTripImportedPayloadSignal_extern(value) +} + +func _$jsRoundTripImportedPayloadSignal(_ value: ImportedPayloadSignal) throws(JSException) -> ImportedPayloadSignal { + let valueCaseId = value.bridgeJSLowerParameter() + let ret = bjs_jsRoundTripImportedPayloadSignal(valueCaseId) + if let error = _swift_js_take_exception() { + throw error + } + return ImportedPayloadSignal.bridgeJSLiftReturn(ret) +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalImportedPayloadSignal") +fileprivate func bjs_jsRoundTripOptionalImportedPayloadSignal_extern(_ valueIsSome: Int32, _ valueCaseId: Int32) -> Int32 +#else +fileprivate func bjs_jsRoundTripOptionalImportedPayloadSignal_extern(_ valueIsSome: Int32, _ valueCaseId: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_jsRoundTripOptionalImportedPayloadSignal(_ valueIsSome: Int32, _ valueCaseId: Int32) -> Int32 { + return bjs_jsRoundTripOptionalImportedPayloadSignal_extern(valueIsSome, valueCaseId) +} + +func _$jsRoundTripOptionalImportedPayloadSignal(_ value: Optional) throws(JSException) -> Optional { + let (valueIsSome, valueCaseId) = value.bridgeJSLowerParameter() + let ret = bjs_jsRoundTripOptionalImportedPayloadSignal(valueIsSome, valueCaseId) + if let error = _swift_js_take_exception() { + throw error + } + return Optional.bridgeJSLiftReturn(ret) +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsTranslatePoint") fileprivate func bjs_jsTranslatePoint_extern(_ point: Int32, _ dx: Int32, _ dy: Int32) -> Int32 diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 6535e9fc1..a51e6bafd 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -6550,6 +6550,53 @@ "swiftCallName" : "ArraySupportExports", "tsFullPath" : "ArraySupportExports" }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + + ], + "name" : "idle" + } + ], + "emitStyle" : "const", + "name" : "AsyncImportedPayloadResult", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "AsyncImportedPayloadResult", + "tsFullPath" : "AsyncImportedPayloadResult" + }, { "cases" : [ @@ -7715,6 +7762,53 @@ "swiftCallName" : "TSTheme", "tsFullPath" : "TSTheme" }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + + ], + "name" : "idle" + } + ], + "emitStyle" : "const", + "name" : "AsyncPayloadResult", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "AsyncPayloadResult", + "tsFullPath" : "AsyncPayloadResult" + }, { "cases" : [ @@ -9326,6 +9420,53 @@ "swiftCallName" : "LightColor", "tsFullPath" : "LightColor" }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "start" + }, + { + "associatedValues" : [ + { + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "name" : "stop" + }, + { + "associatedValues" : [ + + ], + "name" : "idle" + } + ], + "emitStyle" : "const", + "name" : "ImportedPayloadSignal", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "ImportedPayloadSignal", + "tsFullPath" : "ImportedPayloadSignal" + }, { "cases" : [ @@ -12984,6 +13125,66 @@ } } }, + { + "abiName" : "bjs_asyncRoundTripAssociatedValueEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripAssociatedValueEnum", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + } + }, + { + "abiName" : "bjs_asyncRoundTripOptionalAssociatedValueEnum", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : false + }, + "name" : "asyncRoundTripOptionalAssociatedValueEnum", + "parameters" : [ + { + "label" : "_", + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + }, + "_1" : "null" + } + } + }, { "abiName" : "bjs_setHttpStatus", "effects" : { @@ -18442,6 +18643,64 @@ "_1" : "String" } } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripAssociatedValueEnum", + "parameters" : [ + { + "name" : "v", + "type" : { + "associatedValueEnum" : { + "_0" : "AsyncImportedPayloadResult" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "AsyncImportedPayloadResult" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsAsyncRoundTripOptionalAssociatedValueEnum", + "parameters" : [ + { + "name" : "v", + "type" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "AsyncImportedPayloadResult" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "AsyncImportedPayloadResult" + } + }, + "_1" : "null" + } + } } ] } @@ -20406,6 +20665,64 @@ "_0" : "LightColor" } } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripImportedPayloadSignal", + "parameters" : [ + { + "name" : "value", + "type" : { + "associatedValueEnum" : { + "_0" : "ImportedPayloadSignal" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "ImportedPayloadSignal" + } + } + }, + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "jsRoundTripOptionalImportedPayloadSignal", + "parameters" : [ + { + "name" : "value", + "type" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "ImportedPayloadSignal" + } + }, + "_1" : "null" + } + } + } + ], + "returnType" : { + "nullable" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "ImportedPayloadSignal" + } + }, + "_1" : "null" + } + } } ], "types" : [ diff --git a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift index 2bb9158b9..9cf77ed9d 100644 --- a/Tests/BridgeJSRuntimeTests/ImportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ImportAPITests.swift @@ -7,7 +7,19 @@ import JavaScriptKit case green } +@JS enum ImportedPayloadSignal: Equatable { + case start(String) + case stop(Int) + case idle +} + @JSFunction func jsRoundTripLightColor(_ value: LightColor) throws(JSException) -> LightColor +@JSFunction func jsRoundTripImportedPayloadSignal( + _ value: ImportedPayloadSignal +) throws(JSException) -> ImportedPayloadSignal +@JSFunction func jsRoundTripOptionalImportedPayloadSignal( + _ value: ImportedPayloadSignal? +) throws(JSException) -> ImportedPayloadSignal? class ImportAPITests: XCTestCase { func testRoundTripVoid() throws { @@ -80,6 +92,29 @@ class ImportAPITests: XCTestCase { } } + func testRoundTripAssociatedValueEnum() throws { + let values: [ImportedPayloadSignal] = [ + .start("go"), + .stop(42), + .idle, + ] + for value in values { + try XCTAssertEqual(jsRoundTripImportedPayloadSignal(value), value) + } + } + + func testRoundTripOptionalAssociatedValueEnum() throws { + let values: [ImportedPayloadSignal?] = [ + .some(.start("go")), + .some(.stop(42)), + .some(.idle), + nil, + ] + for value in values { + try XCTAssertEqual(jsRoundTripOptionalImportedPayloadSignal(value), value) + } + } + func ensureThrows(_ f: (Bool) throws(JSException) -> T) throws { do { _ = try f(true) diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs index 1a767b184..9be7af1be 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/AsyncImportTests.mjs @@ -1,7 +1,7 @@ // @ts-check import assert from 'node:assert'; -import { ThemeValues, DirectionValues, FileSizeValues } from '../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.js'; +import { ThemeValues, DirectionValues, FileSizeValues, AsyncPayloadResultValues } from '../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.js'; /** * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["AsyncImportImports"]} @@ -38,6 +38,12 @@ export function getImports(importsContext) { jsAsyncRoundTripFeatureFlag: (v) => { return Promise.resolve(v); }, + jsAsyncRoundTripAssociatedValueEnum: (v) => { + return Promise.resolve(v); + }, + jsAsyncRoundTripOptionalAssociatedValueEnum: (v) => { + return Promise.resolve(v); + }, }; } @@ -124,4 +130,15 @@ export async function runAsyncWorksTests(exports) { assert.equal(await exports.asyncRoundTripFileSize(FileSizeValues.Large), FileSizeValues.Large); assert.equal(await exports.asyncRoundTripOptionalFileSize(FileSizeValues.Tiny), FileSizeValues.Tiny); assert.equal(await exports.asyncRoundTripOptionalFileSize(null), null); + + const asyncPayloadSuccess = { tag: AsyncPayloadResultValues.Tag.Success, param0: "ok" }; + const asyncPayloadFailure = { tag: AsyncPayloadResultValues.Tag.Failure, param0: 7 }; + const asyncPayloadIdle = { tag: AsyncPayloadResultValues.Tag.Idle }; + assert.deepEqual(await exports.asyncRoundTripAssociatedValueEnum(asyncPayloadSuccess), asyncPayloadSuccess); + assert.deepEqual(await exports.asyncRoundTripAssociatedValueEnum(asyncPayloadFailure), asyncPayloadFailure); + assert.deepEqual(await exports.asyncRoundTripAssociatedValueEnum(asyncPayloadIdle), asyncPayloadIdle); + assert.deepEqual(await exports.asyncRoundTripOptionalAssociatedValueEnum(asyncPayloadSuccess), asyncPayloadSuccess); + assert.deepEqual(await exports.asyncRoundTripOptionalAssociatedValueEnum(asyncPayloadFailure), asyncPayloadFailure); + assert.deepEqual(await exports.asyncRoundTripOptionalAssociatedValueEnum(asyncPayloadIdle), asyncPayloadIdle); + assert.equal(await exports.asyncRoundTripOptionalAssociatedValueEnum(null), null); } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 0f83da53c..bf3073c62 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -91,6 +91,12 @@ export async function setupOptions(options, context) { "jsRoundTripLightColor": (value) => { return value; }, + "jsRoundTripImportedPayloadSignal": (value) => { + return value; + }, + "jsRoundTripOptionalImportedPayloadSignal": (value) => { + return value; + }, "jsEchoJSValue": (v) => { return v; }, From fa13f45eae06bcabf1c714bdccc0a0462fd047db Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 11 Jun 2026 11:42:34 +0200 Subject: [PATCH 66/68] BridgeJS: Support throws and async for closures --- .../Sources/BridgeJSCore/ClosureCodegen.swift | 106 +- .../Sources/BridgeJSCore/ImportTS.swift | 9 +- .../BridgeJSCore/SwiftToSkeleton.swift | 51 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 6 +- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 80 +- .../ClosureAsyncDiagnosticsTests.swift | 151 +++ .../ClosureManglingTests.swift | 30 + .../ClosureThrowsDiagnosticsTests.swift | 56 ++ .../Inputs/MacroSwift/SwiftClosure.swift | 11 + .../MacroSwift/SwiftClosureImports.swift | 4 + .../BridgeJSCodegenTests/SwiftClosure.json | 227 +++++ .../BridgeJSCodegenTests/SwiftClosure.swift | 844 ++++++++++++++++ .../SwiftClosureImports.json | 105 ++ .../SwiftClosureImports.swift | 340 +++++++ .../BridgeJSLinkTests/SwiftClosure.d.ts | 6 + .../BridgeJSLinkTests/SwiftClosure.js | 368 +++++++ .../SwiftClosureImports.d.ts | 2 + .../BridgeJSLinkTests/SwiftClosureImports.js | 208 ++++ .../Bringing-Swift-Closures-to-JavaScript.md | 42 + .../Exporting-Swift-Closure.md | 143 ++- .../ClosureAsyncAPIs.swift | 89 ++ .../ClosureThrowsAPIs.swift | 31 + .../Generated/BridgeJS.swift | 922 +++++++++++++++++- .../Generated/JavaScript/BridgeJS.json | 446 +++++++++ .../JavaScript/ClosureAsyncTests.mjs | 137 +++ .../JavaScript/ClosureThrowsTests.mjs | 57 ++ Tests/prelude.mjs | 4 + 27 files changed, 4364 insertions(+), 111 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncDiagnosticsTests.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureManglingTests.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureThrowsDiagnosticsTests.swift create mode 100644 Tests/BridgeJSRuntimeTests/ClosureAsyncAPIs.swift create mode 100644 Tests/BridgeJSRuntimeTests/ClosureThrowsAPIs.swift create mode 100644 Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs create mode 100644 Tests/BridgeJSRuntimeTests/JavaScript/ClosureThrowsTests.mjs diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift index 45cfb73f1..d4e65c631 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ClosureCodegen.swift @@ -16,7 +16,7 @@ public struct ClosureCodegen { let closureParams = signature.parameters.map { "\(sendingPrefix)\($0.closureSwiftType)" }.joined( separator: ", " ) - let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "") + let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws(JSException)" : "") let swiftReturnType = signature.returnType.closureSwiftType return "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)" } @@ -73,7 +73,17 @@ public struct ClosureCodegen { helperEnumDeclPrinter.indent { helperEnumDeclPrinter.write("let callback = JSObject.bridgeJSLiftParameter(callbackId)") let parameters: String - if signature.parameters.isEmpty { + if signature.isThrows || signature.isAsync { + let sendingPrefix = signature.sendingParameters ? "sending " : "" + let typedParams = + signature.parameters.enumerated().map { index, paramType in + "param\(index): \(sendingPrefix)\(paramType.closureSwiftType)" + }.joined(separator: ", ") + let returnType = signature.returnType.closureSwiftType + let effects = + (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws(JSException)" : "") + parameters = " (\(typedParams))\(effects) -> \(returnType)" + } else if signature.parameters.isEmpty { parameters = "" } else if signature.parameters.count == 1 { parameters = " param0" @@ -146,9 +156,17 @@ public struct ClosureCodegen { liftedParams.append("\(paramType.swiftType).bridgeJSLiftParameter(\(argNames.joined(separator: ", ")))") } - let closureCallExpr = ExprSyntax("closure(\(raw: liftedParams.joined(separator: ", ")))") + let tryPrefix = signature.isThrows ? "try " : "" + let closureCallExpr = ExprSyntax("\(raw: tryPrefix)closure(\(raw: liftedParams.joined(separator: ", ")))") + let asyncTryPrefix = (signature.isThrows ? "try " : "") + "await " + let asyncClosureCallExpr = ExprSyntax( + "\(raw: asyncTryPrefix)closure(\(raw: liftedParams.joined(separator: ", ")))" + ) - let abiReturnWasmType = try signature.returnType.loweringReturnInfo().returnType + let abiReturnWasmType = + signature.isAsync + ? try BridgeType.jsObject(nil).loweringReturnInfo().returnType + : try signature.returnType.loweringReturnInfo().returnType // Build signature using SwiftSignatureBuilder let funcSignature = SwiftSignatureBuilder.buildABIFunctionSignature( @@ -156,12 +174,7 @@ public struct ClosureCodegen { returnType: abiReturnWasmType ) - // Build function declaration using helper - let funcDecl = SwiftCodePattern.buildExposedFunctionDecl( - abiName: abiName, - signature: funcSignature - ) { printer in - printer.write("let closure = Unmanaged<\(boxType)>.fromOpaque(boxPtr).takeUnretainedValue().closure") + let emitCallAndLower: (CodeFragmentPrinter) -> Void = { printer in if signature.returnType == .void { printer.write(closureCallExpr.description) } else { @@ -189,6 +202,79 @@ public struct ClosureCodegen { } } + let emitAsyncCallAndLower: (CodeFragmentPrinter) -> Void = { printer in + printer.write("let closure = Unmanaged<\(boxType)>.fromOpaque(boxPtr).takeUnretainedValue().closure") + let resolveType = signature.returnType + let resolveName = "Promise_resolve_\(resolveType.mangleTypeName)" + let rejectName = "Promise_reject" + let closureHead: String + if signature.isThrows { + let returnSpelling = resolveType == .void ? "" : " -> \(resolveType.closureSwiftType)" + closureHead = " () async throws(JSException)\(returnSpelling) in" + } else { + closureHead = "" + } + printer.write("return _bjs_makePromise(resolve: \(resolveName), reject: \(rejectName)) {\(closureHead)") + printer.indent { + if resolveType == .void { + printer.write(asyncClosureCallExpr.description) + } else { + printer.write("return \(asyncClosureCallExpr)") + } + } + printer.write("}") + } + + let catchPlaceholderStmt = abiReturnWasmType?.swiftReturnPlaceholderStmt + + // Build function declaration using helper + let funcDecl = SwiftCodePattern.buildExposedFunctionDecl( + abiName: abiName, + signature: funcSignature + ) { printer in + if signature.isAsync { + emitAsyncCallAndLower(printer) + } else if signature.isThrows { + printer.write( + "let closure = Unmanaged<\(boxType)>.fromOpaque(boxPtr).takeUnretainedValue().closure" + ) + printer.write("do {") + printer.indent { + emitCallAndLower(printer) + } + printer.write("} catch let error {") + printer.indent { + printer.write("if let error = error.thrownValue.object {") + printer.indent { + printer.write("withExtendedLifetime(error) {") + printer.indent { + printer.write("_swift_js_throw(Int32(bitPattern: $0.id))") + } + printer.write("}") + } + printer.write("} else {") + printer.indent { + printer.write("let jsError = JSError(message: error.description)") + printer.write("withExtendedLifetime(jsError.jsObject) {") + printer.indent { + printer.write("_swift_js_throw(Int32(bitPattern: $0.id))") + } + printer.write("}") + } + printer.write("}") + if let catchPlaceholderStmt { + printer.write(catchPlaceholderStmt) + } + } + printer.write("}") + } else { + printer.write( + "let closure = Unmanaged<\(boxType)>.fromOpaque(boxPtr).takeUnretainedValue().closure" + ) + emitCallAndLower(printer) + } + } + return DeclSyntax(funcDecl) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index a6a73b8f7..2912ce698 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -272,9 +272,7 @@ public struct ImportTS { } } - // Add exception check for ImportTS context (skipped for async, where - // errors are funneled through the JS-side reject path) - if !effects.isAsync && context == .importTS { + if !effects.isAsync && (context == .importTS || effects.isThrows) { body.write("if let error = _swift_js_take_exception() { throw error }") } } @@ -323,18 +321,19 @@ public struct ImportTS { let innerBody = body body = CodeFragmentPrinter() + let tryKeyword = effects.isThrows ? "try" : "try!" let rejectFactory = "makeRejectClosure: { JSTypedClosure<(sending JSValue) -> Void>($0) }" if returnType == .void { let resolveFactory = "makeResolveClosure: { JSTypedClosure<() -> Void>($0) }" body.write( - "try await _bjs_awaitPromise(\(resolveFactory), \(rejectFactory)) { resolveRef, rejectRef in" + "\(tryKeyword) await _bjs_awaitPromise(\(resolveFactory), \(rejectFactory)) { resolveRef, rejectRef in" ) } else { let resolveSwiftType = returnType.closureSwiftType let resolveFactory = "makeResolveClosure: { JSTypedClosure<(sending \(resolveSwiftType)) -> Void>($0) }" body.write( - "let resolved = try await _bjs_awaitPromise(\(resolveFactory), \(rejectFactory)) { resolveRef, rejectRef in" + "let resolved = \(tryKeyword) await _bjs_awaitPromise(\(resolveFactory), \(rejectFactory)) { resolveRef, rejectRef in" ) } body.indent { diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 57b9a57df..18bde3c7f 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -191,7 +191,40 @@ public final class SwiftToSkeleton { } let isAsync = functionType.effectSpecifiers?.asyncSpecifier != nil - let isThrows = functionType.effectSpecifiers?.throwsClause != nil + + if isAsync, !returnType.isAsyncResolvable { + errors.append( + DiagnosticError( + node: functionType, + message: + "Returning '\(returnType.swiftType)' from an async closure is not yet supported", + hint: + "Return a type lowerable through the async resolve ABI " + + "(String/Int/Bool/Double/Float/raw-value or case-only enum/@JS struct/JSObject/Optional/Array/Dictionary), " + + "or make the closure non-async." + ) + ) + return nil + } + + var isThrows = false + if let throwsClause = functionType.effectSpecifiers?.throwsClause { + guard let thrownType = throwsClause.type, + thrownType.trimmedDescription == "JSException" + else { + errors.append( + DiagnosticError( + node: throwsClause, + message: + "Only JSException is supported for thrown type of Swift closures, " + + "got \(throwsClause.type?.trimmedDescription ?? "unspecified")", + hint: "Annotate the closure as `throws(JSException)`" + ) + ) + return nil + } + isThrows = true + } return .closure( ClosureSignature( @@ -1028,22 +1061,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { guard let type = resolvedType else { continue // Skip unsupported types } - if case .closure(let signature, _) = type { - if signature.isAsync { - diagnose( - node: param.type, - message: "Async is not supported for Swift closures yet." - ) - continue - } - if signature.isThrows { - diagnose( - node: param.type, - message: "Throws is not supported for Swift closures yet." - ) - continue - } - } if case .nullable(let wrappedType, _) = type, wrappedType.isOptional { diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) continue diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 9a8442435..a9acf048e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -894,7 +894,7 @@ public struct BridgeJSLink { ) throws -> [String] { let printer = CodeFragmentPrinter() let builder = ExportedThunkBuilder( - effects: Effects(isAsync: false, isThrows: true), + effects: Effects(isAsync: signature.isAsync, isThrows: signature.isAsync ? signature.isThrows : true), hasDirectAccessToSwiftClass: false, intrinsicRegistry: intrinsicRegistry ) @@ -3743,7 +3743,9 @@ extension BridgeType { let paramTypes = signature.parameters.enumerated().map { index, param in "arg\(index): \(param.tsType)" }.joined(separator: ", ") - return "(\(paramTypes)) => \(signature.returnType.tsType)" + let returnTS = + signature.isAsync ? "Promise<\(signature.returnType.tsType)>" : signature.returnType.tsType + return "(\(paramTypes)) => \(returnTS)" case .array(let elementType): let inner = elementType.tsType if inner.contains("|") || inner.contains("=>") { diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 830132481..3e95b46a7 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -157,7 +157,8 @@ public struct ClosureSignature: Codable, Equatable, Hashable, Sendable { ? "y" : parameters.map { $0.mangleTypeName }.joined() let sendingPart = sendingParameters ? "s" : "" - let signaturePart = "\(sendingPart)\(paramPart)_\(returnType.mangleTypeName)" + let effects = (isAsync ? "Ya" : "") + (isThrows ? "K" : "") + let signaturePart = "\(sendingPart)\(effects)\(paramPart)_\(returnType.mangleTypeName)" self.mangleName = "\(moduleName.count)\(moduleName)\(signaturePart)" } } @@ -1049,8 +1050,31 @@ public struct ExportedSkeleton: Codable { for enumDef in enums { for method in enumDef.staticMethods { consider(method.returnType, method.effects) } } + for returnType in asyncClosureResolveReturnTypes { + consider(returnType, Effects(isAsync: true, isThrows: false)) + } return result } + + private var asyncClosureResolveReturnTypes: [BridgeType] { + var collector = AsyncClosureReturnTypeCollector() + var walker = BridgeSkeletonWalker(visitor: collector) + walker.walk(self) + return walker.visitor.returnTypes + } +} + +private struct AsyncClosureReturnTypeCollector: BridgeSkeletonVisitor { + private(set) var returnTypes: [BridgeType] = [] + + mutating func visitClosure( + _ signature: ClosureSignature, + useJSTypedClosure: Bool, + accessLevel: BridgeJSAccessLevel + ) { + guard signature.isAsync else { return } + returnTypes.append(signature.returnType) + } } // MARK: - Imported Skeleton @@ -1424,11 +1448,18 @@ public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { accessLevel: BridgeJSAccessLevel ) { recordSignature(signature, accessLevel: accessLevel) + + if signature.isAsync { + recordInjectedSignatures( + forReturnType: signature.returnType, + accessLevel: accessLevel + ) + } } /// Insert `signature` at `accessLevel`, or upgrade the existing level to /// the more permissive of the two. Centralizing the merge here keeps - /// `visitClosure` and `recordInjectedSignature` in lockstep — if the + /// `visitClosure` and `recordInjectedSignatures` in lockstep - if the /// merge policy ever needs to change (e.g. adding a diagnostic for /// conflicting levels), there's only one place to update. private mutating func recordSignature( @@ -1444,56 +1475,48 @@ public struct ClosureSignatureCollectorVisitor: BridgeSkeletonVisitor { public mutating func visitImportedFunction(_ function: ImportedFunctionSkeleton) { guard function.effects.isAsync else { return } - // When async imports exist, inject closure signatures for the typed resolve - // and reject callbacks used by _bjs_awaitPromise. - // - Reject always uses (sending JSValue) -> Void - // - Resolve uses a typed closure matching the return type (or () -> Void for void) - // All async callback closures use `sending` parameters so values can be - // transferred through the checked continuation without Sendable constraints. + recordInjectedSignatures( + forReturnType: function.returnType, + accessLevel: function.accessLevel + ) + } + private mutating func recordInjectedSignatures( + forReturnType returnType: BridgeType, + accessLevel: BridgeJSAccessLevel + ) { // Reject callback - recordInjectedSignature( + recordSignature( ClosureSignature( parameters: [.jsValue], returnType: .void, moduleName: moduleName, sendingParameters: true ), - for: function + accessLevel: accessLevel ) // Resolve callback (typed per return type) - if function.returnType == .void { - recordInjectedSignature( + if returnType == .void { + recordSignature( ClosureSignature( parameters: [], returnType: .void, moduleName: moduleName ), - for: function + accessLevel: accessLevel ) } else { - recordInjectedSignature( + recordSignature( ClosureSignature( - parameters: [function.returnType], + parameters: [returnType], returnType: .void, moduleName: moduleName, sendingParameters: true ), - for: function + accessLevel: accessLevel ) } } - - /// Inject a closure signature derived from an async import (e.g. Promise - /// resolve/reject callbacks). The injected signature inherits the access - /// level of the originating function so its synthesized init matches the - /// visibility of the async API surface. - private mutating func recordInjectedSignature( - _ signature: ClosureSignature, - for function: ImportedFunctionSkeleton - ) { - recordSignature(signature, accessLevel: function.accessLevel) - } } // MARK: - Unified Skeleton @@ -1678,7 +1701,8 @@ extension BridgeType { signature.parameters.isEmpty ? "y" : signature.parameters.map { $0.mangleTypeName }.joined() - return "K\(params)_\(signature.returnType.mangleTypeName)\(useJSTypedClosure ? "J" : "")" + let effects = (signature.isAsync ? "Ya" : "") + (signature.isThrows ? "K" : "") + return "K\(effects)\(params)_\(signature.returnType.mangleTypeName)\(useJSTypedClosure ? "J" : "")" case .array(let elementType): // Array mangling: "Sa" prefix followed by element type return "Sa\(elementType.mangleTypeName)" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncDiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncDiagnosticsTests.swift new file mode 100644 index 000000000..55d9e1bd3 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncDiagnosticsTests.swift @@ -0,0 +1,151 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +@Suite struct ClosureAsyncDiagnosticsTests { + @Test + func parsesAsyncClosureParameter() throws { + let app = try resolveApp( + source: """ + @JS public func process(_ cb: (Int) async -> String) {} + """ + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "process" })) + let parameter = try #require(function.parameters.first) + guard case .closure(let signature, _) = parameter.type else { + Issue.record("Expected closure parameter type, got \(parameter.type)") + return + } + #expect(signature.isAsync) + } + + @Test + func collectsResolveRejectSignaturesForAsyncClosure() throws { + let app = try resolveApp( + source: """ + @JS public func process(_ cb: (Int) async -> String) {} + """ + ) + let signatures = collectSignatures(from: app) + + let reject = ClosureSignature( + parameters: [.jsValue], + returnType: .void, + moduleName: "App", + sendingParameters: true + ) + let resolve = ClosureSignature( + parameters: [.string], + returnType: .void, + moduleName: "App", + sendingParameters: true + ) + + #expect(signatures.contains(reject)) + #expect(signatures.contains(resolve)) + } + + @Test + func collectsVoidResolveSignatureForVoidReturningAsyncClosure() throws { + let app = try resolveApp( + source: """ + @JS public func process(_ cb: (Int) async -> Void) {} + """ + ) + let signatures = collectSignatures(from: app) + + let reject = ClosureSignature( + parameters: [.jsValue], + returnType: .void, + moduleName: "App", + sendingParameters: true + ) + let voidResolve = ClosureSignature( + parameters: [], + returnType: .void, + moduleName: "App" + ) + + #expect(signatures.contains(reject)) + #expect(signatures.contains(voidResolve)) + } + + @Test + func supportsAsyncClosureReturningJSStruct() throws { + let app = try resolveApp( + source: """ + @JS struct Point { var x: Int } + @JS public func makePoint() -> JSTypedClosure<(Int) async -> Point> { + fatalError() + } + """ + ) + let resolveTypes = try #require(app.exported?.asyncPromiseResolveReturnTypes) + #expect(resolveTypes.contains { $0.mangleTypeName == "5PointV" }) + } + + @Test + func supportsAsyncThrowsClosureReturningJSStruct() throws { + let app = try resolveApp( + source: """ + @JS struct Point { var x: Int } + @JS public func makePoint() -> JSTypedClosure<(Int) async throws(JSException) -> Point> { + fatalError() + } + """ + ) + let resolveTypes = try #require(app.exported?.asyncPromiseResolveReturnTypes) + #expect(resolveTypes.contains { $0.mangleTypeName == "5PointV" }) + } + + @Test + func supportsAsyncClosureReturningAssociatedValueEnum() throws { + let app = try resolveApp( + source: """ + @JS enum Shape { case circle(radius: Double); case square(side: Double) } + @JS public func process(_ cb: (Int) async -> Shape) {} + """ + ) + let resolveTypes = try #require(app.exported?.asyncPromiseResolveReturnTypes) + #expect(resolveTypes.contains { $0.mangleTypeName == "5ShapeO" }) + } + + @Test + func supportsAsyncThrowsClosureReturningAssociatedValueEnum() throws { + let app = try resolveApp( + source: """ + @JS enum Shape { case circle(radius: Double); case square(side: Double) } + @JS public func makeShape() -> JSTypedClosure<(Int) async throws(JSException) -> Shape> { + fatalError() + } + """ + ) + let resolveTypes = try #require(app.exported?.asyncPromiseResolveReturnTypes) + #expect(resolveTypes.contains { $0.mangleTypeName == "5ShapeO" }) + } + + // MARK: - Utilities + + private func collectSignatures(from skeleton: BridgeJSSkeleton) -> Set { + let collector = ClosureSignatureCollectorVisitor(moduleName: skeleton.moduleName) + var walker = BridgeSkeletonWalker(visitor: collector) + walker.walk(skeleton) + return walker.visitor.signatures + } + + private func resolveApp(source appSource: String) throws -> BridgeJSSkeleton { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "App", + exposeToGlobal: false, + externalModuleIndex: ExternalModuleIndex(dependencies: []) + ) + let sourceFile = Parser.parse(source: appSource) + swiftAPI.addSourceFile(sourceFile, inputFilePath: "App.swift") + return try swiftAPI.finalize() + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureManglingTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureManglingTests.swift new file mode 100644 index 000000000..3675c805a --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureManglingTests.swift @@ -0,0 +1,30 @@ +import Testing + +@testable import BridgeJSSkeleton + +@Suite struct ClosureManglingTests { + private func sig(async a: Bool, throws t: Bool) -> ClosureSignature { + ClosureSignature( + parameters: [.integer(.int)], + returnType: .integer(.int), + moduleName: "M", + isAsync: a, + isThrows: t + ) + } + + @Test func effectsDisambiguateMangle() { + let plain = sig(async: false, throws: false).mangleName + let thr = sig(async: false, throws: true).mangleName + let asy = sig(async: true, throws: false).mangleName + let both = sig(async: true, throws: true).mangleName + #expect(Set([plain, thr, asy, both]).count == 4) + #expect(thr.contains("K")) + #expect(asy.contains("Ya")) + if let ya = both.range(of: "Ya"), let k = both.range(of: "K") { + #expect(ya.lowerBound < k.lowerBound) + } else { + Issue.record("expected both Ya and K in async-throws mangle") + } + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureThrowsDiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureThrowsDiagnosticsTests.swift new file mode 100644 index 000000000..eb41d0132 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureThrowsDiagnosticsTests.swift @@ -0,0 +1,56 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +@Suite struct ClosureThrowsDiagnosticsTests { + @Test + func parsesThrowsJSExceptionClosureParameter() throws { + let app = try resolveApp( + source: """ + @JS public func process(_ cb: (Int) throws(JSException) -> Int) {} + """ + ) + let function = try #require(app.exported?.functions.first(where: { $0.name == "process" })) + let parameter = try #require(function.parameters.first) + guard case .closure(let signature, _) = parameter.type else { + Issue.record("Expected closure parameter type, got \(parameter.type)") + return + } + #expect(signature.isThrows) + #expect(!signature.isAsync) + } + + @Test + func rejectsPlainThrowsClosureParameter() throws { + do { + _ = try resolveApp( + source: """ + @JS public func process(_ cb: (Int) throws -> Int) {} + """ + ) + Issue.record("Expected a plain-throws closure diagnostic, but resolution succeeded") + } catch let error as BridgeJSCoreDiagnosticError { + let combined = error.diagnostics.map(\.diagnostic.message).joined(separator: "\n") + #expect(combined.contains("JSException")) + #expect(!combined.contains("Throws is not supported for Swift closures yet.")) + } + } + + // MARK: - Utilities + + private func resolveApp(source appSource: String) throws -> BridgeJSSkeleton { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "App", + exposeToGlobal: false, + externalModuleIndex: ExternalModuleIndex(dependencies: []) + ) + let sourceFile = Parser.parse(source: appSource) + swiftAPI.addSourceFile(sourceFile, inputFilePath: "App.swift") + return try swiftAPI.finalize() + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift index 6872d7989..cdd756d51 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosure.swift @@ -38,6 +38,17 @@ import JavaScriptKit @JS func roundtripPerson(_ personClosure: (Person) -> Person) -> (Person) -> Person @JS func roundtripOptionalPerson(_ personClosure: (Person?) -> Person?) -> (Person?) -> Person? +@JS func makeThrowingParser() -> JSTypedClosure<(String) throws(JSException) -> Int> +@JS func validateWith(_ validate: (String) throws(JSException) -> Bool) + +@JS func makeFetcher() -> JSTypedClosure<(String) async throws(JSException) -> String> + +@JS func makeAsyncEcho() -> JSTypedClosure<(String) async -> String> + +@JS func makeAnimalLoader() -> JSTypedClosure<(String) async -> Animal> + +@JS func makeResultLoader() -> JSTypedClosure<(Bool) async throws(JSException) -> APIResult> + @JS func roundtripDirection(_ callback: (Direction) -> Direction) -> (Direction) -> Direction @JS func roundtripTheme(_ callback: (Theme) -> Theme) -> (Theme) -> Theme @JS func roundtripHttpStatus(_ callback: (HttpStatus) -> HttpStatus) -> (HttpStatus) -> HttpStatus diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosureImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosureImports.swift index d9f92fffb..88be5420e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosureImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClosureImports.swift @@ -1,3 +1,7 @@ @JSFunction func applyInt(_ value: Int, _ transform: (Int) -> Int) throws(JSException) -> Int @JSFunction func makeAdder(_ base: Int) throws(JSException) -> (Int) -> Int + +@JS func runValidator(_ cb: (String) throws(JSException) -> Bool) + +@JS func loadEach(_ fetch: (String) async throws(JSException) -> String) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json index ac18f6dc2..b1e306c07 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.json @@ -1330,6 +1330,233 @@ } } }, + { + "abiName" : "bjs_makeThrowingParser", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeThrowingParser", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : true, + "mangleName" : "10TestModuleKSS_Si", + "moduleName" : "TestModule", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_validateWith", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "validateWith", + "parameters" : [ + { + "label" : "_", + "name" : "validate", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : true, + "mangleName" : "10TestModuleKSS_Sb", + "moduleName" : "TestModule", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "bool" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_makeFetcher", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeFetcher", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "10TestModuleYaKSS_SS", + "moduleName" : "TestModule", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_makeAsyncEcho", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAsyncEcho", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : false, + "mangleName" : "10TestModuleYaSS_SS", + "moduleName" : "TestModule", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_makeAnimalLoader", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAnimalLoader", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : false, + "mangleName" : "10TestModuleYaSS_6AnimalV", + "moduleName" : "TestModule", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Animal" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_makeResultLoader", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeResultLoader", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "10TestModuleYaKSb_9APIResultO", + "moduleName" : "TestModule", + "parameters" : [ + { + "bool" : { + + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, { "abiName" : "bjs_roundtripDirection", "effects" : { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index 4eb7c8da4..f8f2c76a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -379,6 +379,172 @@ public func _invoke_swift_closure_TestModule_10TestModule9DirectionO_9DirectionO #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleKSS_Sb") +fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Sb(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuleKSS_Sb_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleKSS_Sb") +fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Sb_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Sb_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Sb(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleKSS_Sb_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleKSS_Sb { + static func bridgeJSLift(_ callbackId: Int32) -> (String) throws(JSException) -> Bool { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) throws(JSException) -> Bool in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_TestModule_10TestModuleKSS_Sb(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 + if let error = _swift_js_take_exception() { + throw error + } + return Bool.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) throws(JSException) -> Bool { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) throws(JSException) -> Bool) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleKSS_Sb, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleKSS_Sb") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleKSS_Sb") +public func _invoke_swift_closure_TestModule_10TestModuleKSS_Sb(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) throws(JSException) -> Bool>>.fromOpaque(boxPtr).takeUnretainedValue().closure + do { + let result = try closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleKSS_Si") +fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Si_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Si_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Si(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuleKSS_Si_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleKSS_Si") +fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Si_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Si_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Si(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleKSS_Si_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleKSS_Si { + static func bridgeJSLift(_ callbackId: Int32) -> (String) throws(JSException) -> Int { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) throws(JSException) -> Int in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_TestModule_10TestModuleKSS_Si(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 + if let error = _swift_js_take_exception() { + throw error + } + return Int.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) throws(JSException) -> Int { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) throws(JSException) -> Int) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleKSS_Si, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleKSS_Si") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleKSS_Si") +public func _invoke_swift_closure_TestModule_10TestModuleKSS_Si(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) throws(JSException) -> Int>>.fromOpaque(boxPtr).takeUnretainedValue().closure + do { + let result = try closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSS_SS") fileprivate func invoke_js_callback_TestModule_10TestModuleSS_SS_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 @@ -1392,6 +1558,534 @@ public func _invoke_swift_closure_TestModule_10TestModuleSqSi_SqSi(_ boxPtr: Uns #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleYaKSS_SS") +fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSS_SS(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleYaKSS_SS_extern(resolveRef, rejectRef, callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleYaKSS_SS") +fileprivate func make_swift_closure_TestModule_10TestModuleYaKSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleYaKSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleYaKSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleYaKSS_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleYaKSS_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (String) async throws(JSException) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) async throws(JSException) -> String in + #if arch(wasm32) + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending String) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModuleYaKSS_SS(resolveRef, rejectRef, callbackValue, param0Bytes, param0Length) + } + } + return resolved + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) async throws(JSException) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) async throws(JSException) -> String) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleYaKSS_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleYaKSS_SS") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleYaKSS_SS") +public func _invoke_swift_closure_TestModule_10TestModuleYaKSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) async throws(JSException) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { () async throws(JSException) -> String in + return try await closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleYaKSb_9APIResultO") +fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSb_9APIResultO_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSb_9APIResultO_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSb_9APIResultO(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleYaKSb_9APIResultO_extern(resolveRef, rejectRef, callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO") +fileprivate func make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleYaKSb_9APIResultO { + static func bridgeJSLift(_ callbackId: Int32) -> (Bool) async throws(JSException) -> APIResult { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: Bool) async throws(JSException) -> APIResult in + #if arch(wasm32) + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending APIResult) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModuleYaKSb_9APIResultO(resolveRef, rejectRef, callbackValue, param0Value) + } + return resolved + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Bool) async throws(JSException) -> APIResult { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Bool) async throws(JSException) -> APIResult) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO") +public func _invoke_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Bool) async throws(JSException) -> APIResult>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_9APIResultO, reject: Promise_reject) { () async throws(JSException) -> APIResult in + return try await closure(Bool.bridgeJSLiftParameter(param0)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleYaSS_6AnimalV") +fileprivate func invoke_js_callback_TestModule_10TestModuleYaSS_6AnimalV_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleYaSS_6AnimalV_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleYaSS_6AnimalV(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleYaSS_6AnimalV_extern(resolveRef, rejectRef, callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleYaSS_6AnimalV") +fileprivate func make_swift_closure_TestModule_10TestModuleYaSS_6AnimalV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleYaSS_6AnimalV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleYaSS_6AnimalV(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleYaSS_6AnimalV_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleYaSS_6AnimalV { + static func bridgeJSLift(_ callbackId: Int32) -> (String) async -> Animal { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) async -> Animal in + #if arch(wasm32) + let resolved = try! await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending Animal) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModuleYaSS_6AnimalV(resolveRef, rejectRef, callbackValue, param0Bytes, param0Length) + } + } + return resolved + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) async -> Animal { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) async -> Animal) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleYaSS_6AnimalV, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleYaSS_6AnimalV") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleYaSS_6AnimalV") +public func _invoke_swift_closure_TestModule_10TestModuleYaSS_6AnimalV(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) async -> Animal>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_6AnimalV, reject: Promise_reject) { + return await closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleYaSS_SS") +fileprivate func invoke_js_callback_TestModule_10TestModuleYaSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleYaSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleYaSS_SS(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleYaSS_SS_extern(resolveRef, rejectRef, callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleYaSS_SS") +fileprivate func make_swift_closure_TestModule_10TestModuleYaSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleYaSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleYaSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleYaSS_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleYaSS_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (String) async -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) async -> String in + #if arch(wasm32) + let resolved = try! await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending String) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModuleYaSS_SS(resolveRef, rejectRef, callbackValue, param0Bytes, param0Length) + } + } + return resolved + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) async -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) async -> String) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleYaSS_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleYaSS_SS") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleYaSS_SS") +public func _invoke_swift_closure_TestModule_10TestModuleYaSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) async -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { + return await closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules6AnimalV_y") +fileprivate func invoke_js_callback_TestModule_10TestModules6AnimalV_y_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModules6AnimalV_y_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules6AnimalV_y(_ callback: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModules6AnimalV_y_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules6AnimalV_y") +fileprivate func make_swift_closure_TestModule_10TestModules6AnimalV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModules6AnimalV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules6AnimalV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModules6AnimalV_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModules6AnimalV_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending Animal) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let _ = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModules6AnimalV_y(callbackValue) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending Animal) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending Animal) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModules6AnimalV_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules6AnimalV_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModules6AnimalV_y") +public func _invoke_swift_closure_TestModule_10TestModules6AnimalV_y(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending Animal) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(Animal.bridgeJSLiftParameter()) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules7JSValueV_y") +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + return invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(callback, param0Kind, param0Payload1, param0Payload2) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules7JSValueV_y") +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModules7JSValueV_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending JSValue) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0Kind, param0Payload1, param0Payload2) = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModules7JSValueV_y(callbackValue, param0Kind, param0Payload1, param0Payload2) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending JSValue) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending JSValue) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModules7JSValueV_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +public func _invoke_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending JSValue) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSValue.bridgeJSLiftParameter(param0Kind, param0Payload1, param0Payload2)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules9APIResultO_y") +fileprivate func invoke_js_callback_TestModule_10TestModules9APIResultO_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModules9APIResultO_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules9APIResultO_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModules9APIResultO_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules9APIResultO_y") +fileprivate func make_swift_closure_TestModule_10TestModules9APIResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModules9APIResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules9APIResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModules9APIResultO_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModules9APIResultO_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending APIResult) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0CaseId = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModules9APIResultO_y(callbackValue, param0CaseId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending APIResult) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending APIResult) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModules9APIResultO_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules9APIResultO_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModules9APIResultO_y") +public func _invoke_swift_closure_TestModule_10TestModules9APIResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending APIResult) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(APIResult.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSS_y") +fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModulesSS_y_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSS_y") +fileprivate func make_swift_closure_TestModule_10TestModulesSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModulesSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSS_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModulesSS_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModulesSS_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending String) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModulesSS_y(callbackValue, param0Bytes, param0Length) + } + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending String) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending String) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModulesSS_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSS_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModulesSS_y") +public func _invoke_swift_closure_TestModule_10TestModulesSS_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending String) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + #else + fatalError("Only available on WebAssembly") + #endif +} + extension Direction: _BridgedSwiftCaseEnum { @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { return bridgeJSRawValue @@ -1695,6 +2389,71 @@ public func _bjs_roundtripOptionalPerson(_ personClosure: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_makeThrowingParser") +@_cdecl("bjs_makeThrowingParser") +public func _bjs_makeThrowingParser() -> Int32 { + #if arch(wasm32) + let ret = makeThrowingParser() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_validateWith") +@_cdecl("bjs_validateWith") +public func _bjs_validateWith(_ validate: Int32) -> Void { + #if arch(wasm32) + validateWith(_: _BJS_Closure_10TestModuleKSS_Sb.bridgeJSLift(validate)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeFetcher") +@_cdecl("bjs_makeFetcher") +public func _bjs_makeFetcher() -> Int32 { + #if arch(wasm32) + let ret = makeFetcher() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAsyncEcho") +@_cdecl("bjs_makeAsyncEcho") +public func _bjs_makeAsyncEcho() -> Int32 { + #if arch(wasm32) + let ret = makeAsyncEcho() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAnimalLoader") +@_cdecl("bjs_makeAnimalLoader") +public func _bjs_makeAnimalLoader() -> Int32 { + #if arch(wasm32) + let ret = makeAnimalLoader() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeResultLoader") +@_cdecl("bjs_makeResultLoader") +public func _bjs_makeResultLoader() -> Int32 { + #if arch(wasm32) + let ret = makeResultLoader() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundtripDirection") @_cdecl("bjs_roundtripDirection") public func _bjs_roundtripDirection(_ callback: Int32) -> Int32 { @@ -1876,4 +2635,89 @@ fileprivate func _bjs_TestProcessor_wrap_extern(_ pointer: UnsafeMutableRawPoint #endif @inline(never) fileprivate func _bjs_TestProcessor_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { return _bjs_TestProcessor_wrap_extern(pointer) +} + +@JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_reject_TestModule") +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void +#else +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_reject_TestModule(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + return promise_reject_TestModule_extern(promise, valueKind, valuePayload1, valuePayload2) +} + +func _$Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueKind, valuePayload1, valuePayload2) = value.bridgeJSLowerParameter() + promise_reject_TestModule(promiseValue, valueKind, valuePayload1, valuePayload2) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_SS") +fileprivate func promise_resolve_TestModule_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_SS(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_TestModule_SS_extern(promise, valueBytes, valueLength) +} + +func _$Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + promise_resolve_TestModule_SS(promiseValue, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_6AnimalV(_ promise: JSObject, _ value: Animal) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_6AnimalV") +fileprivate func promise_resolve_TestModule_6AnimalV_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_6AnimalV_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_6AnimalV(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_6AnimalV_extern(promise, value) +} + +func _$Promise_resolve_6AnimalV(_ promise: JSObject, _ value: Animal) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueObjectId = value.bridgeJSLowerParameter() + promise_resolve_TestModule_6AnimalV(promiseValue, valueObjectId) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_9APIResultO(_ promise: JSObject, _ value: APIResult) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_9APIResultO") +fileprivate func promise_resolve_TestModule_9APIResultO_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_9APIResultO_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_9APIResultO(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_TestModule_9APIResultO_extern(promise, value) +} + +func _$Promise_resolve_9APIResultO(_ promise: JSObject, _ value: APIResult) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueCaseId = value.bridgeJSLowerParameter() + promise_resolve_TestModule_9APIResultO(promiseValue, valueCaseId) + if let error = _swift_js_take_exception() { throw error } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json index a84441bb4..d1cda5c7d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.json @@ -1,4 +1,109 @@ { + "exported" : { + "classes" : [ + + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_runValidator", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "runValidator", + "parameters" : [ + { + "label" : "_", + "name" : "cb", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : true, + "mangleName" : "10TestModuleKSS_Sb", + "moduleName" : "TestModule", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "bool" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_loadEach", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "loadEach", + "parameters" : [ + { + "label" : "_", + "name" : "fetch", + "type" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "10TestModuleYaKSS_SS", + "moduleName" : "TestModule", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "void" : { + + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, "imported" : { "children" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.swift index f87c8ecca..93c534c12 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosureImports.swift @@ -1,3 +1,86 @@ +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleKSS_Sb") +fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleKSS_Sb(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_TestModule_10TestModuleKSS_Sb_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleKSS_Sb") +fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Sb_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Sb_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleKSS_Sb(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleKSS_Sb_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleKSS_Sb { + static func bridgeJSLift(_ callbackId: Int32) -> (String) throws(JSException) -> Bool { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) throws(JSException) -> Bool in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_TestModule_10TestModuleKSS_Sb(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 + if let error = _swift_js_take_exception() { + throw error + } + return Bool.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) throws(JSException) -> Bool { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) throws(JSException) -> Bool) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleKSS_Sb, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleKSS_Sb") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleKSS_Sb") +public func _invoke_swift_closure_TestModule_10TestModuleKSS_Sb(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) throws(JSException) -> Bool>>.fromOpaque(boxPtr).takeUnretainedValue().closure + do { + let result = try closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSi_Si") fileprivate func invoke_js_callback_TestModule_10TestModuleSi_Si_extern(_ callback: Int32, _ param0: Int32) -> Int32 @@ -61,6 +144,263 @@ public func _invoke_swift_closure_TestModule_10TestModuleSi_Si(_ boxPtr: UnsafeM #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleYaKSS_SS") +fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleYaKSS_SS(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleYaKSS_SS_extern(resolveRef, rejectRef, callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModuleYaKSS_SS") +fileprivate func make_swift_closure_TestModule_10TestModuleYaKSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModuleYaKSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModuleYaKSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModuleYaKSS_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModuleYaKSS_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (String) async throws(JSException) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) async throws(JSException) -> String in + #if arch(wasm32) + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending String) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModuleYaKSS_SS(resolveRef, rejectRef, callbackValue, param0Bytes, param0Length) + } + } + return resolved + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) async throws(JSException) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) async throws(JSException) -> String) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModuleYaKSS_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModuleYaKSS_SS") +@_cdecl("invoke_swift_closure_TestModule_10TestModuleYaKSS_SS") +public func _invoke_swift_closure_TestModule_10TestModuleYaKSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) async throws(JSException) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { () async throws(JSException) -> String in + return try await closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModules7JSValueV_y") +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModules7JSValueV_y(_ callback: Int32, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + return invoke_js_callback_TestModule_10TestModules7JSValueV_y_extern(callback, param0Kind, param0Payload1, param0Payload2) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModules7JSValueV_y") +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModules7JSValueV_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModules7JSValueV_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending JSValue) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0Kind, param0Payload1, param0Payload2) = param0.bridgeJSLowerParameter() + invoke_js_callback_TestModule_10TestModules7JSValueV_y(callbackValue, param0Kind, param0Payload1, param0Payload2) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending JSValue) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending JSValue) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModules7JSValueV_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModules7JSValueV_y") +public func _invoke_swift_closure_TestModule_10TestModules7JSValueV_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Kind: Int32, _ param0Payload1: Int32, _ param0Payload2: Float64) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending JSValue) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(JSValue.bridgeJSLiftParameter(param0Kind, param0Payload1, param0Payload2)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModulesSS_y") +fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModulesSS_y(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModulesSS_y_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModulesSS_y") +fileprivate func make_swift_closure_TestModule_10TestModulesSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModulesSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModulesSS_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModulesSS_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModulesSS_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending String) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_TestModule_10TestModulesSS_y(callbackValue, param0Bytes, param0Length) + } + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending String) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending String) -> Void) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModulesSS_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModulesSS_y") +@_cdecl("invoke_swift_closure_TestModule_10TestModulesSS_y") +public func _invoke_swift_closure_TestModule_10TestModulesSS_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending String) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_runValidator") +@_cdecl("bjs_runValidator") +public func _bjs_runValidator(_ cb: Int32) -> Void { + #if arch(wasm32) + runValidator(_: _BJS_Closure_10TestModuleKSS_Sb.bridgeJSLift(cb)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_loadEach") +@_cdecl("bjs_loadEach") +public func _bjs_loadEach(_ fetch: Int32) -> Void { + #if arch(wasm32) + loadEach(_: _BJS_Closure_10TestModuleYaKSS_SS.bridgeJSLift(fetch)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@JSFunction func Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_reject_TestModule") +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void +#else +fileprivate func promise_reject_TestModule_extern(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_reject_TestModule(_ promise: Int32, _ valueKind: Int32, _ valuePayload1: Int32, _ valuePayload2: Float64) -> Void { + return promise_reject_TestModule_extern(promise, valueKind, valuePayload1, valuePayload2) +} + +func _$Promise_reject(_ promise: JSObject, _ value: JSValue) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let (valueKind, valuePayload1, valuePayload2) = value.bridgeJSLowerParameter() + promise_reject_TestModule(promiseValue, valueKind, valuePayload1, valuePayload2) + if let error = _swift_js_take_exception() { throw error } +} + +@JSFunction func Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_TestModule_SS") +fileprivate func promise_resolve_TestModule_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void +#else +fileprivate func promise_resolve_TestModule_SS_extern(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_TestModule_SS(_ promise: Int32, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + return promise_resolve_TestModule_SS_extern(promise, valueBytes, valueLength) +} + +func _$Promise_resolve_SS(_ promise: JSObject, _ value: String) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + value.bridgeJSWithLoweredParameter { (valueBytes, valueLength) in + promise_resolve_TestModule_SS(promiseValue, valueBytes, valueLength) + } + if let error = _swift_js_take_exception() { throw error } +} + #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_applyInt") fileprivate func bjs_applyInt_extern(_ value: Int32, _ transform: Int32) -> Int32 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts index d024be7dd..be62eeedd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.d.ts @@ -84,6 +84,12 @@ export type Exports = { roundtripOptionalDouble(doubleClosure: (arg0: number | null) => number | null): (arg0: number | null) => number | null; roundtripPerson(personClosure: (arg0: Person) => Person): (arg0: Person) => Person; roundtripOptionalPerson(personClosure: (arg0: Person | null) => Person | null): (arg0: Person | null) => Person | null; + makeThrowingParser(): (arg0: string) => number; + validateWith(validate: (arg0: string) => boolean): void; + makeFetcher(): (arg0: string) => Promise; + makeAsyncEcho(): (arg0: string) => Promise; + makeAnimalLoader(): (arg0: string) => Promise; + makeResultLoader(): (arg0: boolean) => Promise; roundtripDirection(callback: (arg0: DirectionTag) => DirectionTag): (arg0: DirectionTag) => DirectionTag; roundtripTheme(callback: (arg0: ThemeTag) => ThemeTag): (arg0: ThemeTag) => ThemeTag; roundtripHttpStatus(callback: (arg0: HttpStatusTag) => HttpStatusTag): (arg0: HttpStatusTag) => HttpStatusTag; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index cdd80e90a..4f0770092 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -61,6 +61,95 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + 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 swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { if (state.unregistered) { return; } instance?.exports?.bjs_release_swift_closure(state.pointer); @@ -248,6 +337,39 @@ export async function createInstantiator(options, swift) { promise[__bjs_promiseSettlers] = { resolve, reject }; return swift.memory.retain(promise); } + bjs["promise_resolve_TestModule_SS"] = function(promise, valueBytes, valueCount) { + try { + const string = decodeString(valueBytes, valueCount); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(string); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_6AnimalV"] = function(promise, value) { + try { + const value1 = swift.memory.getObject(value); + swift.memory.release(value); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(value1); + } catch (error) { + setException(error); + } + } + bjs["promise_resolve_TestModule_9APIResultO"] = function(promise, value) { + try { + const enumValue = enumHelpers.APIResult.lift(value); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(enumValue); + } catch (error) { + setException(error); + } + } + bjs["promise_reject_TestModule"] = function(promise, valueKind, valuePayload1, valuePayload2) { + try { + const jsValue = __bjs_jsValueLift(valueKind, valuePayload1, valuePayload2); + swift.memory.getObject(promise)[__bjs_promiseSettlers].reject(jsValue); + } catch (error) { + setException(error); + } + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -490,6 +612,58 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule9DirectionO_9DirectionO); } + bjs["invoke_js_callback_TestModule_10TestModuleKSS_Sb"] = function(callbackId, param0Bytes, param0Count) { + try { + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + let ret = callback(string); + return ret ? 1 : 0; + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModuleKSS_Sb"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleKSS_Sb = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleKSS_Sb(boxPtr, param0Id, param0Bytes.length); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret !== 0; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleKSS_Sb); + } + bjs["invoke_js_callback_TestModule_10TestModuleKSS_Si"] = function(callbackId, param0Bytes, param0Count) { + try { + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + let ret = callback(string); + return ret; + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModuleKSS_Si"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleKSS_Si = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleKSS_Si(boxPtr, param0Id, param0Bytes.length); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleKSS_Si); + } bjs["invoke_js_callback_TestModule_10TestModuleSS_SS"] = function(callbackId, param0Bytes, param0Count) { try { const callback = swift.memory.getObject(callbackId); @@ -970,6 +1144,176 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSqSi_SqSi); } + bjs["invoke_js_callback_TestModule_10TestModuleYaKSS_SS"] = function(resolveRef, rejectRef, callbackId, param0Bytes, param0Count) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + callback(string).then(resolve, reject); + } + bjs["make_swift_closure_TestModule_10TestModuleYaKSS_SS"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleYaKSS_SS = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaKSS_SS(boxPtr, param0Id, param0Bytes.length); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaKSS_SS); + } + bjs["invoke_js_callback_TestModule_10TestModuleYaKSb_9APIResultO"] = function(resolveRef, rejectRef, callbackId, param0) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + const callback = swift.memory.getObject(callbackId); + callback(param0 !== 0).then(resolve, reject); + } + bjs["make_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleYaKSb_9APIResultO = function(param0) { + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaKSb_9APIResultO(boxPtr, param0); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaKSb_9APIResultO); + } + bjs["invoke_js_callback_TestModule_10TestModuleYaSS_6AnimalV"] = function(resolveRef, rejectRef, callbackId, param0Bytes, param0Count) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + callback(string).then(resolve, reject); + } + bjs["make_swift_closure_TestModule_10TestModuleYaSS_6AnimalV"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleYaSS_6AnimalV = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaSS_6AnimalV(boxPtr, param0Id, param0Bytes.length); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaSS_6AnimalV); + } + bjs["invoke_js_callback_TestModule_10TestModuleYaSS_SS"] = function(resolveRef, rejectRef, callbackId, param0Bytes, param0Count) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + callback(string).then(resolve, reject); + } + bjs["make_swift_closure_TestModule_10TestModuleYaSS_SS"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleYaSS_SS = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaSS_SS(boxPtr, param0Id, param0Bytes.length); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaSS_SS); + } + bjs["invoke_js_callback_TestModule_10TestModules6AnimalV_y"] = function(callbackId) { + try { + const callback = swift.memory.getObject(callbackId); + const structValue = structHelpers.Animal.lift(); + callback(structValue); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModules6AnimalV_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModules6AnimalV_y = function(param0) { + structHelpers.Animal.lower(param0); + instance.exports.invoke_swift_closure_TestModule_10TestModules6AnimalV_y(boxPtr); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModules6AnimalV_y); + } + bjs["invoke_js_callback_TestModule_10TestModules7JSValueV_y"] = function(callbackId, param0Kind, param0Payload1, param0Payload2) { + try { + const callback = swift.memory.getObject(callbackId); + const jsValue = __bjs_jsValueLift(param0Kind, param0Payload1, param0Payload2); + callback(jsValue); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModules7JSValueV_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModules7JSValueV_y = function(param0) { + const [param0Kind, param0Payload1, param0Payload2] = __bjs_jsValueLower(param0); + instance.exports.invoke_swift_closure_TestModule_10TestModules7JSValueV_y(boxPtr, param0Kind, param0Payload1, param0Payload2); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModules7JSValueV_y); + } + bjs["invoke_js_callback_TestModule_10TestModules9APIResultO_y"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + const enumValue = enumHelpers.APIResult.lift(param0); + callback(enumValue); + } catch (error) { + setException(error); + } + } + 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); + instance.exports.invoke_swift_closure_TestModule_10TestModules9APIResultO_y(boxPtr, param0CaseId); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModules9APIResultO_y); + } + bjs["invoke_js_callback_TestModule_10TestModulesSS_y"] = function(callbackId, param0Bytes, param0Count) { + try { + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + callback(string); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModulesSS_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModulesSS_y = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + instance.exports.invoke_swift_closure_TestModule_10TestModulesSS_y(boxPtr, param0Id, param0Bytes.length); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModulesSS_y); + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -1149,6 +1493,30 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_roundtripOptionalPerson(callbackId); return swift.memory.getObject(ret); }, + makeThrowingParser: function bjs_makeThrowingParser() { + const ret = instance.exports.bjs_makeThrowingParser(); + return swift.memory.getObject(ret); + }, + validateWith: function bjs_validateWith(validate) { + const callbackId = swift.memory.retain(validate); + instance.exports.bjs_validateWith(callbackId); + }, + makeFetcher: function bjs_makeFetcher() { + const ret = instance.exports.bjs_makeFetcher(); + return swift.memory.getObject(ret); + }, + makeAsyncEcho: function bjs_makeAsyncEcho() { + const ret = instance.exports.bjs_makeAsyncEcho(); + return swift.memory.getObject(ret); + }, + makeAnimalLoader: function bjs_makeAnimalLoader() { + const ret = instance.exports.bjs_makeAnimalLoader(); + return swift.memory.getObject(ret); + }, + makeResultLoader: function bjs_makeResultLoader() { + const ret = instance.exports.bjs_makeResultLoader(); + return swift.memory.getObject(ret); + }, roundtripDirection: function bjs_roundtripDirection(callback) { const callbackId = swift.memory.retain(callback); const ret = instance.exports.bjs_roundtripDirection(callbackId); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts index ebf493910..b66f960f8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.d.ts @@ -5,6 +5,8 @@ // `swift package bridge-js`. export type Exports = { + runValidator(cb: (arg0: string) => boolean): void; + loadEach(fetch: (arg0: string) => Promise): void; } export type Imports = { applyInt(value: number, transform: (arg0: number) => number): number; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index 6fd627dcb..0cc8fd287 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -31,6 +31,95 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + 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 swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { if (state.unregistered) { return; } instance?.exports?.bjs_release_swift_closure(state.pointer); @@ -139,6 +228,22 @@ export async function createInstantiator(options, swift) { promise[__bjs_promiseSettlers] = { resolve, reject }; return swift.memory.retain(promise); } + bjs["promise_resolve_TestModule_SS"] = function(promise, valueBytes, valueCount) { + try { + const string = decodeString(valueBytes, valueCount); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(string); + } catch (error) { + setException(error); + } + } + bjs["promise_reject_TestModule"] = function(promise, valueKind, valuePayload1, valuePayload2) { + try { + const jsValue = __bjs_jsValueLift(valueKind, valuePayload1, valuePayload2); + swift.memory.getObject(promise)[__bjs_promiseSettlers].reject(jsValue); + } catch (error) { + setException(error); + } + } bjs["swift_js_return_optional_bool"] = function(isSome, value) { if (isSome === 0) { tmpRetOptionalBool = null; @@ -233,6 +338,32 @@ export async function createInstantiator(options, swift) { const func = swift.memory.getObject(funcRef); func.__unregister(); } + bjs["invoke_js_callback_TestModule_10TestModuleKSS_Sb"] = function(callbackId, param0Bytes, param0Count) { + try { + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + let ret = callback(string); + return ret ? 1 : 0; + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModuleKSS_Sb"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleKSS_Sb = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleKSS_Sb(boxPtr, param0Id, param0Bytes.length); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret !== 0; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleKSS_Sb); + } bjs["invoke_js_callback_TestModule_10TestModuleSi_Si"] = function(callbackId, param0) { try { const callback = swift.memory.getObject(callbackId); @@ -256,6 +387,75 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSi_Si); } + bjs["invoke_js_callback_TestModule_10TestModuleYaKSS_SS"] = function(resolveRef, rejectRef, callbackId, param0Bytes, param0Count) { + const resolve = swift.memory.getObject(resolveRef); + const reject = swift.memory.getObject(rejectRef); + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + callback(string).then(resolve, reject); + } + bjs["make_swift_closure_TestModule_10TestModuleYaKSS_SS"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModuleYaKSS_SS = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModuleYaKSS_SS(boxPtr, param0Id, param0Bytes.length); + const ret1 = swift.memory.getObject(ret); + swift.memory.release(ret); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return ret1; + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleYaKSS_SS); + } + bjs["invoke_js_callback_TestModule_10TestModules7JSValueV_y"] = function(callbackId, param0Kind, param0Payload1, param0Payload2) { + try { + const callback = swift.memory.getObject(callbackId); + const jsValue = __bjs_jsValueLift(param0Kind, param0Payload1, param0Payload2); + callback(jsValue); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModules7JSValueV_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModules7JSValueV_y = function(param0) { + const [param0Kind, param0Payload1, param0Payload2] = __bjs_jsValueLower(param0); + instance.exports.invoke_swift_closure_TestModule_10TestModules7JSValueV_y(boxPtr, param0Kind, param0Payload1, param0Payload2); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModules7JSValueV_y); + } + bjs["invoke_js_callback_TestModule_10TestModulesSS_y"] = function(callbackId, param0Bytes, param0Count) { + try { + const callback = swift.memory.getObject(callbackId); + const string = decodeString(param0Bytes, param0Count); + callback(string); + } catch (error) { + setException(error); + } + } + bjs["make_swift_closure_TestModule_10TestModulesSS_y"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModulesSS_y = function(param0) { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + instance.exports.invoke_swift_closure_TestModule_10TestModulesSS_y(boxPtr, param0Id, param0Bytes.length); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModulesSS_y); + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_applyInt"] = function bjs_applyInt(value, transform) { try { @@ -293,6 +493,14 @@ export async function createInstantiator(options, swift) { createExports: (instance) => { const js = swift.memory.heap; const exports = { + runValidator: function bjs_runValidator(cb) { + const callbackId = swift.memory.retain(cb); + instance.exports.bjs_runValidator(callbackId); + }, + loadEach: function bjs_loadEach(fetch) { + const callbackId = swift.memory.retain(fetch); + instance.exports.bjs_loadEach(callbackId); + }, }; _exports = exports; return exports; diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md index ce1d9d555..2d0c94152 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md @@ -38,6 +38,48 @@ let log = JSTypedClosure<(String) -> Void> { print($0) } defer { log.release() } ``` +## Throwing typed closures + +A ``JSTypedClosure`` signature can be `throws(JSException)`. Exceptions propagate across the boundary: a Swift closure that throws surfaces as a thrown JS error (caught with `try/catch` in JavaScript), and a throwing JS callback surfaces back into Swift as a `JSException`. + +```swift +import JavaScriptKit + +let parse = JSTypedClosure<(String) throws(JSException) -> Int> { text in + guard let value = Int(text) else { + throw JSException(JSError(message: "Not a number: \(text)").jsValue) + } + return value +} +defer { parse.release() } +``` + +Only `throws(JSException)` is supported. Plain `throws` is rejected at build time with a diagnostic, consistent with the rest of BridgeJS (see ). + +## Async typed closures + +A ``JSTypedClosure`` signature can be `async`. JavaScript receives a function that returns a `Promise`, so the TypeScript shape is `(args) => Promise`. Supported return types mirror `async` functions: `ConvertibleToJSValue` types, `@JS struct`, raw-value / case-only enums, `Void`, and their `Optional` / `Array` / `Dictionary` compositions. Unsupported async return types (associated-value enums, protocols, namespace enums) are diagnosed at build time. + +```swift +import JavaScriptKit + +let fetchCount = JSTypedClosure<(String) async -> Int> { endpoint in + try? await Task.sleep(nanoseconds: 10_000_000) + return endpoint.count +} +defer { fetchCount.release() } +``` + +```javascript +const count = await fetchCount("/items"); // Promise +``` + +> Important: Async closures require the JavaScript event loop executor, exactly like `async` functions. Call `JavaScriptEventLoop.installGlobalExecutor()` once during startup before invoking them. There is no special handling for closures. + +**Cancellation is a non-goal.** There is no propagation between a Swift `Task` and a JavaScript `Promise` in either direction. + +> Note: The reject path of async throwing typed closures is affected by a Swift compiler bug ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320)). See for details. + ## Lifetime and release() A ``JSTypedClosure`` keeps the Swift closure alive and exposes a JavaScript function that calls into it. To avoid leaks and use-after-free: diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md index adb9ab33b..4dd08faa8 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md @@ -103,6 +103,144 @@ This differs from structs and arrays, which use copy semantics and transfer data When you **return** a closure to JavaScript, we recommend using ``JSTypedClosure`` and calling `release()` when the closure is no longer needed, instead of returning a plain closure type. See . +## Throwing closures + +Closures can throw JavaScript errors across the boundary using `throws(JSException)`, in both directions. Exceptions propagate just like they do for throwing functions (see ). + +A Swift closure handed to JavaScript that throws surfaces as a thrown JS error, so JavaScript catches it with `try/catch`: + +```swift +import JavaScriptKit + +@JS func makeParser() -> (String) throws(JSException) -> Int { + return { text in + guard let value = Int(text) else { + throw JSException(JSError(message: "Not a number: \(text)").jsValue) + } + return value + } +} +``` + +```javascript +const parse = exports.makeParser(); +try { + console.log(parse("42")); // 42 + parse("oops"); // throws +} catch (e) { + console.error("parse failed:", e); +} +``` + +A throwing JavaScript callback passed into Swift surfaces back into Swift as a `JSException`, which the Swift call site rethrows: + +```swift +import JavaScriptKit + +@JS func runValidator(_ input: String, validate: (String) throws(JSException) -> Bool) throws(JSException) -> Bool { + return try validate(input) +} +``` + +```javascript +exports.runValidator("ok", (value) => { + if (value.length === 0) { + throw new Error("empty input"); + } + return true; +}); +``` + +Notes: +- Only `throws(JSException)` is supported. Plain `throws` is rejected at build time with a diagnostic. +- Thrown values are surfaced to JS as normal JS exceptions, and JS exceptions thrown by callbacks are surfaced into Swift as a `JSException`. + +## Async closures + +Closures can be `async` in both directions, just like `async` functions (see ). An async closure is exposed to JavaScript as a function that returns a `Promise`, so its TypeScript shape is `(args) => Promise`. + +> Important: Async closures require the JavaScript event loop executor to be installed, exactly like `async` functions. Call `JavaScriptEventLoop.installGlobalExecutor()` once during startup before invoking async closures. + +### Direction A - Swift awaits a JavaScript async callback + +A Swift `@JS func` can take a JavaScript async callback typed as `(A) async throws(JSException) -> R`. Swift `await`s the `Promise` the callback returns. Both resolution and rejection work: a rejected `Promise` surfaces into Swift as a `JSException`. + +```swift +import JavaScriptKit + +@JS func loadAll(_ keys: [String], fetch: (String) async throws(JSException) -> String) async throws(JSException) -> [String] { + var results: [String] = [] + for key in keys { + results.append(try await fetch(key)) + } + return results +} +``` + +```javascript +const values = await exports.loadAll(["a", "b"], async (key) => { + const response = await fetch(`/items/${key}`); + if (!response.ok) throw new Error(`failed: ${key}`); // rejects → JSException in Swift + return response.text(); +}); +``` + +### Direction B - a Swift async closure handed to JavaScript + +A Swift async closure returned to JavaScript (as a plain async closure type or a ``JSTypedClosure``) becomes a function JavaScript `await`s. Supported return types mirror async functions: `ConvertibleToJSValue` types, `@JS struct`, raw-value / case-only enums, `Void`, and their `Optional` / `Array` / `Dictionary` compositions. Unsupported async return types (associated-value enums, protocols, namespace enums) are diagnosed at build time. + +```swift +import JavaScriptKit + +@JS struct Point { + let x: Double + let y: Double +} + +// Async closure returning a @JS struct +@JS func makePointLoader() -> JSTypedClosure<(Double, Double) async -> Point> { + let loader = JSTypedClosure<(Double, Double) async -> Point> { x, y in + try? await Task.sleep(nanoseconds: 10_000_000) + return Point(x: x, y: y) + } + return loader +} + +// Async closure returning Void +@JS func makeLogger() -> JSTypedClosure<(String) async -> Void> { + return JSTypedClosure<(String) async -> Void> { message in + try? await Task.sleep(nanoseconds: 10_000_000) + print(message) + } +} +``` + +```javascript +const loadPoint = exports.makePointLoader(); +const point = await loadPoint(1, 2); // Promise +console.log(point.x, point.y); // 1 2 +loadPoint.release(); + +const log = exports.makeLogger(); +await log("hello"); // Promise +log.release(); +``` + +The generated TypeScript declarations: + +```typescript +export type Exports = { + makePointLoader(): (arg0: number, arg1: number) => Promise; + makeLogger(): (arg0: string) => Promise; +} +``` + +Notes: +- The same `JavaScriptEventLoop.installGlobalExecutor()` requirement applies as for async functions; there is no special handling for closures. +- **Cancellation is a non-goal.** There is no propagation between a Swift `Task` and a JavaScript `Promise` in either direction; cancelling one side does not cancel the other. + +> Warning: When an async throwing closure handed to JavaScript throws, the error is currently lost instead of rejecting the `Promise` with it, due to a Swift compiler bug on `wasm32` ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320), fix in progress in [swiftlang/swift#89715](https://github.com/swiftlang/swift/pull/89715)). Closures that capture state are unaffected, as are throwing JavaScript callbacks passed into Swift. + ## Supported Features | Swift Feature | Status | @@ -112,8 +250,9 @@ When you **return** a closure to JavaScript, we recommend using ``JSTypedClosure | `@escaping` closures | ✅ | | Optional types in closures | ✅ | | Closure-typed `@JS` properties | ❌ | -| Async closures | ❌ | -| Throwing closures | ❌ | +| Async closures `(A) async -> B` | ✅ | +| Async throwing closures `(A) async throws(JSException) -> B` | ✅ (reject path of closures handed to JS pending [swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320)) | +| Throwing closures `(A) throws(JSException) -> B` | ✅ | ## See Also diff --git a/Tests/BridgeJSRuntimeTests/ClosureAsyncAPIs.swift b/Tests/BridgeJSRuntimeTests/ClosureAsyncAPIs.swift new file mode 100644 index 000000000..678981ede --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/ClosureAsyncAPIs.swift @@ -0,0 +1,89 @@ +import XCTest +import JavaScriptKit +import JavaScriptEventLoop + +// MARK: - Direction A: Swift awaits a JS async callback + +@JS func awaitAsyncCallback(_ fetch: (String) async throws(JSException) -> String) async throws(JSException) -> String { + let resolved = try await fetch("request") + return "swift-saw:\(resolved)" +} + +// MARK: - Direction B: a Swift async closure handed to JS + +@JS func makeAsyncParser() -> JSTypedClosure<(String) async throws(JSException) -> String> { + return JSTypedClosure { (text: String) async throws(JSException) -> String in + await Task.yield() + guard let value = Int(text) else { + throw JSException(JSError(message: "AsyncParseError: \(text)").jsValue) + } + return "parsed:\(value)" + } +} + +@JS func makeAsyncEcho() -> JSTypedClosure<(String) async -> String> { + return JSTypedClosure { (text: String) async -> String in + await Task.yield() + return "echo:\(text)" + } +} + +@JS func makeAsyncRecorder() -> JSTypedClosure<(String) async throws(JSException) -> Void> { + return JSTypedClosure { (text: String) async throws(JSException) -> Void in + await Task.yield() + if text == "boom" { + throw JSException(JSError(message: "AsyncRecorderError").jsValue) + } + AsyncRecorderState.lastRecorded = text + } +} + +@JS func lastRecordedValue() -> String { + return AsyncRecorderState.lastRecorded +} + +@JS func makeAsyncPayloadLoader() -> JSTypedClosure<(Bool) async throws(JSException) -> AsyncPayloadResult> { + return JSTypedClosure { (succeed: Bool) async throws(JSException) -> AsyncPayloadResult in + await Task.yield() + return succeed ? .success("loaded") : .failure(42) + } +} + +@JS func awaitPayloadCallback( + _ load: (Bool) async throws(JSException) -> AsyncPayloadResult +) async throws(JSException) -> String { + let first = try await load(true) + let second = try await load(false) + return "\(payloadSummary(first))|\(payloadSummary(second))" +} + +private func payloadSummary(_ result: AsyncPayloadResult) -> String { + switch result { + case .success(let value): return "success:\(value)" + case .failure(let code): return "failure:\(code)" + case .idle: return "idle" + } +} + +@JS func makeAsyncPointMaker() -> JSTypedClosure<(Double) async -> DataPoint> { + return JSTypedClosure { (seed: Double) async -> DataPoint in + await Task.yield() + return DataPoint(x: seed, y: seed * 2, label: "async:\(seed)", optCount: nil, optFlag: nil) + } +} + +enum AsyncRecorderState { + nonisolated(unsafe) static var lastRecorded: String = "" +} + +// MARK: - XCTest entry point + +final class ClosureAsyncTests: XCTestCase { + func testRunJsClosureAsyncTests() async throws { + try await ClosureAsyncImports.runJsClosureAsyncTests() + } +} + +@JSClass struct ClosureAsyncImports { + @JSFunction static func runJsClosureAsyncTests() async throws(JSException) +} diff --git a/Tests/BridgeJSRuntimeTests/ClosureThrowsAPIs.swift b/Tests/BridgeJSRuntimeTests/ClosureThrowsAPIs.swift new file mode 100644 index 000000000..472d57ad6 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/ClosureThrowsAPIs.swift @@ -0,0 +1,31 @@ +import XCTest +import JavaScriptKit + +// MARK: - Direction B: Swift closure (throws) called from JS + +@JS func makeThrowingParser() -> JSTypedClosure<(String) throws(JSException) -> Int> { + return JSTypedClosure { (text: String) throws(JSException) -> Int in + guard let value = Int(text) else { + throw JSException(JSError(message: "ParseError: \(text)").jsValue) + } + return value + } +} + +// MARK: - Direction A: JS callback (throws) called from Swift + +@JS func runValidator(_ validate: (String) throws(JSException) -> Bool) throws(JSException) -> Bool { + return try validate("input") +} + +// MARK: - XCTest entry point + +final class ClosureThrowsTests: XCTestCase { + func testRunJsClosureThrowsTests() throws { + try ClosureThrowsImports.runJsClosureThrowsTests() + } +} + +@JSClass struct ClosureThrowsImports { + @JSFunction static func runJsClosureThrowsTests() throws(JSException) +} diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index c02cb72f7..b2afb6d5b 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -644,6 +644,172 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTests9Di #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsKSS_Sb { + static func bridgeJSLift(_ callbackId: Int32) -> (String) throws(JSException) -> Bool { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) throws(JSException) -> Bool in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 + if let error = _swift_js_take_exception() { + throw error + } + return Bool.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) throws(JSException) -> Bool { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) throws(JSException) -> Bool) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Sb(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) throws(JSException) -> Bool>>.fromOpaque(boxPtr).takeUnretainedValue().closure + do { + let result = try closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si_extern(callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsKSS_Si { + static func bridgeJSLift(_ callbackId: Int32) -> (String) throws(JSException) -> Int { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) throws(JSException) -> Int in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret0 = param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si(callbackValue, param0Bytes, param0Length) + return ret + } + let ret = ret0 + if let error = _swift_js_take_exception() { + throw error + } + return Int.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) throws(JSException) -> Int { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) throws(JSException) -> Int) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsKSS_Si(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) throws(JSException) -> Int>>.fromOpaque(boxPtr).takeUnretainedValue().closure + do { + let result = try closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSS_7GreeterC_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> UnsafeMutableRawPointer @@ -1688,26 +1854,370 @@ fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsS @_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS") fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 #else -fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsSqSS_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let ret0 = param0.bridgeJSWithLoweredParameter { (param0IsSome, param0Bytes, param0Length) in + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(callbackValue, param0IsSome, param0Bytes, param0Length) + return ret + } + let ret = ret0 + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Optional) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(callback, param0IsSome, param0Value) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsSqSi_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameter() + let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(callbackValue, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Optional) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS_extern(resolveRef, rejectRef, callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsYaKSS_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (String) async throws(JSException) -> String { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) async throws(JSException) -> String in + #if arch(wasm32) + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending String) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS(resolveRef, rejectRef, callbackValue, param0Bytes, param0Length) + } + } + return resolved + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) async throws(JSException) -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) async throws(JSException) -> String) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) async throws(JSException) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { () async throws(JSException) -> String in + return try await closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y_extern(resolveRef, rejectRef, callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsYaKSS_y { + static func bridgeJSLift(_ callbackId: Int32) -> (String) async throws(JSException) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: String) async throws(JSException) -> Void in + #if arch(wasm32) + try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<() -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y(resolveRef, rejectRef, callbackValue, param0Bytes, param0Length) + } + } + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (String) async throws(JSException) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) async throws(JSException) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSS_y(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) async throws(JSException) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_y, reject: Promise_reject) { () async throws(JSException) in + try await closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO_extern(resolveRef, rejectRef, callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO { + static func bridgeJSLift(_ callbackId: Int32) -> (Bool) async throws(JSException) -> AsyncPayloadResult { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] (param0: Bool) async throws(JSException) -> AsyncPayloadResult in + #if arch(wasm32) + let resolved = try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending AsyncPayloadResult) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO(resolveRef, rejectRef, callbackValue, param0Value) + } + return resolved + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Bool) async throws(JSException) -> AsyncPayloadResult { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Bool) async throws(JSException) -> AsyncPayloadResult) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Int32 { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Bool) async throws(JSException) -> AsyncPayloadResult>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_18AsyncPayloadResultO, reject: Promise_reject) { () async throws(JSException) -> AsyncPayloadResult in + return try await closure(Bool.bridgeJSLiftParameter(param0)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS_extern(resolveRef, rejectRef, callback, param0Bytes, param0Length) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { - return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS_extern(boxPtr, file, line) +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS_extern(boxPtr, file, line) } -private enum _BJS_Closure_20BridgeJSRuntimeTestsSqSS_SS { - static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { +private enum _BJS_Closure_20BridgeJSRuntimeTestsYaSS_SS { + static func bridgeJSLift(_ callbackId: Int32) -> (String) async -> String { let callback = JSObject.bridgeJSLiftParameter(callbackId) - return { [callback] param0 in + return { [callback] (param0: String) async -> String in #if arch(wasm32) - let callbackValue = callback.bridgeJSLowerParameter() - let ret0 = param0.bridgeJSWithLoweredParameter { (param0IsSome, param0Bytes, param0Length) in - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(callbackValue, param0IsSome, param0Bytes, param0Length) - return ret + let resolved = try! await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending String) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + param0.bridgeJSWithLoweredParameter { (param0Bytes, param0Length) in + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS(resolveRef, rejectRef, callbackValue, param0Bytes, param0Length) + } } - let ret = ret0 - return String.bridgeJSLiftReturn(ret) + return resolved #else fatalError("Only available on WebAssembly") #endif @@ -1715,10 +2225,10 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSqSS_SS { } } -extension JSTypedClosure where Signature == (Optional) -> String { - init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { +extension JSTypedClosure where Signature == (String) async -> String { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (String) async -> String) { self.init( - makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS, + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS, body: body, fileID: fileID, line: line @@ -1726,51 +2236,58 @@ extension JSTypedClosure where Signature == (Optional) -> String { } } -@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS") -@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS") -public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void { +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSS_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0Bytes: Int32, _ param0Length: Int32) -> Int32 { #if arch(wasm32) - let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure - let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Bytes, param0Length)) - return result.bridgeJSLowerReturn() + let closure = Unmanaged<_BridgeJSTypedClosureBox<(String) async -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { + return await closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + } #else fatalError("Only available on WebAssembly") #endif } #if arch(wasm32) -@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Float64) -> Void #else -fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV_extern(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Float64) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(_ callback: Int32, _ param0IsSome: Int32, _ param0Value: Int32) -> Int32 { - return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(callback, param0IsSome, param0Value) +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV(_ resolveRef: Int32, _ rejectRef: Int32, _ callback: Int32, _ param0: Float64) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV_extern(resolveRef, rejectRef, callback, param0) } #if arch(wasm32) -@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") -fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 #else -fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { - return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS_extern(boxPtr, file, line) +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV_extern(boxPtr, file, line) } -private enum _BJS_Closure_20BridgeJSRuntimeTestsSqSi_SS { - static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { +private enum _BJS_Closure_20BridgeJSRuntimeTestsYaSd_9DataPointV { + static func bridgeJSLift(_ callbackId: Int32) -> (Double) async -> DataPoint { let callback = JSObject.bridgeJSLiftParameter(callbackId) - return { [callback] param0 in + return { [callback] (param0: Double) async -> DataPoint in #if arch(wasm32) - let callbackValue = callback.bridgeJSLowerParameter() - let (param0IsSome, param0Value) = param0.bridgeJSLowerParameter() - let ret = invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(callbackValue, param0IsSome, param0Value) - return String.bridgeJSLiftReturn(ret) + let resolved = try! await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<(sending DataPoint) -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + let callbackValue = callback.bridgeJSLowerParameter() + let param0Value = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV(resolveRef, rejectRef, callbackValue, param0Value) + } + return resolved #else fatalError("Only available on WebAssembly") #endif @@ -1778,10 +2295,10 @@ private enum _BJS_Closure_20BridgeJSRuntimeTestsSqSi_SS { } } -extension JSTypedClosure where Signature == (Optional) -> String { - init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Optional) -> String) { +extension JSTypedClosure where Signature == (Double) async -> DataPoint { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Double) async -> DataPoint) { self.init( - makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS, + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV, body: body, fileID: fileID, line: line @@ -1789,13 +2306,14 @@ extension JSTypedClosure where Signature == (Optional) -> String { } } -@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") -@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS") -public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsSqSi_SS(_ boxPtr: UnsafeMutableRawPointer, _ param0IsSome: Int32, _ param0Value: Int32) -> Void { +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestsYaSd_9DataPointV(_ boxPtr: UnsafeMutableRawPointer, _ param0: Float64) -> Int32 { #if arch(wasm32) - let closure = Unmanaged<_BridgeJSTypedClosureBox<(Optional) -> String>>.fromOpaque(boxPtr).takeUnretainedValue().closure - let result = closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) - return result.bridgeJSLowerReturn() + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Double) async -> DataPoint>>.fromOpaque(boxPtr).takeUnretainedValue().closure + return _bjs_makePromise(resolve: Promise_resolve_9DataPointV, reject: Promise_reject) { + return await closure(Double.bridgeJSLiftParameter(param0)) + } #else fatalError("Only available on WebAssembly") #endif @@ -1924,6 +2442,67 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss11 #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y_extern(_ callback: Int32, _ param0: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y_extern(_ callback: Int32, _ param0: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y(_ callback: Int32, _ param0: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending AsyncPayloadResult) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let param0CaseId = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y(callbackValue, param0CaseId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending AsyncPayloadResult) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending AsyncPayloadResult) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss18AsyncPayloadResultO_y(_ boxPtr: UnsafeMutableRawPointer, _ param0: Int32) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending AsyncPayloadResult) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(AsyncPayloadResult.bridgeJSLiftParameter(param0)) + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss26AsyncImportedPayloadResultO_y_extern(_ callback: Int32, _ param0: Int32) -> Void @@ -2046,6 +2625,67 @@ public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss7J #endif } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y") +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y_extern(_ callback: Int32) -> Void +#else +fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y_extern(_ callback: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y(_ callback: Int32) -> Void { + return invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y_extern(callback) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y") +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_20BridgeJSRuntimeTestss9DataPointV_y { + static func bridgeJSLift(_ callbackId: Int32) -> (sending DataPoint) -> Void { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let callbackValue = callback.bridgeJSLowerParameter() + let _ = param0.bridgeJSLowerParameter() + invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y(callbackValue) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (sending DataPoint) -> Void { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (sending DataPoint) -> Void) { + self.init( + makeClosure: make_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y") +@_cdecl("invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y") +public func _invoke_swift_closure_BridgeJSRuntimeTests_20BridgeJSRuntimeTestss9DataPointV_y(_ boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(sending DataPoint) -> Void>>.fromOpaque(boxPtr).takeUnretainedValue().closure + closure(DataPoint.bridgeJSLiftParameter()) + #else + fatalError("Only available on WebAssembly") + #endif +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y") fileprivate func invoke_js_callback_BridgeJSRuntimeTests_20BridgeJSRuntimeTestssSS_y_extern(_ callback: Int32, _ param0Bytes: Int32, _ param0Length: Int32) -> Void @@ -6974,6 +7614,132 @@ public func _bjs_ArrayMembers_firstString() -> Void { #endif } +@_expose(wasm, "bjs_awaitAsyncCallback") +@_cdecl("bjs_awaitAsyncCallback") +public func _bjs_awaitAsyncCallback(_ fetch: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { () async throws(JSException) -> String in + return try await awaitAsyncCallback(_: _BJS_Closure_20BridgeJSRuntimeTestsYaKSS_SS.bridgeJSLift(fetch)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAsyncParser") +@_cdecl("bjs_makeAsyncParser") +public func _bjs_makeAsyncParser() -> Int32 { + #if arch(wasm32) + let ret = makeAsyncParser() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAsyncEcho") +@_cdecl("bjs_makeAsyncEcho") +public func _bjs_makeAsyncEcho() -> Int32 { + #if arch(wasm32) + let ret = makeAsyncEcho() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAsyncRecorder") +@_cdecl("bjs_makeAsyncRecorder") +public func _bjs_makeAsyncRecorder() -> Int32 { + #if arch(wasm32) + let ret = makeAsyncRecorder() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_lastRecordedValue") +@_cdecl("bjs_lastRecordedValue") +public func _bjs_lastRecordedValue() -> Void { + #if arch(wasm32) + let ret = lastRecordedValue() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAsyncPayloadLoader") +@_cdecl("bjs_makeAsyncPayloadLoader") +public func _bjs_makeAsyncPayloadLoader() -> Int32 { + #if arch(wasm32) + let ret = makeAsyncPayloadLoader() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_awaitPayloadCallback") +@_cdecl("bjs_awaitPayloadCallback") +public func _bjs_awaitPayloadCallback(_ load: Int32) -> Int32 { + #if arch(wasm32) + return _bjs_makePromise(resolve: Promise_resolve_SS, reject: Promise_reject) { () async throws(JSException) -> String in + return try await awaitPayloadCallback(_: _BJS_Closure_20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO.bridgeJSLift(load)) + } + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAsyncPointMaker") +@_cdecl("bjs_makeAsyncPointMaker") +public func _bjs_makeAsyncPointMaker() -> Int32 { + #if arch(wasm32) + let ret = makeAsyncPointMaker() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeThrowingParser") +@_cdecl("bjs_makeThrowingParser") +public func _bjs_makeThrowingParser() -> Int32 { + #if arch(wasm32) + let ret = makeThrowingParser() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_runValidator") +@_cdecl("bjs_runValidator") +public func _bjs_runValidator(_ validate: Int32) -> Int32 { + #if arch(wasm32) + do { + let ret = try runValidator(_: _BJS_Closure_20BridgeJSRuntimeTestsKSS_Sb.bridgeJSLift(validate)) + return ret.bridgeJSLowerReturn() + } catch let error { + if let error = error.thrownValue.object { + withExtendedLifetime(error) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } else { + let jsError = JSError(message: error.description) + withExtendedLifetime(jsError.jsObject) { + _swift_js_throw(Int32(bitPattern: $0.id)) + } + } + return 0 + } + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundTripVoid") @_cdecl("bjs_roundTripVoid") public func _bjs_roundTripVoid() -> Void { @@ -12176,6 +12942,27 @@ func _$Promise_resolve_SD11PublicPointV(_ promise: JSObject, _ value: [String: P if let error = _swift_js_take_exception() { throw error } } +@JSFunction func Promise_resolve_9DataPointV(_ promise: JSObject, _ value: DataPoint) throws(JSException) + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_9DataPointV") +fileprivate func promise_resolve_BridgeJSRuntimeTests_9DataPointV_extern(_ promise: Int32, _ value: Int32) -> Void +#else +fileprivate func promise_resolve_BridgeJSRuntimeTests_9DataPointV_extern(_ promise: Int32, _ value: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_9DataPointV(_ promise: Int32, _ value: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_9DataPointV_extern(promise, value) +} + +func _$Promise_resolve_9DataPointV(_ promise: JSObject, _ value: DataPoint) throws(JSException) -> Void { + let promiseValue = promise.bridgeJSLowerParameter() + let valueObjectId = value.bridgeJSLowerParameter() + promise_resolve_BridgeJSRuntimeTests_9DataPointV(promiseValue, valueObjectId) + if let error = _swift_js_take_exception() { throw error } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ArrayElementObject_init") fileprivate func bjs_ArrayElementObject_init_extern(_ idBytes: Int32, _ idLength: Int32) -> Int32 @@ -12864,6 +13651,28 @@ func _$AsyncImportImports_jsAsyncRoundTripOptionalAssociatedValueEnum(_ v: Optio return resolved } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ClosureAsyncImports_runJsClosureAsyncTests_static") +fileprivate func bjs_ClosureAsyncImports_runJsClosureAsyncTests_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void +#else +fileprivate func bjs_ClosureAsyncImports_runJsClosureAsyncTests_static_extern(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ClosureAsyncImports_runJsClosureAsyncTests_static(_ resolveRef: Int32, _ rejectRef: Int32) -> Void { + return bjs_ClosureAsyncImports_runJsClosureAsyncTests_static_extern(resolveRef, rejectRef) +} + +func _$ClosureAsyncImports_runJsClosureAsyncTests() async throws(JSException) -> Void { + try await _bjs_awaitPromise(makeResolveClosure: { + JSTypedClosure<() -> Void>($0) + }, makeRejectClosure: { + JSTypedClosure<(sending JSValue) -> Void>($0) + }) { resolveRef, rejectRef in + bjs_ClosureAsyncImports_runJsClosureAsyncTests_static(resolveRef, rejectRef) + } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ClosureSupportImports_jsApplyVoid_static") fileprivate func bjs_ClosureSupportImports_jsApplyVoid_static_extern(_ callback: Int32) -> Void @@ -13246,6 +14055,25 @@ func _$ClosureSupportImports_runJsClosureSupportTests() throws(JSException) -> V } } +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_ClosureThrowsImports_runJsClosureThrowsTests_static") +fileprivate func bjs_ClosureThrowsImports_runJsClosureThrowsTests_static_extern() -> Void +#else +fileprivate func bjs_ClosureThrowsImports_runJsClosureThrowsTests_static_extern() -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func bjs_ClosureThrowsImports_runJsClosureThrowsTests_static() -> Void { + return bjs_ClosureThrowsImports_runJsClosureThrowsTests_static_extern() +} + +func _$ClosureThrowsImports_runJsClosureThrowsTests() throws(JSException) -> Void { + bjs_ClosureThrowsImports_runJsClosureThrowsTests_static() + if let error = _swift_js_take_exception() { + throw error + } +} + #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DefaultArgumentImports_runJsDefaultArgumentTests_static") fileprivate func bjs_DefaultArgumentImports_runJsDefaultArgumentTests_static_extern() -> Void diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index a51e6bafd..297ab5a07 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -11604,6 +11604,374 @@ ], "exposeToGlobal" : false, "functions" : [ + { + "abiName" : "bjs_awaitAsyncCallback", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "awaitAsyncCallback", + "parameters" : [ + { + "label" : "_", + "name" : "fetch", + "type" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "20BridgeJSRuntimeTestsYaKSS_SS", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_makeAsyncParser", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAsyncParser", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "20BridgeJSRuntimeTestsYaKSS_SS", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_makeAsyncEcho", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAsyncEcho", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsYaSS_SS", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_makeAsyncRecorder", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAsyncRecorder", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "20BridgeJSRuntimeTestsYaKSS_y", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "void" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_lastRecordedValue", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "lastRecordedValue", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_makeAsyncPayloadLoader", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAsyncPayloadLoader", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "bool" : { + + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_awaitPayloadCallback", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "awaitPayloadCallback", + "parameters" : [ + { + "label" : "_", + "name" : "load", + "type" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : true, + "mangleName" : "20BridgeJSRuntimeTestsYaKSb_18AsyncPayloadResultO", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "bool" : { + + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "AsyncPayloadResult" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_makeAsyncPointMaker", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAsyncPointMaker", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : true, + "isThrows" : false, + "mangleName" : "20BridgeJSRuntimeTestsYaSd_9DataPointV", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "double" : { + + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_makeThrowingParser", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeThrowingParser", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : true, + "mangleName" : "20BridgeJSRuntimeTestsKSS_Si", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : true + } + } + }, + { + "abiName" : "bjs_runValidator", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "runValidator", + "parameters" : [ + { + "label" : "_", + "name" : "validate", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : true, + "mangleName" : "20BridgeJSRuntimeTestsKSS_Sb", + "moduleName" : "BridgeJSRuntimeTests", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "bool" : { + + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "bool" : { + + } + } + }, { "abiName" : "bjs_roundTripVoid", "effects" : { @@ -18709,6 +19077,45 @@ { "functions" : [ + ], + "types" : [ + { + "accessLevel" : "internal", + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "ClosureAsyncImports", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : true, + "isStatic" : false, + "isThrows" : true + }, + "name" : "runJsClosureAsyncTests", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ] + } + ] + }, + { + "functions" : [ + ], "types" : [ { @@ -19527,6 +19934,45 @@ { "functions" : [ + ], + "types" : [ + { + "accessLevel" : "internal", + "getters" : [ + + ], + "methods" : [ + + ], + "name" : "ClosureThrowsImports", + "setters" : [ + + ], + "staticMethods" : [ + { + "accessLevel" : "internal", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : true + }, + "name" : "runJsClosureThrowsTests", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ] + } + ] + }, + { + "functions" : [ + ], "types" : [ { diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs new file mode 100644 index 000000000..d7f249ec4 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs @@ -0,0 +1,137 @@ +import assert from "node:assert"; +import { AsyncPayloadResultValues } from '../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.js'; + +/** + * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["ClosureAsyncImports"]} + */ +export function getImports(importsContext) { + return { + runJsClosureAsyncTests: async () => { + const exports = importsContext.getExports(); + if (!exports) { + throw new Error("No exports!?"); + } + await runJsClosureAsyncTests(exports); + }, + }; +} + +/** @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ +export async function runJsClosureAsyncTests(exports) { + assert.equal( + await exports.awaitAsyncCallback(async (req) => { + await Promise.resolve(); + return `js-${req}`; + }), + "swift-saw:js-request", + ); + + let directionAReject = null; + try { + await exports.awaitAsyncCallback(async () => { + throw new Error("CallbackRejected"); + }); + assert.fail("Expected awaitAsyncCallback to reject when the JS callback rejects"); + } catch (error) { + directionAReject = error; + } + assert.notEqual(directionAReject, null); + assert.equal(directionAReject.message, "CallbackRejected"); + + const parser = exports.makeAsyncParser(); + + const parsed = parser("42"); + assert.ok(parsed instanceof Promise, "async closure must return a Promise"); + assert.equal(await parsed, "parsed:42"); + assert.equal(await parser("-7"), "parsed:-7"); + + // Blocked by swiftlang/swift#89320 (wasm32 typed-throws async miscompile for captureless closures); re-enable once swiftlang/swift#89715 lands. + const ASYNC_THROWS_CLOSURE_REJECT_BLOCKED = true; + if (!ASYNC_THROWS_CLOSURE_REJECT_BLOCKED) { + let directionBReject = null; + try { + await parser("not-a-number"); + assert.fail("Expected makeAsyncParser closure to reject for invalid input"); + } catch (error) { + directionBReject = error; + } + assert.notEqual(directionBReject, null); + assert.equal(directionBReject.message, "AsyncParseError: not-a-number"); + } + + assert.equal(await parser("100"), "parsed:100"); + + const echo = exports.makeAsyncEcho(); + const echoed = echo("hi"); + assert.ok(echoed instanceof Promise, "non-throwing async closure must return a Promise"); + assert.equal(await echoed, "echo:hi"); + + const recorder = exports.makeAsyncRecorder(); + const recorded = recorder("logged-value"); + assert.ok(recorded instanceof Promise, "Void async closure must return a Promise"); + assert.equal(await recorded, undefined); + assert.equal(exports.lastRecordedValue(), "logged-value"); + + if (!ASYNC_THROWS_CLOSURE_REJECT_BLOCKED) { + let voidReject = null; + try { + await recorder("boom"); + assert.fail("Expected makeAsyncRecorder closure to reject for 'boom'"); + } catch (error) { + voidReject = error; + } + assert.notEqual(voidReject, null); + assert.equal(voidReject.message, "AsyncRecorderError"); + } + + const payloadLoader = exports.makeAsyncPayloadLoader(); + const payloadPromise = payloadLoader(true); + assert.ok(payloadPromise instanceof Promise, "associated-value enum async closure must return a Promise"); + assert.deepEqual(await payloadPromise, { tag: AsyncPayloadResultValues.Tag.Success, param0: "loaded" }); + assert.deepEqual(await payloadLoader(false), { tag: AsyncPayloadResultValues.Tag.Failure, param0: 42 }); + + assert.equal( + await exports.awaitPayloadCallback(async (succeed) => { + await Promise.resolve(); + return succeed + ? { tag: AsyncPayloadResultValues.Tag.Success, param0: "js" } + : { tag: AsyncPayloadResultValues.Tag.Idle }; + }), + "success:js|idle", + ); + + const pointMaker = exports.makeAsyncPointMaker(); + const pointPromise = pointMaker(3); + assert.ok(pointPromise instanceof Promise, "struct-returning async closure must return a Promise"); + const point = await pointPromise; + assert.equal(point.x, 3); + assert.equal(point.y, 6); + assert.equal(point.label, "async:3.0"); + + { + const racer = exports.makeAsyncEcho(); + const inFlight = racer("race"); + if (typeof racer.release === "function") { + racer.release(); + } + if (typeof global !== "undefined" && typeof global.gc === "function") { + global.gc(); + } + assert.equal(await inFlight, "echo:race"); + } + + { + const concurrent = exports.makeAsyncEcho(); + const promises = []; + for (let i = 0; i < 16; i++) { + promises.push(concurrent("c" + i)); + } + const results = await Promise.all(promises); + for (let i = 0; i < 16; i++) { + assert.equal(results[i], "echo:c" + i); + } + if (typeof concurrent.release === "function") { + concurrent.release(); + } + } +} diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureThrowsTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureThrowsTests.mjs new file mode 100644 index 000000000..94bd27d5c --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureThrowsTests.mjs @@ -0,0 +1,57 @@ +import assert from "node:assert"; + +/** + * @returns {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Imports["ClosureThrowsImports"]} + */ +export function getImports(importsContext) { + return { + runJsClosureThrowsTests: () => { + const exports = importsContext.getExports(); + if (!exports) { + throw new Error("No exports!?"); + } + runJsClosureThrowsTests(exports); + }, + }; +} + +/** @param {import('../../../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ +export function runJsClosureThrowsTests(exports) { + const parser = exports.makeThrowingParser(); + + assert.equal(parser("42"), 42); + assert.equal(parser("-7"), -7); + + let caught = null; + try { + parser("not-a-number"); + assert.fail("Expected makeThrowingParser closure to throw for invalid input"); + } catch (error) { + caught = error; + } + assert.notEqual(caught, null); + assert.equal(caught.message, "ParseError: not-a-number"); + + assert.equal(parser("100"), 100); + + assert.equal( + exports.runValidator((value) => value === "input"), + true, + ); + assert.equal( + exports.runValidator((value) => value === "something-else"), + false, + ); + + let propagated = null; + try { + exports.runValidator(() => { + throw new Error("ValidatorError"); + }); + assert.fail("Expected runValidator to propagate the JS callback error"); + } catch (error) { + propagated = error; + } + assert.notEqual(propagated, null); + assert.equal(propagated.message, "ValidatorError"); +} diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index bf3073c62..658bceed9 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -6,6 +6,8 @@ import { import { ImportedFoo } from './BridgeJSRuntimeTests/JavaScript/Types.mjs'; import { runJsOptionalSupportTests } from './BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs'; import { getImports as getClosureSupportImports } from './BridgeJSRuntimeTests/JavaScript/ClosureSupportTests.mjs'; +import { getImports as getClosureThrowsImports } from './BridgeJSRuntimeTests/JavaScript/ClosureThrowsTests.mjs'; +import { getImports as getClosureAsyncImports } from './BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs'; import { getImports as getSwiftClassSupportImports } from './BridgeJSRuntimeTests/JavaScript/SwiftClassSupportTests.mjs'; import { getImports as getOptionalSupportImports } from './BridgeJSRuntimeTests/JavaScript/OptionalSupportTests.mjs'; import { getImports as getArraySupportImports, ArrayElementObject } from './BridgeJSRuntimeTests/JavaScript/ArraySupportTests.mjs'; @@ -160,6 +162,8 @@ export async function setupOptions(options, context) { runJsOptionalSupportTests(exports); }, ClosureSupportImports: getClosureSupportImports(importsContext), + ClosureThrowsImports: getClosureThrowsImports(importsContext), + ClosureAsyncImports: getClosureAsyncImports(importsContext), SwiftClassSupportImports: getSwiftClassSupportImports(importsContext), OptionalSupportImports: getOptionalSupportImports(importsContext), ArraySupportImports: getArraySupportImports(importsContext), From c02073465631e595fecff9872db7450707b37b49 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 11 Jun 2026 11:42:34 +0200 Subject: [PATCH 67/68] BridgeJS: Warn on async throwing closures passed to JavaScript --- .../BridgeJS/Sources/BridgeJSCore/Misc.swift | 20 ++- .../BridgeJSCore/SwiftToSkeleton.swift | 53 +++++++- .../Sources/BridgeJSTool/BridgeJSTool.swift | 3 + .../BridgeJSToolInternal.swift | 5 + .../ClosureAsyncThrowsWarningTests.swift | 122 ++++++++++++++++++ .../Bringing-Swift-Closures-to-JavaScript.md | 2 +- .../Exporting-Swift-Closure.md | 2 +- 7 files changed, 197 insertions(+), 10 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift index 37040d7a6..8d7b7c902 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/Misc.swift @@ -137,14 +137,21 @@ import SwiftSyntax import class Foundation.ProcessInfo public struct DiagnosticError: Error { + public enum Severity: String, Sendable { + case error + case warning + } + public let node: Syntax public let message: String public let hint: String? + public let severity: Severity - public init(node: some SyntaxProtocol, message: String, hint: String? = nil) { + public init(node: some SyntaxProtocol, message: String, hint: String? = nil, severity: Severity = .error) { self.node = Syntax(node) self.message = message self.hint = hint + self.severity = severity } /// Formats the diagnostic error as a string. @@ -166,12 +173,14 @@ public struct DiagnosticError: Error { let lineNumberWidth = max(3, String(lines.count).count) + let severityLabel = severity.rawValue + let severityColor = severity == .warning ? ANSI.boldYellow : ANSI.boldRed let header: String = { guard colorize else { - return "\(displayFileName):\(startLocation.line):\(startLocation.column): error: \(message)" + return "\(displayFileName):\(startLocation.line):\(startLocation.column): \(severityLabel): \(message)" } return - "\(displayFileName):\(startLocation.line):\(startLocation.column): \(ANSI.boldRed)error: \(ANSI.boldDefault)\(message)\(ANSI.reset)" + "\(displayFileName):\(startLocation.line):\(startLocation.column): \(severityColor)\(severityLabel): \(ANSI.boldDefault)\(message)\(ANSI.reset)" }() let highlightStartColumn = min(max(1, startLocation.column), mainLine.utf8.count + 1) @@ -227,8 +236,8 @@ public struct DiagnosticError: Error { let pointerSpacing = max(0, highlightStartColumn - 1) let pointerMessage: String = { let pointer = String(repeating: " ", count: pointerSpacing) + "`- " - guard colorize else { return pointer + "error: \(message)" } - return pointer + "\(ANSI.boldRed)error: \(ANSI.boldDefault)\(message)\(ANSI.reset)" + guard colorize else { return pointer + "\(severityLabel): \(message)" } + return pointer + "\(severityColor)\(severityLabel): \(ANSI.boldDefault)\(message)\(ANSI.reset)" }() descriptionParts.append( Self.formatSourceLine( @@ -304,6 +313,7 @@ public struct BridgeJSCoreDiagnosticError: Swift.Error, CustomStringConvertible private enum ANSI { static let reset = "\u{001B}[0;0m" static let boldRed = "\u{001B}[1;31m" + static let boldYellow = "\u{001B}[1;33m" static let boldDefault = "\u{001B}[1;39m" static let cyan = "\u{001B}[0;36m" static let underline = "\u{001B}[4;39m" diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 18bde3c7f..ab9175e16 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -24,6 +24,9 @@ public final class SwiftToSkeleton { private var sourceFiles: [(sourceFile: SourceFileSyntax, inputFilePath: String)] = [] private var usedExternalModules = Set() + /// Non-fatal diagnostics collected during `finalize()`. These do not fail the build. + public private(set) var warnings: [(file: String, diagnostic: DiagnosticError)] = [] + public init( progress: ProgressReporting, moduleName: String, @@ -87,10 +90,15 @@ public final class SwiftToSkeleton { ) importCollector.walk(sourceFile) - let importErrorsFatal = importCollector.errors.filter { !$0.message.contains("Unsupported type '") } - if !exportCollector.errors.isEmpty || !importErrorsFatal.isEmpty { + let exportErrors = exportCollector.errors.filter { $0.severity == .error } + let importErrorsFatal = importCollector.errors.filter { + $0.severity == .error && !$0.message.contains("Unsupported type '") + } + let fileWarnings = (exportCollector.errors + importCollector.errors).filter { $0.severity == .warning } + warnings.append(contentsOf: fileWarnings.map { (file: inputFilePath, diagnostic: $0) }) + if !exportErrors.isEmpty || !importErrorsFatal.isEmpty { perSourceErrors.append( - (inputFilePath: inputFilePath, errors: exportCollector.errors + importErrorsFatal) + (inputFilePath: inputFilePath, errors: exportErrors + importErrorsFatal) ) } @@ -602,6 +610,37 @@ private enum ExportSwiftConstants { static let supportedRawTypes = SwiftEnumRawType.supportedTypeNames } +/// Warns about Swift closures handed to JavaScript with an `async throws(JSException)` signature. +/// Captureless closure values lose their thrown error at runtime due to a Swift compiler bug. +private func asyncThrowsClosureWarning(node: some SyntaxProtocol) -> DiagnosticError { + DiagnosticError( + node: node, + message: + "async throwing closures passed to JavaScript may lose thrown errors due to a Swift compiler bug " + + "(swiftlang/swift#89320) unless the closure value captures state", + hint: + "Pass a closure that captures state, or see the BridgeJS closure documentation for details", + severity: .warning + ) +} + +extension BridgeType { + fileprivate var containsAsyncThrowsClosure: Bool { + switch self { + case .closure(let signature, _): + return signature.isAsync && signature.isThrows + case .nullable(let wrapped, _): + return wrapped.containsAsyncThrowsClosure + case .array(let element): + return element.containsAsyncThrowsClosure + case .dictionary(let value): + return value.containsAsyncThrowsClosure + default: + return false + } + } +} + extension AttributeSyntax { /// The attribute name as text when it is a simple identifier (e.g. "JS", "JSFunction"). /// Prefer this over `attributeName.trimmedDescription` for name checks to avoid unnecessary string work. @@ -1194,6 +1233,9 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { guard let type = resolvedType else { return nil } returnType = type + if returnType.containsAsyncThrowsClosure { + errors.append(asyncThrowsClosureWarning(node: returnClause.type)) + } } else { returnType = .void } @@ -2853,6 +2895,11 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { guard let bridgeType = withLookupErrors({ parent.lookupType(for: type, errors: &$0) }) else { return nil } + if case .closure(let signature, useJSTypedClosure: true) = bridgeType, + signature.isAsync, signature.isThrows + { + errors.append(asyncThrowsClosureWarning(node: type)) + } let nameToken = param.secondName ?? param.firstName let name = SwiftToSkeleton.normalizeIdentifier(nameToken.text) let labelToken = param.secondName == nil ? nil : param.firstName diff --git a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift index 005af04a8..fa8a0a273 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSTool.swift @@ -201,6 +201,9 @@ import BridgeJSUtilities let skeleton = try withSpan("SwiftToSkeleton.finalize") { return try swiftToSkeleton.finalize() } + for (file, diagnostic) in swiftToSkeleton.warnings { + printStderr(diagnostic.formattedDescription(fileName: file)) + } var exporter: ExportSwift? if let skeleton = skeleton.exported { diff --git a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift index f4de24093..4a58f1972 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSToolInternal/BridgeJSToolInternal.swift @@ -60,6 +60,11 @@ import ArgumentParser swiftToSkeleton.addSourceFile(sourceFile, inputFilePath: inputFile) } let skeleton = try swiftToSkeleton.finalize() + for (file, diagnostic) in swiftToSkeleton.warnings { + FileHandle.standardError.write( + Data((diagnostic.formattedDescription(fileName: file, colorize: false) + "\n").utf8) + ) + } let encoder = JSONEncoder() encoder.outputFormatting = [.prettyPrinted, .sortedKeys] let skeletonData = try encoder.encode(skeleton) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift new file mode 100644 index 000000000..4ee9bc5cc --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift @@ -0,0 +1,122 @@ +import Foundation +import SwiftParser +import SwiftSyntax +import Testing + +@testable import BridgeJSCore +@testable import BridgeJSSkeleton + +@Suite struct ClosureAsyncThrowsWarningTests { + @Test + func warnsOnTypedAsyncThrowsClosureReturn() throws { + let result = try resolveApp( + source: """ + @JS public func makeParser() -> JSTypedClosure<(String) async throws(JSException) -> String> { + fatalError() + } + """ + ) + #expect(result.warnings.count == 1) + let warning = try #require(result.warnings.first) + #expect(warning.diagnostic.severity == .warning) + #expect(warning.diagnostic.message.contains("swiftlang/swift#89320")) + } + + @Test + func warnsOnPlainAsyncThrowsClosureReturn() throws { + let result = try resolveApp( + source: """ + @JS public func makeParser() -> (String) async throws(JSException) -> String { + fatalError() + } + """ + ) + #expect(result.warnings.count == 1) + #expect(result.warnings.first?.diagnostic.severity == .warning) + } + + @Test + func doesNotWarnOnAsyncThrowsClosureParameter() throws { + let result = try resolveApp( + source: """ + @JS public func process(_ cb: (String) async throws(JSException) -> String) {} + """ + ) + #expect(result.warnings.isEmpty) + } + + @Test + func doesNotWarnOnNonThrowingAsyncClosureReturn() throws { + let result = try resolveApp( + source: """ + @JS public func makeParser() -> JSTypedClosure<(String) async -> String> { + fatalError() + } + """ + ) + #expect(result.warnings.isEmpty) + } + + @Test + func doesNotWarnOnSyncThrowsClosureReturn() throws { + let result = try resolveApp( + source: """ + @JS public func makeParser() -> JSTypedClosure<(String) throws(JSException) -> String> { + fatalError() + } + """ + ) + #expect(result.warnings.isEmpty) + } + + @Test + func warnsOnTypedAsyncThrowsClosureImportParameter() throws { + let result = try resolveApp( + source: """ + @JSFunction func register( + _ cb: JSTypedClosure<(String) async throws(JSException) -> String> + ) throws(JSException) + """ + ) + #expect(result.warnings.count == 1) + #expect(result.warnings.first?.diagnostic.severity == .warning) + } + + @Test + func warningDoesNotFailSkeletonResolution() throws { + let result = try resolveApp( + source: """ + @JS public func makeParser() -> JSTypedClosure<(String) async throws(JSException) -> String> { + fatalError() + } + """ + ) + let function = try #require(result.skeleton.exported?.functions.first(where: { $0.name == "makeParser" })) + guard case .closure(let signature, true) = function.returnType else { + Issue.record("Expected typed closure return type, got \(function.returnType)") + return + } + #expect(signature.isAsync) + #expect(signature.isThrows) + } + + // MARK: - Utilities + + private struct Resolution { + let skeleton: BridgeJSSkeleton + let warnings: [(file: String, diagnostic: DiagnosticError)] + } + + private func resolveApp(source appSource: String) throws -> Resolution { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "App", + exposeToGlobal: false, + externalModuleIndex: ExternalModuleIndex(dependencies: []) + ) + let sourceFile = Parser.parse(source: appSource) + swiftAPI.addSourceFile(sourceFile, inputFilePath: "App.swift") + let skeleton = try swiftAPI.finalize() + return Resolution(skeleton: skeleton, warnings: swiftAPI.warnings) + } +} diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md index 2d0c94152..81383cb83 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md @@ -78,7 +78,7 @@ const count = await fetchCount("/items"); // Promise **Cancellation is a non-goal.** There is no propagation between a Swift `Task` and a JavaScript `Promise` in either direction. -> Note: The reject path of async throwing typed closures is affected by a Swift compiler bug ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320)). See for details. +> Note: The reject path of async throwing typed closures is affected by a Swift compiler bug ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320)); BridgeJS emits a build-time warning for this signature. See for details. ## Lifetime and release() diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md index 4dd08faa8..8e3e70176 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md @@ -239,7 +239,7 @@ Notes: - The same `JavaScriptEventLoop.installGlobalExecutor()` requirement applies as for async functions; there is no special handling for closures. - **Cancellation is a non-goal.** There is no propagation between a Swift `Task` and a JavaScript `Promise` in either direction; cancelling one side does not cancel the other. -> Warning: When an async throwing closure handed to JavaScript throws, the error is currently lost instead of rejecting the `Promise` with it, due to a Swift compiler bug on `wasm32` ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320), fix in progress in [swiftlang/swift#89715](https://github.com/swiftlang/swift/pull/89715)). Closures that capture state are unaffected, as are throwing JavaScript callbacks passed into Swift. +> Warning: When an async throwing closure handed to JavaScript throws, the error is currently lost instead of rejecting the `Promise` with it, due to a Swift compiler bug on `wasm32` ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320), fix in progress in [swiftlang/swift#89715](https://github.com/swiftlang/swift/pull/89715)). Closures that capture state are unaffected, as are throwing JavaScript callbacks passed into Swift. BridgeJS emits a build-time warning for this signature. ## Supported Features From d26143ea6797d94f37ff76bc2f242b81c1cc28ad Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 11 Jun 2026 09:24:29 +0200 Subject: [PATCH 68/68] Box JSException storage in a class to fit the direct typed-error convention --- .../BridgeJSCore/SwiftToSkeleton.swift | 39 ------ .../ClosureAsyncThrowsWarningTests.swift | 122 ------------------ .../Bringing-Swift-Closures-to-JavaScript.md | 1 - .../Exporting-Swift-Closure.md | 4 +- Sources/JavaScriptKit/JSException.swift | 64 ++++++--- .../JavaScript/ClosureAsyncTests.mjs | 6 - .../JSClosure+AsyncTests.swift | 12 ++ 7 files changed, 63 insertions(+), 185 deletions(-) delete mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index ab9175e16..a6afe2779 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -610,37 +610,6 @@ private enum ExportSwiftConstants { static let supportedRawTypes = SwiftEnumRawType.supportedTypeNames } -/// Warns about Swift closures handed to JavaScript with an `async throws(JSException)` signature. -/// Captureless closure values lose their thrown error at runtime due to a Swift compiler bug. -private func asyncThrowsClosureWarning(node: some SyntaxProtocol) -> DiagnosticError { - DiagnosticError( - node: node, - message: - "async throwing closures passed to JavaScript may lose thrown errors due to a Swift compiler bug " - + "(swiftlang/swift#89320) unless the closure value captures state", - hint: - "Pass a closure that captures state, or see the BridgeJS closure documentation for details", - severity: .warning - ) -} - -extension BridgeType { - fileprivate var containsAsyncThrowsClosure: Bool { - switch self { - case .closure(let signature, _): - return signature.isAsync && signature.isThrows - case .nullable(let wrapped, _): - return wrapped.containsAsyncThrowsClosure - case .array(let element): - return element.containsAsyncThrowsClosure - case .dictionary(let value): - return value.containsAsyncThrowsClosure - default: - return false - } - } -} - extension AttributeSyntax { /// The attribute name as text when it is a simple identifier (e.g. "JS", "JSFunction"). /// Prefer this over `attributeName.trimmedDescription` for name checks to avoid unnecessary string work. @@ -1233,9 +1202,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { guard let type = resolvedType else { return nil } returnType = type - if returnType.containsAsyncThrowsClosure { - errors.append(asyncThrowsClosureWarning(node: returnClause.type)) - } } else { returnType = .void } @@ -2895,11 +2861,6 @@ private final class ImportSwiftMacrosAPICollector: SyntaxAnyVisitor { guard let bridgeType = withLookupErrors({ parent.lookupType(for: type, errors: &$0) }) else { return nil } - if case .closure(let signature, useJSTypedClosure: true) = bridgeType, - signature.isAsync, signature.isThrows - { - errors.append(asyncThrowsClosureWarning(node: type)) - } let nameToken = param.secondName ?? param.firstName let name = SwiftToSkeleton.normalizeIdentifier(nameToken.text) let labelToken = param.secondName == nil ? nil : param.firstName diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift deleted file mode 100644 index 4ee9bc5cc..000000000 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/ClosureAsyncThrowsWarningTests.swift +++ /dev/null @@ -1,122 +0,0 @@ -import Foundation -import SwiftParser -import SwiftSyntax -import Testing - -@testable import BridgeJSCore -@testable import BridgeJSSkeleton - -@Suite struct ClosureAsyncThrowsWarningTests { - @Test - func warnsOnTypedAsyncThrowsClosureReturn() throws { - let result = try resolveApp( - source: """ - @JS public func makeParser() -> JSTypedClosure<(String) async throws(JSException) -> String> { - fatalError() - } - """ - ) - #expect(result.warnings.count == 1) - let warning = try #require(result.warnings.first) - #expect(warning.diagnostic.severity == .warning) - #expect(warning.diagnostic.message.contains("swiftlang/swift#89320")) - } - - @Test - func warnsOnPlainAsyncThrowsClosureReturn() throws { - let result = try resolveApp( - source: """ - @JS public func makeParser() -> (String) async throws(JSException) -> String { - fatalError() - } - """ - ) - #expect(result.warnings.count == 1) - #expect(result.warnings.first?.diagnostic.severity == .warning) - } - - @Test - func doesNotWarnOnAsyncThrowsClosureParameter() throws { - let result = try resolveApp( - source: """ - @JS public func process(_ cb: (String) async throws(JSException) -> String) {} - """ - ) - #expect(result.warnings.isEmpty) - } - - @Test - func doesNotWarnOnNonThrowingAsyncClosureReturn() throws { - let result = try resolveApp( - source: """ - @JS public func makeParser() -> JSTypedClosure<(String) async -> String> { - fatalError() - } - """ - ) - #expect(result.warnings.isEmpty) - } - - @Test - func doesNotWarnOnSyncThrowsClosureReturn() throws { - let result = try resolveApp( - source: """ - @JS public func makeParser() -> JSTypedClosure<(String) throws(JSException) -> String> { - fatalError() - } - """ - ) - #expect(result.warnings.isEmpty) - } - - @Test - func warnsOnTypedAsyncThrowsClosureImportParameter() throws { - let result = try resolveApp( - source: """ - @JSFunction func register( - _ cb: JSTypedClosure<(String) async throws(JSException) -> String> - ) throws(JSException) - """ - ) - #expect(result.warnings.count == 1) - #expect(result.warnings.first?.diagnostic.severity == .warning) - } - - @Test - func warningDoesNotFailSkeletonResolution() throws { - let result = try resolveApp( - source: """ - @JS public func makeParser() -> JSTypedClosure<(String) async throws(JSException) -> String> { - fatalError() - } - """ - ) - let function = try #require(result.skeleton.exported?.functions.first(where: { $0.name == "makeParser" })) - guard case .closure(let signature, true) = function.returnType else { - Issue.record("Expected typed closure return type, got \(function.returnType)") - return - } - #expect(signature.isAsync) - #expect(signature.isThrows) - } - - // MARK: - Utilities - - private struct Resolution { - let skeleton: BridgeJSSkeleton - let warnings: [(file: String, diagnostic: DiagnosticError)] - } - - private func resolveApp(source appSource: String) throws -> Resolution { - let swiftAPI = SwiftToSkeleton( - progress: .silent, - moduleName: "App", - exposeToGlobal: false, - externalModuleIndex: ExternalModuleIndex(dependencies: []) - ) - let sourceFile = Parser.parse(source: appSource) - swiftAPI.addSourceFile(sourceFile, inputFilePath: "App.swift") - let skeleton = try swiftAPI.finalize() - return Resolution(skeleton: skeleton, warnings: swiftAPI.warnings) - } -} diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md index 81383cb83..7b95feb50 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Bringing-Swift-Closures-to-JavaScript.md @@ -78,7 +78,6 @@ const count = await fetchCount("/items"); // Promise **Cancellation is a non-goal.** There is no propagation between a Swift `Task` and a JavaScript `Promise` in either direction. -> Note: The reject path of async throwing typed closures is affected by a Swift compiler bug ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320)); BridgeJS emits a build-time warning for this signature. See for details. ## Lifetime and release() diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md index 8e3e70176..9b9f4ab97 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md @@ -239,7 +239,7 @@ Notes: - The same `JavaScriptEventLoop.installGlobalExecutor()` requirement applies as for async functions; there is no special handling for closures. - **Cancellation is a non-goal.** There is no propagation between a Swift `Task` and a JavaScript `Promise` in either direction; cancelling one side does not cancel the other. -> Warning: When an async throwing closure handed to JavaScript throws, the error is currently lost instead of rejecting the `Promise` with it, due to a Swift compiler bug on `wasm32` ([swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320), fix in progress in [swiftlang/swift#89715](https://github.com/swiftlang/swift/pull/89715)). Closures that capture state are unaffected, as are throwing JavaScript callbacks passed into Swift. BridgeJS emits a build-time warning for this signature. + ## Supported Features @@ -251,7 +251,7 @@ Notes: | Optional types in closures | ✅ | | Closure-typed `@JS` properties | ❌ | | Async closures `(A) async -> B` | ✅ | -| Async throwing closures `(A) async throws(JSException) -> B` | ✅ (reject path of closures handed to JS pending [swiftlang/swift#89320](https://github.com/swiftlang/swift/issues/89320)) | +| Async throwing closures `(A) async throws(JSException) -> B` | ✅ | | Throwing closures `(A) throws(JSException) -> B` | ✅ | ## See Also diff --git a/Sources/JavaScriptKit/JSException.swift b/Sources/JavaScriptKit/JSException.swift index 4d95e207d..84232163c 100644 --- a/Sources/JavaScriptKit/JSException.swift +++ b/Sources/JavaScriptKit/JSException.swift @@ -13,38 +13,66 @@ /// } /// ``` public struct JSException: Error, Equatable, CustomStringConvertible { - /// The value thrown from JavaScript. - /// This can be any JavaScript value (error object, string, number, etc.). - public var thrownValue: JSValue { - return _thrownValue + /// Boxes the exception payload in a class so `JSException` stays within the direct + /// typed-error convention on wasm32. + private final class Storage { + /// The actual JavaScript value that was thrown. + let thrownValue: JSValue + + /// A description of the exception. + let description: String + + /// The stack trace of the exception. + let stack: String? + + init(thrownValue: JSValue, description: String, stack: String?) { + self.thrownValue = thrownValue + self.description = description + self.stack = stack + } } - /// The actual JavaScript value that was thrown. + /// The boxed payload of the exception. /// /// Marked as `nonisolated(unsafe)` to satisfy `Sendable` requirement /// from `Error` protocol. - private nonisolated(unsafe) let _thrownValue: JSValue + private nonisolated(unsafe) let storage: Storage + + /// The value thrown from JavaScript. + /// This can be any JavaScript value (error object, string, number, etc.). + public var thrownValue: JSValue { + return storage.thrownValue + } /// A description of the exception. - public let description: String + public var description: String { + return storage.description + } /// The stack trace of the exception. - public let stack: String? + public var stack: String? { + return storage.stack + } /// Initializes a new JSException instance with a value thrown from JavaScript. /// /// Only available within the package. This must be called on the thread where the exception object created. + /// The stringified representation is captured on the object owner thread to bring useful info + /// to the catching thread even if they are different threads. @usableFromInline package init(_ thrownValue: JSValue) { - self._thrownValue = thrownValue - // Capture the stringified representation on the object owner thread - // to bring useful info to the catching thread even if they are different threads. if let errorObject = thrownValue.object, let stack = errorObject.stack.string { - self.description = "JSException(\(stack))" - self.stack = stack + self.storage = Storage( + thrownValue: thrownValue, + description: "JSException(\(stack))", + stack: stack + ) } else { - self.description = "JSException(\(thrownValue))" - self.stack = nil + self.storage = Storage( + thrownValue: thrownValue, + description: "JSException(\(thrownValue))", + stack: nil + ) } } @@ -55,4 +83,10 @@ public struct JSException: Error, Equatable, CustomStringConvertible { public init(message: String) { self.init(JSError(message: message).jsValue) } + + public static func == (lhs: JSException, rhs: JSException) -> Bool { + return lhs.storage.thrownValue == rhs.storage.thrownValue + && lhs.storage.description == rhs.storage.description + && lhs.storage.stack == rhs.storage.stack + } } diff --git a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs index d7f249ec4..57a824aa4 100644 --- a/Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs +++ b/Tests/BridgeJSRuntimeTests/JavaScript/ClosureAsyncTests.mjs @@ -45,9 +45,6 @@ export async function runJsClosureAsyncTests(exports) { assert.equal(await parsed, "parsed:42"); assert.equal(await parser("-7"), "parsed:-7"); - // Blocked by swiftlang/swift#89320 (wasm32 typed-throws async miscompile for captureless closures); re-enable once swiftlang/swift#89715 lands. - const ASYNC_THROWS_CLOSURE_REJECT_BLOCKED = true; - if (!ASYNC_THROWS_CLOSURE_REJECT_BLOCKED) { let directionBReject = null; try { await parser("not-a-number"); @@ -57,7 +54,6 @@ export async function runJsClosureAsyncTests(exports) { } assert.notEqual(directionBReject, null); assert.equal(directionBReject.message, "AsyncParseError: not-a-number"); - } assert.equal(await parser("100"), "parsed:100"); @@ -72,7 +68,6 @@ export async function runJsClosureAsyncTests(exports) { assert.equal(await recorded, undefined); assert.equal(exports.lastRecordedValue(), "logged-value"); - if (!ASYNC_THROWS_CLOSURE_REJECT_BLOCKED) { let voidReject = null; try { await recorder("boom"); @@ -82,7 +77,6 @@ export async function runJsClosureAsyncTests(exports) { } assert.notEqual(voidReject, null); assert.equal(voidReject.message, "AsyncRecorderError"); - } const payloadLoader = exports.makeAsyncPayloadLoader(); const payloadPromise = payloadLoader(true); diff --git a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift index e3c19a8e4..f53c7eeb7 100644 --- a/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift +++ b/Tests/JavaScriptEventLoopTests/JSClosure+AsyncTests.swift @@ -24,6 +24,18 @@ class JSClosureAsyncTests: XCTestCase { XCTAssertEqual(result, 42.0) } + func testAsyncClosureReject() async throws { + let closure = JSClosure.async { (_) async throws(JSException) -> JSValue in + throw JSException(message: "AsyncClosureRejected") + }.jsValue + let result = await JSPromise(from: closure.function!())!.result + guard case .failure(let rejectedValue) = result else { + XCTFail("Expected the async closure promise to reject, got \(result)") + return + } + XCTAssertEqual(rejectedValue.object?.message.string, "AsyncClosureRejected") + } + func testAsyncClosureWithPriority() async throws { let priority = UnsafeSendableBox(nil) let closure = JSClosure.async(priority: .high) { _ in