From 3d17fda4c0ad9d109e4b1fe9922cda8389f30b52 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Fri, 24 Oct 2025 10:42:53 +0200 Subject: [PATCH] BridgeJS: Swift closure support --- .../Sources/BridgeJSCore/ExportSwift.swift | 364 ++++- .../Sources/BridgeJSCore/ImportTS.swift | 24 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 349 ++++- .../Sources/BridgeJSLink/JSGlueGen.swift | 664 ++++++++- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 82 +- .../Inputs/SwiftClosure.swift | 75 + .../ArrayParameter.Import.js | 14 +- .../BridgeJSLinkTests/Async.Export.js | 14 +- .../BridgeJSLinkTests/Async.Import.js | 14 +- .../DefaultParameters.Export.js | 14 +- .../EnumAssociatedValue.Export.js | 11 +- .../BridgeJSLinkTests/EnumCase.Export.js | 14 +- .../BridgeJSLinkTests/EnumNamespace.Export.js | 11 +- .../BridgeJSLinkTests/EnumRawType.Export.js | 14 +- .../BridgeJSLinkTests/Interface.Import.js | 14 +- .../InvalidPropertyNames.Import.js | 14 +- .../MultipleImportedTypes.Import.js | 14 +- .../BridgeJSLinkTests/Namespaces.Export.js | 11 +- .../BridgeJSLinkTests/Optionals.Export.js | 14 +- .../PrimitiveParameters.Export.js | 14 +- .../PrimitiveParameters.Import.js | 14 +- .../PrimitiveReturn.Export.js | 14 +- .../PrimitiveReturn.Import.js | 14 +- .../BridgeJSLinkTests/PropertyTypes.Export.js | 14 +- .../BridgeJSLinkTests/Protocol.Export.js | 14 +- .../StaticFunctions.Export.js | 11 +- .../StaticProperties.Export.js | 14 +- .../StringParameter.Export.js | 14 +- .../StringParameter.Import.js | 14 +- .../BridgeJSLinkTests/StringReturn.Export.js | 14 +- .../BridgeJSLinkTests/StringReturn.Import.js | 14 +- .../BridgeJSLinkTests/SwiftClass.Export.js | 14 +- .../SwiftClosure.Export.d.ts | 100 ++ .../BridgeJSLinkTests/SwiftClosure.Export.js | 942 +++++++++++++ .../TS2SkeletonLike.Import.js | 14 +- .../BridgeJSLinkTests/Throws.Export.js | 14 +- .../BridgeJSLinkTests/TypeAlias.Import.js | 14 +- .../TypeScriptClass.Import.js | 14 +- .../VoidParameterVoidReturn.Export.js | 14 +- .../VoidParameterVoidReturn.Import.js | 14 +- .../ExportSwiftTests/SwiftClosure.json | 1048 ++++++++++++++ .../ExportSwiftTests/SwiftClosure.swift | 915 ++++++++++++ Plugins/PackageToJS/Templates/instantiate.js | 2 + .../JavaScriptKit/BridgeJSInstrincics.swift | 114 +- .../BridgeJS/Exporting-Swift-to-JavaScript.md | 1 + .../Exporting-Swift-Closure.md | 114 ++ .../BridgeJSRuntimeTests/ExportAPITests.swift | 178 ++- .../Generated/BridgeJS.ExportSwift.swift | 1056 +++++++++++++- .../JavaScript/BridgeJS.ExportSwift.json | 1255 ++++++++++++++++- Tests/prelude.mjs | 195 +++ 50 files changed, 7683 insertions(+), 231 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/SwiftClosure.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.Export.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.Export.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.swift create mode 100644 Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 4cdc8a3b..50889462 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -28,6 +28,7 @@ public class ExportSwift { private var exportedProtocolNameByKey: [String: String] = [:] private var typeDeclResolver: TypeDeclResolver = TypeDeclResolver() private let enumCodegen: EnumCodegen = EnumCodegen() + private lazy var closureCodegen = ClosureCodegen(moduleName: moduleName) public init(progress: ProgressReporting, moduleName: String) { self.progress = progress @@ -421,7 +422,26 @@ public class ExportSwift { for param in parameterClause.parameters { let resolvedType = self.parent.lookupType(for: param.type) - + if let type = resolvedType, 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 let type = resolvedType, case .optional(let wrappedType) = type, wrappedType.isOptional { + diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) + continue + } if let type = resolvedType, case .optional(let wrappedType) = type, wrappedType.isOptional { diagnoseNestedOptional(node: param.type, type: param.type.trimmedDescription) continue @@ -1309,6 +1329,37 @@ public class ExportSwift { } func lookupType(for type: TypeSyntax) -> BridgeType? { + if let attributedType = type.as(AttributedTypeSyntax.self) { + return lookupType(for: attributedType.baseType) + } + + // (T1, T2, ...) -> R + if let functionType = type.as(FunctionTypeSyntax.self) { + var parameters: [BridgeType] = [] + for param in functionType.parameters { + guard let paramType = lookupType(for: param.type) else { + return nil + } + parameters.append(paramType) + } + + guard let returnType = lookupType(for: functionType.returnClause.type) else { + return nil + } + + let isAsync = functionType.effectSpecifiers?.asyncSpecifier != nil + let isThrows = functionType.effectSpecifiers?.throwsClause != nil + + return .closure( + ClosureSignature( + parameters: parameters, + returnType: returnType, + isAsync: isAsync, + isThrows: isThrows + ) + ) + } + // T? if let optionalType = type.as(OptionalTypeSyntax.self) { let wrappedType = optionalType.wrappedType @@ -1426,6 +1477,30 @@ public class ExportSwift { } decls.append(Self.prelude) + // Collect all unique closure signatures + var closureSignatures: Set = [] + for function in exportedFunctions { + collectClosureSignatures(from: function.parameters, into: &closureSignatures) + collectClosureSignatures(from: function.returnType, into: &closureSignatures) + } + for klass in exportedClasses { + if let constructor = klass.constructor { + collectClosureSignatures(from: constructor.parameters, into: &closureSignatures) + } + for method in klass.methods { + collectClosureSignatures(from: method.parameters, into: &closureSignatures) + collectClosureSignatures(from: method.returnType, into: &closureSignatures) + } + for property in klass.properties { + collectClosureSignatures(from: property.type, into: &closureSignatures) + } + } + + for signature in closureSignatures.sorted(by: { $0.mangleName < $1.mangleName }) { + decls.append(try closureCodegen.renderClosureHelper(signature: signature)) + decls.append(try closureCodegen.renderClosureInvokeHandler(signature: signature)) + } + for proto in exportedProtocols { decls.append(try renderProtocolWrapper(protocol: proto)) } @@ -1498,18 +1573,25 @@ public class ExportSwift { } let typeNameForIntrinsic: String + let liftingExpr: ExprSyntax + switch param.type { + case .closure(let signature): + typeNameForIntrinsic = param.type.swiftType + liftingExpr = ExprSyntax("_BJS_Closure_\(raw: signature.mangleName).bridgeJSLift(\(raw: param.name))") case .optional(let wrappedType): typeNameForIntrinsic = "Optional<\(wrappedType.swiftType)>" + liftingExpr = ExprSyntax( + "\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))" + ) default: typeNameForIntrinsic = param.type.swiftType - } - - liftedParameterExprs.append( - ExprSyntax( + liftingExpr = ExprSyntax( "\(raw: typeNameForIntrinsic).bridgeJSLiftParameter(\(raw: argumentsToLift.joined(separator: ", ")))" ) - ) + } + + liftedParameterExprs.append(liftingExpr) for (name, type) in zip(argumentsToLift, liftingInfo.parameters.map { $0.type }) { abiParameterSignatures.append((name, type)) } @@ -1660,7 +1742,11 @@ public class ExportSwift { return } - append("return ret.bridgeJSLowerReturn()") + if case .closure(let signature) = returnType { + append("return _BJS_Closure_\(raw: signature.mangleName).bridgeJSLower(ret)") + } else { + append("return ret.bridgeJSLowerReturn()") + } } func render(abiName: String) -> DeclSyntax { @@ -1730,6 +1816,204 @@ public class ExportSwift { } } + private struct ClosureCodegen { + let moduleName: String + + func generateOptionalParameterLowering(signature: ClosureSignature) throws -> String { + var lines: [String] = [] + + for (index, paramType) in signature.parameters.enumerated() { + guard case .optional(let wrappedType) = paramType else { + continue + } + + let paramName = "param\(index)" + + // Use bridgeJSLowerParameterWithRetain for heap objects in escaping closures + // to ensure proper ownership transfer + if case .swiftHeapObject = wrappedType { + lines.append( + "let (\(paramName)IsSome, \(paramName)Value) = \(paramName).bridgeJSLowerParameterWithRetain()" + ) + } else { + lines.append( + "let (\(paramName)IsSome, \(paramName)Value) = \(paramName).bridgeJSLowerParameterWithPresence()" + ) + } + } + + return lines.isEmpty ? "" : lines.joined(separator: "\n") + "\n" + } + + func renderClosureHelper(signature: ClosureSignature) throws -> DeclSyntax { + let mangledName = signature.mangleName + let helperName = "_BJS_Closure_\(mangledName)" + let boxClassName = "_BJS_ClosureBox_\(mangledName)" + + let closureParams = signature.parameters.enumerated().map { index, type in + "\(type.swiftType)" + }.joined(separator: ", ") + + let swiftEffects = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "") + let swiftReturnType = signature.returnType.swiftType + let closureType = "(\(closureParams))\(swiftEffects) -> \(swiftReturnType)" + + var invokeParams: [(name: String, type: String)] = [("_", "Int32")] + var invokeCallArgs: [String] = ["owner.callbackId"] + + for (index, paramType) in signature.parameters.enumerated() { + let paramName = "param\(index)" + + if case .optional(let wrappedType) = paramType { + invokeParams.append(("_", "Int32")) + + switch wrappedType { + case .swiftHeapObject: + invokeParams.append(("_", "UnsafeMutableRawPointer")) + case .string, .rawValueEnum(_, .string): + invokeParams.append(("_", "Int32")) + default: + let lowerInfo = try wrappedType.loweringReturnInfo() + if let wasmType = lowerInfo.returnType { + invokeParams.append(("_", wasmType.swiftType)) + } else { + invokeParams.append(("_", "Int32")) + } + } + + invokeCallArgs.append("\(paramName)IsSome") + invokeCallArgs.append("\(paramName)Value") + } else { + let lowerInfo = try paramType.loweringReturnInfo() + if let wasmType = lowerInfo.returnType { + invokeParams.append(("_", wasmType.swiftType)) + invokeCallArgs.append("\(paramName).bridgeJSLowerParameter()") + } else { + invokeParams.append(("_", "Int32")) + invokeCallArgs.append("\(paramName).bridgeJSLowerParameter()") + } + } + } + + let invokeSignature = invokeParams.map { "\($0.name): \($0.type)" }.joined(separator: ", ") + let invokeReturnType: String + if case .optional = signature.returnType { + invokeReturnType = "Void" + } else if let wasmType = try signature.returnType.liftingReturnInfo(context: .exportSwift).valueToLift { + invokeReturnType = wasmType.swiftType + } else { + invokeReturnType = "Void" + } + + let returnLifting: String + if signature.returnType == .void { + returnLifting = "_invoke(\(invokeCallArgs.joined(separator: ", ")))" + } else if case .optional = signature.returnType { + returnLifting = """ + _invoke(\(invokeCallArgs.joined(separator: ", "))) + return \(signature.returnType.swiftType).bridgeJSLiftReturnFromSideChannel() + """ + } else { + returnLifting = """ + let resultId = _invoke(\(invokeCallArgs.joined(separator: ", "))) + return \(signature.returnType.swiftType).bridgeJSLiftReturn(resultId) + """ + } + + let externName = "invoke_js_callback_\(mangledName.lowercased())" + let optionalLoweringCode = try generateOptionalParameterLowering(signature: signature) + + return """ + private final class \(raw: boxClassName): _BridgedSwiftClosureBox { + let closure: \(raw: closureType) + init(_ closure: @escaping \(raw: closureType)) { + self.closure = closure + } + } + + private enum \(raw: helperName) { + static func bridgeJSLower(_ closure: @escaping \(raw: closureType)) -> UnsafeMutableRawPointer { + let box = \(raw: boxClassName)(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> \(raw: closureType) { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] \(raw: signature.parameters.indices.map { "param\($0)" }.joined(separator: ", ")) in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "\(raw: externName)") + func _invoke(\(raw: invokeSignature)) -> \(raw: invokeReturnType) + \(raw: optionalLoweringCode)\(raw: returnLifting) + #else + fatalError("Only available on WebAssembly") + #endif + } + } + } + """ + } + + func renderClosureInvokeHandler(signature: ClosureSignature) throws -> DeclSyntax { + let boxClassName = "_BJS_ClosureBox_\(signature.mangleName)" + let abiName = "invoke_swift_closure_\(signature.mangleName.lowercased())" + + var abiParams: [(name: String, type: String)] = [("boxPtr", "UnsafeMutableRawPointer")] + var liftedParams: [String] = [] + + for (index, paramType) in signature.parameters.enumerated() { + let paramName = "param\(index)" + let liftInfo = try paramType.liftParameterInfo() + + for (argName, wasmType) in liftInfo.parameters { + let fullName = + liftInfo.parameters.count > 1 ? "\(paramName)\(argName.capitalizedFirstLetter)" : paramName + abiParams.append((fullName, wasmType.swiftType)) + } + + let argNames = liftInfo.parameters.map { (argName, _) in + liftInfo.parameters.count > 1 ? "\(paramName)\(argName.capitalizedFirstLetter)" : paramName + } + liftedParams.append("\(paramType.swiftType).bridgeJSLiftParameter(\(argNames.joined(separator: ", ")))") + } + + let paramSignature = abiParams.map { "\($0.name): \($0.type)" }.joined(separator: ", ") + let closureCall = "box.closure(\(liftedParams.joined(separator: ", ")))" + + let returnCode: String + if signature.returnType == .void { + returnCode = closureCall + } else { + returnCode = """ + let result = \(closureCall) + return result.bridgeJSLowerReturn() + """ + } + + let abiReturnType: String + if signature.returnType == .void { + abiReturnType = "Void" + } else if let wasmType = try signature.returnType.loweringReturnInfo().returnType { + abiReturnType = wasmType.swiftType + } else { + abiReturnType = "Void" + } + + return """ + @_expose(wasm, "\(raw: abiName)") + @_cdecl("\(raw: abiName)") + public func _\(raw: abiName)(\(raw: paramSignature)) -> \(raw: abiReturnType) { + #if arch(wasm32) + let box = Unmanaged<\(raw: boxClassName)>.fromOpaque(boxPtr).takeUnretainedValue() + \(raw: returnCode) + #else + fatalError("Only available on WebAssembly") + #endif + } + """ + } + + } + private struct EnumCodegen { func renderCaseEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { let typeName = enumDef.swiftCallName @@ -2187,6 +2471,29 @@ public class ExportSwift { return decls } + /// Collects all closure signatures from function parameters + private func collectClosureSignatures(from parameters: [Parameter], into signatures: inout Set) { + for param in parameters { + collectClosureSignatures(from: param.type, into: &signatures) + } + } + + /// Collects all closure signatures from a bridge type + private func collectClosureSignatures(from type: BridgeType, into signatures: inout Set) { + switch type { + case .closure(let signature): + signatures.insert(signature) + for paramType in signature.parameters { + collectClosureSignatures(from: paramType, into: &signatures) + } + collectClosureSignatures(from: signature.returnType, into: &signatures) + case .optional(let wrapped): + collectClosureSignatures(from: wrapped, into: &signatures) + default: + break + } + } + /// Generates a ConvertibleToJSValue extension for the exported class /// /// # Example @@ -2246,7 +2553,7 @@ public class ExportSwift { var externParams: [String] = ["this: Int32"] for param in method.parameters { - let loweringInfo = try param.type.loweringParameterInfo(context: .protocolExport) + let loweringInfo = try param.type.loweringParameterInfo(context: .exportSwift) for (paramName, wasmType) in loweringInfo.loweredParameters { let fullParamName = loweringInfo.loweredParameters.count > 1 @@ -2258,7 +2565,7 @@ public class ExportSwift { var preCallStatements: [String] = [] var callArgs: [String] = ["this: Int32(bitPattern: jsObject.id)"] for param in method.parameters { - let loweringInfo = try param.type.loweringParameterInfo(context: .protocolExport) + let loweringInfo = try param.type.loweringParameterInfo(context: .exportSwift) if case .optional = param.type, loweringInfo.loweredParameters.count > 1 { let isSomeName = "\(param.name)\(loweringInfo.loweredParameters[0].name.capitalizedFirstLetter)" let wrappedName = "\(param.name)\(loweringInfo.loweredParameters[1].name.capitalizedFirstLetter)" @@ -2287,7 +2594,7 @@ public class ExportSwift { } else { returnTypeStr = " -> \(method.returnType.swiftType)" let liftingInfo = try method.returnType.liftingReturnInfo( - context: .protocolExport + context: .exportSwift ) if case .optional = method.returnType { @@ -2371,30 +2678,8 @@ public class ExportSwift { className: protocolName ) - let usesSideChannel: Bool - if case .optional(let wrappedType) = property.type { - switch wrappedType { - case .string: - usesSideChannel = true - case .rawValueEnum(_, let rawType): - switch rawType { - case .string: - usesSideChannel = true - default: - usesSideChannel = true - } - case .int, .float, .double: - usesSideChannel = true - case .bool, .caseEnum, .associatedValueEnum, .swiftHeapObject: - usesSideChannel = false - default: - usesSideChannel = false - } - } else { - usesSideChannel = false - } - - let liftingInfo = try property.type.liftingReturnInfo(context: .protocolExport) + let usesSideChannel = property.type.usesSideChannelForOptionalReturn() + let liftingInfo = try property.type.liftingReturnInfo(context: .exportSwift) let getterReturnType: String let getterBody: String @@ -2430,7 +2715,7 @@ public class ExportSwift { } """ } else { - let loweringInfo = try property.type.loweringParameterInfo(context: .protocolExport) + let loweringInfo = try property.type.loweringParameterInfo(context: .exportSwift) let setterParams = (["this: Int32"] + loweringInfo.loweredParameters.map { "\($0.name): \($0.type.swiftType)" }).joined( @@ -2538,6 +2823,10 @@ extension BridgeType { case .rawValueEnum(let name, _): return name case .associatedValueEnum(let name): return name case .namespaceEnum(let name): return name + case .closure(let signature): + let paramTypes = signature.parameters.map { $0.swiftType }.joined(separator: ", ") + let effectsStr = (signature.isAsync ? " async" : "") + (signature.isThrows ? " throws" : "") + return "(\(paramTypes))\(effectsStr) -> \(signature.returnType.swiftType)" } } @@ -2591,6 +2880,8 @@ extension BridgeType { return .associatedValueEnum case .namespaceEnum: throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters") + case .closure: + return LiftingIntrinsicInfo(parameters: [("callbackId", .i32)]) } } @@ -2641,6 +2932,9 @@ extension BridgeType { return .associatedValueEnum case .namespaceEnum: throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters") + case .closure: + // Closures are returned as UnsafeMutableRawPointer (box pointer) + return .swiftHeapObject } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 4589817d..af4a59c9 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -433,6 +433,8 @@ extension BridgeType { case .string: return .string case .jsObject: return .jsObject case .void: return .void + case .closure: + throw BridgeJSCoreError("Closure types are not yet supported in TypeScript imports") case .swiftHeapObject(let className): switch context { case .importTS: @@ -442,7 +444,7 @@ extension BridgeType { Swift classes can only be used in @JS protocols where Swift owns the instance. """ ) - case .protocolExport: + case .exportSwift: return LoweringParameterInfo(loweredParameters: [("pointer", .pointer)]) } case .swiftProtocol: @@ -451,14 +453,14 @@ extension BridgeType { switch context { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: return LoweringParameterInfo(loweredParameters: [("value", .i32)]) } case .rawValueEnum(_, let rawType): switch context { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: // For protocol export we return .i32 for String raw value type instead of nil return LoweringParameterInfo(loweredParameters: [("value", rawType.wasmCoreType ?? .i32)]) } @@ -466,7 +468,7 @@ extension BridgeType { switch context { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: return LoweringParameterInfo(loweredParameters: [("caseId", .i32)]) } case .namespaceEnum: @@ -475,7 +477,7 @@ extension BridgeType { switch context { case .importTS: throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) var params = [("isSome", WasmCoreType.i32)] params.append(contentsOf: wrappedInfo.loweredParameters) @@ -507,6 +509,8 @@ extension BridgeType { case .string: return .string case .jsObject: return .jsObject case .void: return .void + case .closure: + throw BridgeJSCoreError("Closure types are not yet supported in TypeScript imports") case .swiftHeapObject(let className): switch context { case .importTS: @@ -516,7 +520,7 @@ extension BridgeType { JavaScript cannot create Swift heap objects. """ ) - case .protocolExport: + case .exportSwift: return LiftingReturnInfo(valueToLift: .pointer) } case .swiftProtocol: @@ -525,14 +529,14 @@ extension BridgeType { switch context { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: return LiftingReturnInfo(valueToLift: .i32) } case .rawValueEnum(_, let rawType): switch context { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: // For protocol export we return .i32 for String raw value type instead of nil return LiftingReturnInfo(valueToLift: rawType.wasmCoreType ?? .i32) } @@ -540,7 +544,7 @@ extension BridgeType { switch context { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: return LiftingReturnInfo(valueToLift: .i32) } case .namespaceEnum: @@ -549,7 +553,7 @@ extension BridgeType { switch context { case .importTS: throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") - case .protocolExport: + case .exportSwift: let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 6abfd305..eef3f31d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -368,9 +368,53 @@ struct BridgeJSLink { declarations.append("const enumHelpers = {};") } + declarations.append("") + declarations.append("let _exports = null;") + declarations.append("let bjs = null;") + return declarations } + /// Checks if a skeleton contains any closure types + private func hasClosureTypes(in skeleton: ExportedSkeleton) -> Bool { + for function in skeleton.functions { + if containsClosureType(in: function.parameters) || containsClosureType(in: function.returnType) { + return true + } + } + for klass in skeleton.classes { + if let constructor = klass.constructor, containsClosureType(in: constructor.parameters) { + return true + } + for method in klass.methods { + if containsClosureType(in: method.parameters) || containsClosureType(in: method.returnType) { + return true + } + } + for property in klass.properties { + if containsClosureType(in: property.type) { + return true + } + } + } + return false + } + + private func containsClosureType(in parameters: [Parameter]) -> Bool { + parameters.contains { containsClosureType(in: $0.type) } + } + + private func containsClosureType(in type: BridgeType) -> Bool { + switch type { + case .closure: + return true + case .optional(let wrapped): + return containsClosureType(in: wrapped) + default: + return false + } + } + private func generateAddImports() -> CodeFragmentPrinter { let printer = CodeFragmentPrinter() printer.write("return {") @@ -384,7 +428,7 @@ struct BridgeJSLink { printer.indent { printer.write(lines: [ - "const bjs = {};", + "bjs = {};", "importObject[\"bjs\"] = bjs;", "const imports = options.getImports(importsContext);", ]) @@ -644,11 +688,231 @@ struct BridgeJSLink { printer.write("return value;") } printer.write("}") + printer.write("bjs[\"swift_js_get_optional_heap_object_pointer\"] = function() {") + printer.indent { + printer.write("const pointer = \(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject);") + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject) = undefined;") + printer.write("return pointer || 0;") + } + printer.write("}") + + var closureSignatures: Set = [] + for skeleton in exportedSkeletons { + collectClosureSignatures(from: skeleton, into: &closureSignatures) + } + + var classToModule: [String: String] = [:] + for skeleton in exportedSkeletons { + for klass in skeleton.classes { + classToModule[klass.name] = skeleton.moduleName + } + } + + for signature in closureSignatures.sorted(by: { $0.mangleName < $1.mangleName }) { + let invokeFuncName = "invoke_js_callback_\(signature.mangleName.lowercased())" + printer.write( + lines: generateInvokeFunction( + signature: signature, + functionName: invokeFuncName, + classToModule: classToModule + ) + ) + + let lowerFuncName = "lower_closure_\(signature.mangleName.lowercased())" + printer.write( + lines: generateLowerClosureFunction( + signature: signature, + functionName: lowerFuncName + ) + ) + } + + if !closureSignatures.isEmpty { + printer.nextLine() + printer.write("bjs[\"release_js_callback\"] = function(id) {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(id);") + } + printer.write("};") + + printer.nextLine() + printer.write("bjs[\"release_swift_closure\"] = function(boxPtr) {") + printer.indent { + printer.write( + "\(JSGlueVariableScope.reservedInstance).exports._release_swift_closure(boxPtr);" + ) + } + printer.write("};") + } } } + return printer } + private func collectClosureSignatures(from skeleton: ExportedSkeleton, into signatures: inout Set) + { + for function in skeleton.functions { + collectClosureSignatures(from: function.parameters, into: &signatures) + collectClosureSignatures(from: function.returnType, into: &signatures) + } + for klass in skeleton.classes { + if let constructor = klass.constructor { + collectClosureSignatures(from: constructor.parameters, into: &signatures) + } + for method in klass.methods { + collectClosureSignatures(from: method.parameters, into: &signatures) + collectClosureSignatures(from: method.returnType, into: &signatures) + } + for property in klass.properties { + collectClosureSignatures(from: property.type, into: &signatures) + } + } + } + + private func collectClosureSignatures(from parameters: [Parameter], into signatures: inout Set) { + for param in parameters { + collectClosureSignatures(from: param.type, into: &signatures) + } + } + + private func collectClosureSignatures(from type: BridgeType, into signatures: inout Set) { + switch type { + case .closure(let signature): + signatures.insert(signature) + for paramType in signature.parameters { + collectClosureSignatures(from: paramType, into: &signatures) + } + collectClosureSignatures(from: signature.returnType, into: &signatures) + case .optional(let wrapped): + collectClosureSignatures(from: wrapped, into: &signatures) + default: + break + } + } + + private func generateInvokeFunction( + signature: ClosureSignature, + functionName: String, + classToModule: [String: String] + ) -> [String] { + let printer = CodeFragmentPrinter() + let scope = JSGlueVariableScope() + let cleanupCode = CodeFragmentPrinter() + + // Build parameter list for invoke function + var invokeParams: [String] = ["callbackId"] + for (index, paramType) in signature.parameters.enumerated() { + if case .optional = paramType { + invokeParams.append("param\(index)IsSome") + invokeParams.append("param\(index)Value") + } else { + invokeParams.append("param\(index)Id") + } + } + + printer.nextLine() + printer.write("bjs[\"\(functionName)\"] = function(\(invokeParams.joined(separator: ", "))) {") + printer.indent { + printer.write("try {") + printer.indent { + printer.write("const callback = \(JSGlueVariableScope.reservedSwift).memory.getObject(callbackId);") + + for (index, paramType) in signature.parameters.enumerated() { + let fragment = try! IntrinsicJSFragment.closureLiftParameter(type: paramType) + let args: [String] + if case .optional = paramType { + args = ["param\(index)IsSome", "param\(index)Value", "param\(index)"] + } else { + args = ["param\(index)Id", "param\(index)"] + } + _ = fragment.printCode(args, scope, printer, cleanupCode) + } + + let callbackParams = signature.parameters.indices.map { "param\($0)" }.joined(separator: ", ") + printer.write("const result = callback(\(callbackParams));") + + // Type check if needed (for example, formatName requires string return) + switch signature.returnType { + case .string: + printer.write("if (typeof result !== \"string\") {") + printer.indent { + printer.write("throw new TypeError(\"Callback must return a string\");") + } + printer.write("}") + default: + break + } + + let returnFragment = try! IntrinsicJSFragment.closureLowerReturn(type: signature.returnType) + _ = returnFragment.printCode(["result"], scope, printer, cleanupCode) + } + printer.write("} catch (error) {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedSetException)?.(error);") + let errorFragment = IntrinsicJSFragment.closureErrorReturn(type: signature.returnType) + _ = errorFragment.printCode([], scope, printer, cleanupCode) + } + printer.write("}") + } + printer.write("};") + + return printer.lines + } + + /// Generates a lower_closure_* function that wraps a Swift closure for JavaScript + private func generateLowerClosureFunction( + signature: ClosureSignature, + functionName: String + ) -> [String] { + let printer = CodeFragmentPrinter() + let scope = JSGlueVariableScope() + let cleanupCode = CodeFragmentPrinter() + + printer.nextLine() + printer.write("bjs[\"\(functionName)\"] = function(closurePtr) {") + printer.indent { + printer.write( + "return function(\(signature.parameters.indices.map { "param\($0)" }.joined(separator: ", "))) {" + ) + printer.indent { + printer.write("try {") + printer.indent { + var invokeArgs: [String] = ["closurePtr"] + + for (index, paramType) in signature.parameters.enumerated() { + let paramName = "param\(index)" + let fragment = try! IntrinsicJSFragment.lowerParameter(type: paramType) + let lowered = fragment.printCode([paramName], scope, printer, cleanupCode) + invokeArgs.append(contentsOf: lowered) + } + + // Call the Swift invoke function + let invokeCall = + "\(JSGlueVariableScope.reservedInstance).exports.invoke_swift_closure_\(signature.mangleName.lowercased())(\(invokeArgs.joined(separator: ", ")))" + + let returnFragment = try! IntrinsicJSFragment.closureLiftReturn(type: signature.returnType) + _ = returnFragment.printCode([invokeCall], scope, printer, cleanupCode) + } + printer.write("} catch (error) {") + printer.indent { + printer.write("\(JSGlueVariableScope.reservedSetException)?.(error);") + switch signature.returnType { + case .void: + printer.write("return;") + default: + printer.write("throw error;") + } + } + printer.write("}") + } + printer.write("};") + } + printer.write("};") + + return printer.lines + } + private func generateTypeScript(data: LinkData) -> String { let header = """ // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, @@ -988,36 +1252,29 @@ struct BridgeJSLink { } /// Generates JavaScript code for assigning namespaced items to globalThis - private func generateNamespacePropertyAssignments(data: LinkData, hasAnyNamespacedItems: Bool) -> [String] { + private func generateNamespacePropertyAssignments( + data: LinkData, + hasAnyNamespacedItems: Bool + ) -> [String] { let printer = CodeFragmentPrinter() - printer.write(lines: data.enumStaticAssignments) - + printer.write("const exports = {") + printer.indent() + printer.write(lines: data.exportsLines.map { "\($0)" }) + printer.unindent() + printer.write("};") + printer.write("_exports = exports;") if hasAnyNamespacedItems { - printer.write("const exports = {") - printer.indent() - printer.write(lines: data.exportsLines.map { "\($0)" }) - printer.unindent() - printer.write("};") - data.namespacedClasses.forEach { klass in let namespacePath: String = klass.namespace?.joined(separator: ".") ?? "" printer.write("globalThis.\(namespacePath).\(klass.name) = exports.\(klass.name);") } - data.namespacedFunctions.forEach { function in let namespacePath: String = function.namespace?.joined(separator: ".") ?? "" printer.write("globalThis.\(namespacePath).\(function.name) = exports.\(function.name);") } - - printer.write("return exports;") - } else { - printer.write("return {") - printer.indent() - printer.write(lines: data.exportsLines.map { "\($0)" }) - printer.unindent() - printer.write("};") } + printer.write("return exports;") return printer.lines } @@ -2017,41 +2274,20 @@ extension BridgeJSLink { } func callPropertyGetter(name: String, returnType: BridgeType) throws -> String? { - if context == .protocolExport, case .optional(let wrappedType) = returnType { - let usesSideChannel: Bool - switch wrappedType { - case .string, .int, .float, .double, .jsObject, .swiftProtocol: - usesSideChannel = true - case .rawValueEnum: - usesSideChannel = true - case .bool, .caseEnum, .swiftHeapObject, .associatedValueEnum: - usesSideChannel = false - default: - usesSideChannel = false + if context == .exportSwift, returnType.usesSideChannelForOptionalReturn() { + guard case .optional(let wrappedType) = returnType else { + fatalError("usesSideChannelForOptionalReturn returned true for non-optional type") } - if usesSideChannel { - let resultVar = scope.variable("ret") - body.write( - "let \(resultVar) = \(JSGlueVariableScope.reservedSwift).memory.getObject(self).\(name);" - ) + let resultVar = scope.variable("ret") + body.write( + "let \(resultVar) = \(JSGlueVariableScope.reservedSwift).memory.getObject(self).\(name);" + ) - switch wrappedType { - case .string, .rawValueEnum(_, .string): - body.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(resultVar);") - case .int, .rawValueEnum(_, .int): - body.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(resultVar);") - case .float, .rawValueEnum(_, .float): - body.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = \(resultVar);") - case .double, .rawValueEnum(_, .double): - body.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = \(resultVar);") - case .jsObject, .swiftProtocol: - body.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(resultVar);") - default: - break - } - return nil // Side-channel types return nil (no direct return value) - } + let fragment = try IntrinsicJSFragment.protocolPropertyOptionalToSideChannel(wrappedType: wrappedType) + _ = fragment.printCode([resultVar], scope, body, cleanupCode) + + return nil // Side-channel types return nil (no direct return value) } return try call( @@ -2539,7 +2775,7 @@ extension BridgeJSLink { className: `protocol`.name ) - let getterThunkBuilder = ImportedThunkBuilder(context: .protocolExport) + let getterThunkBuilder = ImportedThunkBuilder(context: .exportSwift) getterThunkBuilder.liftSelf() let returnExpr = try getterThunkBuilder.callPropertyGetter(name: property.name, returnType: property.type) let getterLines = getterThunkBuilder.renderFunction( @@ -2557,7 +2793,7 @@ extension BridgeJSLink { operation: "set", className: `protocol`.name ) - let setterThunkBuilder = ImportedThunkBuilder(context: .protocolExport) + let setterThunkBuilder = ImportedThunkBuilder(context: .exportSwift) setterThunkBuilder.liftSelf() try setterThunkBuilder.liftParameter( param: Parameter(label: nil, name: "value", type: property.type) @@ -2577,7 +2813,7 @@ extension BridgeJSLink { protocol: ExportedProtocol, method: ExportedFunction ) throws { - let thunkBuilder = ImportedThunkBuilder(context: .protocolExport) + let thunkBuilder = ImportedThunkBuilder(context: .exportSwift) thunkBuilder.liftSelf() for param in method.parameters { try thunkBuilder.liftParameter(param: param) @@ -2627,6 +2863,11 @@ extension BridgeType { return name case .swiftProtocol(let name): return name + case .closure(let signature): + let paramTypes = signature.parameters.enumerated().map { index, param in + "arg\(index): \(param.tsType)" + }.joined(separator: ", ") + return "(\(paramTypes)) => \(signature.returnType.tsType)" } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 9cdf9d72..6ba378de 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -411,7 +411,10 @@ struct IntrinsicJSFragment: Sendable { ) } - static func optionalLiftReturn(wrappedType: BridgeType) -> IntrinsicJSFragment { + static func optionalLiftReturn( + wrappedType: BridgeType, + context: BridgeContext = .exportSwift + ) -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: [], printCode: { arguments, scope, printer, cleanupCode in @@ -441,8 +444,12 @@ struct IntrinsicJSFragment: Sendable { "const \(pointerVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject);" ) printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject) = undefined;") + let constructExpr = + context == .exportSwift + ? "\(className).__construct(\(pointerVar))" + : "_exports['\(className)'].__construct(\(pointerVar))" printer.write( - "const \(resultVar) = \(pointerVar) === null ? null : \(className).__construct(\(pointerVar));" + "const \(resultVar) = \(pointerVar) === null ? null : \(constructExpr);" ) case .caseEnum: printer.write("const \(resultVar) = \(JSGlueVariableScope.reservedStorageToReturnOptionalInt);") @@ -498,7 +505,7 @@ struct IntrinsicJSFragment: Sendable { static func optionalLowerReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { switch wrappedType { - case .void, .optional, .namespaceEnum: + case .void, .optional, .namespaceEnum, .closure: throw BridgeJSLinkError(message: "Unsupported optional wrapped type for protocol export: \(wrappedType)") default: break } @@ -618,6 +625,617 @@ struct IntrinsicJSFragment: Sendable { ) } + // MARK: - Protocol Support + + static func protocolPropertyOptionalToSideChannel(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + switch wrappedType { + case .string, .int, .float, .double, .jsObject, .swiftProtocol: + break + case .rawValueEnum(_, let rawType): + switch rawType { + case .string, .int, .float, .double: + break + default: + throw BridgeJSLinkError( + message: "Unsupported raw value enum type for protocol property side channel: \(rawType)" + ) + } + default: + throw BridgeJSLinkError( + message: "Type \(wrappedType) does not use side channel for protocol property returns" + ) + } + + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanupCode in + let value = arguments[0] + + switch wrappedType { + case .string, .rawValueEnum(_, .string): + printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);") + case .int, .rawValueEnum(_, .int): + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(value);") + case .float, .rawValueEnum(_, .float): + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = \(value);") + case .double, .rawValueEnum(_, .double): + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = \(value);") + case .jsObject, .swiftProtocol: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(value);") + default: + fatalError("Unsupported type in protocolPropertyOptionalToSideChannel: \(wrappedType)") + } + + return [] + } + ) + } + + // MARK: - Closure Support + + /// Lifts a WASM parameter to JS for passing to a JS callback (invoke_js_callback_*) + static func closureLiftParameter(type: BridgeType) throws -> IntrinsicJSFragment { + switch type { + case .int, .float, .double, .caseEnum: + return IntrinsicJSFragment( + parameters: ["value", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("let \(arguments[1]) = \(arguments[0]);") + return [] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: ["value", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = boolLiftParameter + let lifted = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("let \(arguments[1]) = \(lifted[0]);") + return [] + } + ) + case .string: + return IntrinsicJSFragment( + parameters: ["objectId", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = stringLiftParameter + let lifted = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("let \(arguments[1]) = String(\(lifted[0]));") + return [] + } + ) + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + return IntrinsicJSFragment( + parameters: ["objectId", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = stringLiftParameter + let lifted = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("let \(arguments[1]) = String(\(lifted[0]));") + return [] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: ["value", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = boolLiftParameter + let lifted = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("let \(arguments[1]) = \(lifted[0]);") + return [] + } + ) + default: + return IntrinsicJSFragment( + parameters: ["value", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("let \(arguments[1]) = \(arguments[0]);") + return [] + } + ) + } + case .jsObject: + return IntrinsicJSFragment( + parameters: ["objectId", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let objectId = arguments[0] + let targetVar = arguments[1] + printer.write( + "let \(targetVar) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(objectId));" + ) + printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(objectId));") + return [] + } + ) + case .swiftHeapObject(let name): + return IntrinsicJSFragment( + parameters: ["pointer", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let pointer = arguments[0] + let targetVar = arguments[1] + printer.write("let \(targetVar) = _exports['\(name)'].__construct(\(pointer));") + return [] + } + ) + case .associatedValueEnum(let fullName): + return IntrinsicJSFragment( + parameters: ["caseId", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let caseId = arguments[0] + let targetVar = arguments[1] + let base = fullName.components(separatedBy: ".").last ?? fullName + printer.write( + "let \(targetVar) = enumHelpers.\(base).raise(\(caseId), \(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s));" + ) + return [] + } + ) + case .optional(let wrappedType): + return try closureOptionalLiftParameter(wrappedType: wrappedType) + default: + throw BridgeJSLinkError(message: "Unsupported closure parameter type for lifting: \(type)") + } + } + + /// Handles optional parameter lifting for closure invocation + private static func closureOptionalLiftParameter(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + switch wrappedType { + case .string, .rawValueEnum, .int, .bool, .double, .float, .jsObject, .swiftHeapObject, .caseEnum, + .associatedValueEnum: + break + default: + throw BridgeJSLinkError( + message: "Unsupported optional wrapped type in closure parameter lifting: \(wrappedType)" + ) + } + + return IntrinsicJSFragment( + parameters: ["isSome", "value", "targetVar"], + printCode: { arguments, scope, printer, cleanupCode in + let isSome = arguments[0] + let value = arguments[1] + let targetVar = arguments[2] + + printer.write("let \(targetVar);") + printer.write("if (\(isSome)) {") + printer.indent() + switch wrappedType { + case .string, .rawValueEnum(_, .string): + let objectLabel = scope.variable("\(targetVar)Object") + printer.write( + "const \(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(value));" + ) + printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(value));") + printer.write("\(targetVar) = String(\(objectLabel));") + case .int: + printer.write("\(targetVar) = \(value) | 0;") + case .bool: + printer.write("\(targetVar) = \(value) !== 0;") + case .double: + printer.write("\(targetVar) = \(value);") + case .float: + printer.write("\(targetVar) = Math.fround(\(value));") + case .jsObject: + printer.write("\(targetVar) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(value));") + printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(value));") + case .swiftHeapObject(let typeName): + printer.write("\(targetVar) = _exports['\(typeName)'].__construct(\(value));") + case .caseEnum: + printer.write("\(targetVar) = \(value);") + case .rawValueEnum(_, let rawType): + switch rawType { + case .bool: + printer.write("\(targetVar) = \(value) !== 0;") + default: + printer.write("\(targetVar) = \(value);") + } + case .associatedValueEnum(let fullName): + let base = fullName.components(separatedBy: ".").last ?? fullName + printer.write( + "\(targetVar) = enumHelpers.\(base).raise(\(value), \(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s));" + ) + default: + fatalError("Unsupported optional wrapped type in closure parameter lifting: \(wrappedType)") + } + printer.unindent() + printer.write("} else {") + printer.indent() + printer.write("\(targetVar) = null;") + printer.unindent() + printer.write("}") + + return [] + } + ) + } + + /// Lowers a JS return value to WASM for returning from callback (invoke_js_callback_*) + static func closureLowerReturn(type: BridgeType) throws -> IntrinsicJSFragment { + switch type { + case .void: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { _, _, printer, _ in + printer.write("return;") + return [] + } + ) + case .int, .caseEnum: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("return \(arguments[0]) | 0;") + return [] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = boolLowerReturn + let lowered = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lowered[0]);") + return [] + } + ) + case .float: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("return Math.fround(\(arguments[0]));") + return [] + } + ) + case .double: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("return \(arguments[0]);") + return [] + } + ) + case .string: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = stringLowerReturn + let lowered = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lowered[0]);") + return [] + } + ) + case .jsObject: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = jsObjectLowerReturn + let lowered = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lowered[0]);") + return [] + } + ) + case .swiftHeapObject: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = swiftHeapObjectLowerReturn + let lowered = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lowered[0]);") + return [] + } + ) + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = stringLowerReturn + let lowered = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lowered[0]);") + return [] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = boolLowerReturn + let lowered = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lowered[0]);") + return [] + } + ) + default: + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("return \(arguments[0]) | 0;") + return [] + } + ) + } + case .associatedValueEnum(let fullName): + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let result = arguments[0] + let base = fullName.components(separatedBy: ".").last ?? fullName + let caseIdVar = scope.variable("caseId") + let cleanupVar = scope.variable("cleanup") + printer.write( + "const { caseId: \(caseIdVar), cleanup: \(cleanupVar) } = enumHelpers.\(base).lower(\(result));" + ) + cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") + printer.write("return \(caseIdVar);") + return [] + } + ) + case .optional(let wrappedType): + return try closureOptionalLowerReturn(wrappedType: wrappedType) + default: + throw BridgeJSLinkError(message: "Unsupported closure return type for lowering: \(type)") + } + } + + /// Handles optional return lowering for closure invocation + private static func closureOptionalLowerReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["result"], + printCode: { arguments, scope, printer, cleanupCode in + let result = arguments[0] + + switch wrappedType { + case .swiftHeapObject: + printer.write("return \(result) ? \(result).pointer : 0;") + case .string: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(result);") + printer.write("return;") + case .int: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(result);") + printer.write("return;") + case .bool: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalBool) = \(result);") + printer.write("return;") + case .float: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = \(result);") + printer.write("return;") + case .double: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = \(result);") + printer.write("return;") + case .caseEnum: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(result);") + printer.write("return;") + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(result);") + printer.write("return;") + case .bool: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalBool) = \(result);") + printer.write("return;") + case .float: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = \(result);") + printer.write("return;") + case .double: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = \(result);") + printer.write("return;") + default: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(result);") + printer.write("return;") + } + case .associatedValueEnum(let fullName): + let base = fullName.components(separatedBy: ".").last ?? fullName + let caseIdVar = scope.variable("caseId") + let cleanupVar = scope.variable("cleanup") + printer.write("if (\(result)) {") + printer.indent() + printer.write( + "const { caseId: \(caseIdVar), cleanup: \(cleanupVar) } = enumHelpers.\(base).lower(\(result));" + ) + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(caseIdVar);") + cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") + printer.unindent() + printer.write("} else {") + printer.indent() + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = null;") + printer.unindent() + printer.write("}") + printer.write("return;") + default: + fatalError("Unsupported optional wrapped type in closure return lowering: \(wrappedType)") + } + + return [] + } + ) + } + + /// Lifts a WASM return value to JS from Swift closure (lower_closure_*) + static func closureLiftReturn(type: BridgeType) throws -> IntrinsicJSFragment { + switch type { + case .void: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("\(arguments[0]);") + printer.write("return;") + return [] + } + ) + case .int, .caseEnum: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("return \(arguments[0]) | 0;") + return [] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = boolLiftReturn + let lifted = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lifted[0]);") + return [] + } + ) + case .float, .double: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("return \(arguments[0]);") + return [] + } + ) + case .string: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("const resultLen = \(arguments[0]);") + let baseFragment = stringLiftReturn + let lifted = baseFragment.printCode([], scope, printer, cleanupCode) + printer.write("return \(lifted[0]);") + return [] + } + ) + case .jsObject: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("const resultId = \(arguments[0]);") + let baseFragment = jsObjectLiftReturn + let lifted = baseFragment.printCode(["resultId"], scope, printer, cleanupCode) + printer.write("return \(lifted[0]);") + return [] + } + ) + case .swiftHeapObject(let className): + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("const resultPtr = \(arguments[0]);") + printer.write("return _exports['\(className)'].__construct(resultPtr);") + return [] + } + ) + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("const resultLen = \(arguments[0]);") + let baseFragment = stringLiftReturn + let lifted = baseFragment.printCode([], scope, printer, cleanupCode) + printer.write("return \(lifted[0]);") + return [] + } + ) + case .bool: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + let baseFragment = boolLiftReturn + let lifted = baseFragment.printCode([arguments[0]], scope, printer, cleanupCode) + printer.write("return \(lifted[0]);") + return [] + } + ) + default: + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("return \(arguments[0]) | 0;") + return [] + } + ) + } + case .associatedValueEnum(let fullName): + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + printer.write("\(arguments[0]);") + let base = fullName.components(separatedBy: ".").last ?? fullName + let resultVar = scope.variable("result") + printer.write( + "const \(resultVar) = enumHelpers.\(base).raise(\(JSGlueVariableScope.reservedTmpRetTag), \(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s));" + ) + printer.write("return \(resultVar);") + return [] + } + ) + case .optional(let wrappedType): + return try closureOptionalLiftReturn(wrappedType: wrappedType) + default: + throw BridgeJSLinkError(message: "Unsupported closure return type for lifting: \(type)") + } + } + + /// Handles optional return lifting for Swift closure returns + private static func closureOptionalLiftReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["invokeCall"], + printCode: { arguments, scope, printer, cleanupCode in + let invokeCall = arguments[0] + printer.write("\(invokeCall);") + let baseFragment = optionalLiftReturn(wrappedType: wrappedType, context: .importTS) + let lifted = baseFragment.printCode([], scope, printer, cleanupCode) + if !lifted.isEmpty { + printer.write("return \(lifted[0]);") + } + return [] + } + ) + } + + /// Provides appropriate default values for error cases in closure invocation + static func closureErrorReturn(type: BridgeType) -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: [], + printCode: { arguments, scope, printer, cleanupCode in + switch type { + case .void: + printer.write("return;") + case .string: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnBytes) = new Uint8Array(0);") + printer.write("return 0;") + case .int, .bool, .caseEnum: + printer.write("return 0;") + case .float, .double: + printer.write("return 0.0;") + case .jsObject, .swiftHeapObject: + printer.write("return 0;") + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + printer.write("\(JSGlueVariableScope.reservedStorageToReturnBytes) = new Uint8Array(0);") + printer.write("return 0;") + case .bool, .int, .int32, .int64, .uint, .uint32, .uint64: + printer.write("return 0;") + case .float, .double: + printer.write("return 0.0;") + } + case .associatedValueEnum: + printer.write("return;") + case .optional(let wrappedType): + switch wrappedType { + case .swiftHeapObject: + printer.write("return 0;") + default: + printer.write("return;") + } + default: + printer.write("return 0;") + } + + return [] + } + ) + } + // MARK: - ExportSwift /// Returns a fragment that lowers a JS value to Wasm core values for parameters @@ -641,6 +1259,18 @@ struct IntrinsicJSFragment: Sendable { case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName return .associatedEnumLowerParameter(enumBase: base) + case .closure: + return IntrinsicJSFragment( + parameters: ["closure"], + printCode: { arguments, scope, printer, cleanupCode in + let closure = arguments[0] + let callbackIdVar = scope.variable("callbackId") + printer.write( + "const \(callbackIdVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(closure));" + ) + return [callbackIdVar] + } + ) case .namespaceEnum(let string): throw BridgeJSLinkError(message: "Namespace enums are not supported to be passed as parameters: \(string)") } @@ -667,6 +1297,17 @@ struct IntrinsicJSFragment: Sendable { case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName return .associatedEnumLiftReturn(enumBase: base) + case .closure(let signature): + return IntrinsicJSFragment( + parameters: ["closurePtr"], + printCode: { arguments, scope, printer, cleanupCode in + let closurePtr = arguments[0] + let lowerFuncName = "lower_closure_\(signature.mangleName.lowercased())" + let resultVar = scope.variable("closure") + printer.write("const \(resultVar) = bjs[\"\(lowerFuncName)\"](\(closurePtr));") + return [resultVar] + } + ) case .namespaceEnum(let string): throw BridgeJSLinkError( message: "Namespace enums are not supported to be returned from functions: \(string)" @@ -689,7 +1330,7 @@ struct IntrinsicJSFragment: Sendable { throw BridgeJSLinkError( message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)" ) - case .protocolExport: + case .exportSwift: return .swiftHeapObjectLiftParameter(name) } case .swiftProtocol: return .jsObjectLiftParameter @@ -703,7 +1344,7 @@ struct IntrinsicJSFragment: Sendable { throw BridgeJSLinkError( message: "Optional types are not supported for imported JS functions: \(wrappedType)" ) - case .protocolExport: + case .exportSwift: return try .optionalLiftParameter(wrappedType: wrappedType) } case .caseEnum: return .identity @@ -720,7 +1361,7 @@ struct IntrinsicJSFragment: Sendable { message: "Associated value enums are not supported to be passed as parameters to imported JS functions: \(fullName)" ) - case .protocolExport: + case .exportSwift: let base = fullName.components(separatedBy: ".").last ?? fullName return IntrinsicJSFragment( parameters: ["caseId"], @@ -734,6 +1375,8 @@ struct IntrinsicJSFragment: Sendable { } ) } + case .closure: + throw BridgeJSLinkError(message: "Closure parameters not yet implemented for imported JS functions") case .namespaceEnum(let string): throw BridgeJSLinkError( message: @@ -755,7 +1398,7 @@ struct IntrinsicJSFragment: Sendable { throw BridgeJSLinkError( message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)" ) - case .protocolExport: + case .exportSwift: return .swiftHeapObjectLowerReturn } case .swiftProtocol: return .jsObjectLowerReturn @@ -766,8 +1409,7 @@ struct IntrinsicJSFragment: Sendable { throw BridgeJSLinkError( message: "Optional types are not supported for imported JS functions: \(wrappedType)" ) - case .protocolExport: - // Protocol exports support Optional - use side channel approach for return values + case .exportSwift: return try .optionalLowerReturn(wrappedType: wrappedType) } case .caseEnum: return .identity @@ -784,9 +1426,11 @@ struct IntrinsicJSFragment: Sendable { message: "Associated value enums are not supported to be returned from imported JS functions: \(fullName)" ) - case .protocolExport: + case .exportSwift: return associatedValueLowerReturn(fullName: fullName) } + case .closure: + throw BridgeJSLinkError(message: "Closure return values not yet implemented for imported JS functions") case .namespaceEnum(let string): throw BridgeJSLinkError( message: "Namespace enums are not supported to be returned from imported JS functions: \(string)" diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index c9a60275..325ace7b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -70,10 +70,32 @@ public struct ABINameGenerator { /// Context for bridge operations that determines which types are valid public enum BridgeContext: Sendable { case importTS - case protocolExport + case exportSwift } -public enum BridgeType: Codable, Equatable, Sendable { +public struct ClosureSignature: Codable, Equatable, Hashable, Sendable { + public let parameters: [BridgeType] + public let returnType: BridgeType + public let isAsync: Bool + public let isThrows: Bool + public let mangleName: String + + public init(parameters: [BridgeType], returnType: BridgeType, isAsync: Bool = false, isThrows: Bool = false) { + self.parameters = parameters + self.returnType = returnType + self.isAsync = isAsync + self.isThrows = isThrows + + let paramPart = + parameters.isEmpty + ? "Void" + : parameters.map { $0.mangleTypeName }.joined(separator: "_") + let returnPart = returnType.mangleTypeName + self.mangleName = "\(paramPart)_To_\(returnPart)" + } +} + +public enum BridgeType: Codable, Equatable, Hashable, Sendable { case int, float, double, string, bool, jsObject(String?), swiftHeapObject(String), void indirect case optional(BridgeType) case caseEnum(String) @@ -81,6 +103,7 @@ public enum BridgeType: Codable, Equatable, Sendable { case associatedValueEnum(String) case namespaceEnum(String) case swiftProtocol(String) + indirect case closure(ClosureSignature) } public enum WasmCoreType: String, Codable, Sendable { @@ -567,6 +590,9 @@ extension BridgeType { case .swiftProtocol: // Protocols pass JSObject IDs as Int32 return .i32 + case .closure: + // Closures pass callback ID as Int32 + return .i32 } } @@ -575,4 +601,56 @@ extension BridgeType { if case .optional = self { return true } return false } + + /// Generates a mangled name for use in closure type names + /// Examples: "String", "Int", "MyClass", "Bool" + public var mangleTypeName: String { + switch self { + case .int: return "Int" + case .float: return "Float" + case .double: return "Double" + case .string: return "String" + case .bool: return "Bool" + case .void: return "Void" + case .jsObject(let name): + return name ?? "JSObject" + case .swiftHeapObject(let name): + return name + case .optional(let wrapped): + return "Optional\(wrapped.mangleTypeName)" + case .caseEnum(let name), + .rawValueEnum(let name, _), + .associatedValueEnum(let name), + .namespaceEnum(let name): + return name + case .swiftProtocol(let name): + return name + case .closure(let signature): + return "Closure_\(signature.mangleName)" + } + } + + /// Determines if an optional type requires side-channel communication for protocol property returns + /// + /// Side channels are needed when the wrapped type cannot be directly returned via WASM, + /// or when we need to distinguish null from absent value for certain primitives. + public func usesSideChannelForOptionalReturn() -> Bool { + guard case .optional(let wrappedType) = self else { return false } + + switch wrappedType { + case .string, .int, .float, .double, .jsObject, .swiftProtocol: + return true + case .rawValueEnum(_, let rawType): + switch rawType { + case .string, .int, .float, .double: + return true + default: + return false + } + case .bool, .caseEnum, .swiftHeapObject, .associatedValueEnum: + return false + default: + return false + } + } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/SwiftClosure.swift new file mode 100644 index 00000000..129f53b5 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/SwiftClosure.swift @@ -0,0 +1,75 @@ +import JavaScriptKit + +@JS public class Person { + public let name: String + + @JS public init(name: String) { + self.name = name + } +} + +@JS class TestProcessor { + private var transform: (String) -> String + + @JS init(transform: @escaping (String) -> String) { + self.transform = transform + } + + @JS func getTransform() -> (String) -> String + + @JS func processWithCustom(_ text: String, customTransform: (String) -> String) -> String + + @JS func printTogether( + person: Person, + name: String, + ratio: Double, + customTransform: (Person?, String?, Double?) -> String + ) -> String + + @JS func roundtrip(_ personClosure: (Person) -> String) -> (Person) -> String + @JS func roundtripOptional(_ personClosure: (Person?) -> String) -> (Person?) -> String + + @JS func processDirection(_ callback: (Direction) -> String) -> String + @JS func processTheme(_ callback: (Theme) -> String) -> String + @JS func processHttpStatus(_ callback: (HttpStatus) -> Int) -> Int + @JS func processAPIResult(_ callback: (APIResult) -> String) -> String + + @JS func makeDirectionChecker() -> (Direction) -> Bool + @JS func makeThemeValidator() -> (Theme) -> Bool + @JS func makeStatusCodeExtractor() -> (HttpStatus) -> Int + @JS func makeAPIResultHandler() -> (APIResult) -> String + + @JS func processOptionalDirection(_ callback: (Direction?) -> String) -> String + @JS func processOptionalTheme(_ callback: (Theme?) -> String) -> String + @JS func processOptionalAPIResult(_ callback: (APIResult?) -> String) -> String + @JS func makeOptionalDirectionFormatter() -> (Direction?) -> String +} + +@JS enum Direction { + case north + case south + case east + case west +} + +@JS enum Theme: String { + case light = "light" + case dark = "dark" + case auto = "auto" +} + +@JS enum HttpStatus: Int { + case ok = 200 + case notFound = 404 + case serverError = 500 + case unknown = -1 +} + +@JS enum APIResult { + case success(String) + case failure(Int) + case flag(Bool) + case rate(Float) + case precise(Double) + case info +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js index c9485c39..22709366 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkArray"] = function bjs_checkArray(a) { try { @@ -207,8 +215,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js index a763e45f..372de6ec 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -185,7 +193,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { asyncReturnVoid: function bjs_asyncReturnVoid() { const ret = instance.exports.bjs_asyncReturnVoid(); const ret1 = swift.memory.getObject(ret); @@ -232,6 +240,8 @@ export async function createInstantiator(options, swift) { return ret1; }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js index b5537ddc..873c9d69 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_asyncReturnVoid"] = function bjs_asyncReturnVoid() { try { @@ -251,8 +259,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js index a2b07002..9f56215d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js @@ -32,13 +32,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -179,6 +182,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -340,7 +348,7 @@ export async function createInstantiator(options, swift) { } } } - return { + const exports = { DefaultGreeter, EmptyGreeter, ConstructorDefaults, @@ -422,6 +430,8 @@ export async function createInstantiator(options, swift) { }, Status: StatusValues, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js index b6518d71..658361df 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js @@ -510,13 +510,16 @@ export async function createInstantiator(options, swift) { let tmpParamF32s = []; let tmpParamF64s = []; const enumHelpers = {}; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -657,6 +660,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -826,6 +834,7 @@ export async function createInstantiator(options, swift) { NetworkingResult: NetworkingResultValues, APIOptionalResult: APIOptionalResultValues, }; + _exports = exports; return exports; }, } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js index 04eda063..526e2fc9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js @@ -50,13 +50,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -197,6 +200,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -209,7 +217,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { setDirection: function bjs_setDirection(direction) { instance.exports.bjs_setDirection(direction); }, @@ -246,6 +254,8 @@ export async function createInstantiator(options, swift) { Status: StatusValues, PublicStatus: PublicStatusValues, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js index 9e645a67..a788abf5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js @@ -70,13 +70,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -217,6 +220,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -333,6 +341,7 @@ export async function createInstantiator(options, swift) { Port: PortValues, SupportedMethod: SupportedMethodValues, }; + _exports = exports; globalThis.Utils.Converter = exports.Converter; globalThis.Networking.API.HTTPServer = exports.HTTPServer; globalThis.Networking.APIV2.Internal.TestServer = exports.TestServer; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js index 15b03a4b..9daa221b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js @@ -101,13 +101,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -248,6 +251,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -260,7 +268,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { setTheme: function bjs_setTheme(theme) { const themeBytes = textEncoder.encode(theme); const themeId = swift.memory.retain(themeBytes); @@ -483,6 +491,8 @@ export async function createInstantiator(options, swift) { Precision: PrecisionValues, Ratio: RatioValues, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js index 51921ddc..6e546119 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_returnAnimatable"] = function bjs_returnAnimatable() { try { @@ -213,8 +221,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js index b6694c06..9336edc6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createArrayBuffer"] = function bjs_createArrayBuffer() { try { @@ -283,8 +291,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js index 3253d17d..380f1a72 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createDatabaseConnection"] = function bjs_createDatabaseConnection(config) { try { @@ -317,8 +325,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js index 89dd9023..395b97f1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -302,6 +310,7 @@ export async function createInstantiator(options, swift) { return ret; }, }; + _exports = exports; globalThis.__Swift.Foundation.Greeter = exports.Greeter; globalThis.Utils.Converters.Converter = exports.Converter; globalThis.__Swift.Foundation.UUID = exports.UUID; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js index 319556b9..f9c60e06 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -320,7 +328,7 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_OptionalPropertyHolder_optionalGreeter_set(this.pointer, +isSome, isSome ? value.pointer : 0); } } - return { + const exports = { Greeter, OptionalPropertyHolder, roundTripOptionalClass: function bjs_roundTripOptionalClass(value) { @@ -497,6 +505,8 @@ export async function createInstantiator(options, swift) { return optResult; }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js index 17e1a1e5..c8bd621d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -185,11 +193,13 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { check: function bjs_check(a, b, c, d) { instance.exports.bjs_check(a, b, c, d); }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js index e8d18b98..32f5e36f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_check"] = function bjs_check(a, b) { try { @@ -193,8 +201,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js index c7efcf0d..605a13ea 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -185,7 +193,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { checkInt: function bjs_checkInt() { const ret = instance.exports.bjs_checkInt(); return ret; @@ -203,6 +211,8 @@ export async function createInstantiator(options, swift) { return ret !== 0; }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js index 24fa28a0..62122a83 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkNumber"] = function bjs_checkNumber() { try { @@ -204,8 +212,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js index bc9748d8..e37af60c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -344,7 +352,7 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_PropertyHolder_observedProperty_set(this.pointer, value); } } - return { + const exports = { PropertyHolder, createPropertyHolder: function bjs_createPropertyHolder(intValue, floatValue, doubleValue, boolValue, stringValue, jsObject) { const stringValueBytes = textEncoder.encode(stringValue); @@ -360,6 +368,8 @@ export async function createInstantiator(options, swift) { return ret; }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js index 2740c7c2..58f32ea9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js @@ -91,13 +91,16 @@ export async function createInstantiator(options, swift) { let tmpParamF32s = []; let tmpParamF64s = []; const enumHelpers = {}; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -238,6 +241,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -653,7 +661,7 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_MyViewController_secondDelegate_set(this.pointer, +isSome, isSome ? swift.memory.retain(value) : 0); } } - return { + const exports = { Helper, MyViewController, Direction: DirectionValues, @@ -661,6 +669,8 @@ export async function createInstantiator(options, swift) { Result: ResultValues, Priority: PriorityValues, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js index 6fa84a4f..14f11469 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js @@ -78,13 +78,16 @@ export async function createInstantiator(options, swift) { let tmpParamF32s = []; let tmpParamF64s = []; const enumHelpers = {}; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -225,6 +228,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -324,6 +332,7 @@ export async function createInstantiator(options, swift) { } }, }; + _exports = exports; globalThis.Utils.String.uppercase = exports.uppercase; return exports; }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js index 29060b93..3577228e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js @@ -31,13 +31,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -178,6 +181,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -330,7 +338,7 @@ export async function createInstantiator(options, swift) { }, set: function(value) { instance.exports.bjs_PropertyNamespace_Nested_static_nestedDouble_set(value); } }); - return { + const exports = { PropertyClass, PropertyEnum: { ...PropertyEnumValues, @@ -364,6 +372,8 @@ export async function createInstantiator(options, swift) { } }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js index a9f4bcd7..a668639d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -185,7 +193,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { checkString: function bjs_checkString(a) { const aBytes = textEncoder.encode(a); const aId = swift.memory.retain(aBytes); @@ -202,6 +210,8 @@ export async function createInstantiator(options, swift) { return ret; }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js index 4f6e1dae..e13404bb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkString"] = function bjs_checkString(a) { try { @@ -204,8 +212,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js index 2d9a848f..f31ef140 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -185,7 +193,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { checkString: function bjs_checkString() { instance.exports.bjs_checkString(); const ret = tmpRetString; @@ -193,6 +201,8 @@ export async function createInstantiator(options, swift) { return ret; }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js index 80d4fcd9..ae86fd8f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkString"] = function bjs_checkString() { try { @@ -195,8 +203,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js index 395057d8..9a5eec43 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -269,7 +277,7 @@ export async function createInstantiator(options, swift) { } } - return { + const exports = { Greeter, PublicGreeter, PackageGreeter, @@ -277,6 +285,8 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_takeGreeter(greeter.pointer); }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.Export.d.ts new file mode 100644 index 00000000..942b1826 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.Export.d.ts @@ -0,0 +1,100 @@ +// 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 DirectionValues: { + readonly North: 0; + readonly South: 1; + readonly East: 2; + readonly West: 3; +}; +export type DirectionTag = typeof DirectionValues[keyof typeof DirectionValues]; + +export const ThemeValues: { + readonly Light: "light"; + readonly Dark: "dark"; + readonly Auto: "auto"; +}; +export type ThemeTag = typeof ThemeValues[keyof typeof ThemeValues]; + +export const HttpStatusValues: { + readonly Ok: 200; + readonly NotFound: 404; + readonly ServerError: 500; + readonly Unknown: -1; +}; +export type HttpStatusTag = typeof HttpStatusValues[keyof typeof HttpStatusValues]; + +export const APIResultValues: { + readonly Tag: { + readonly Success: 0; + readonly Failure: 1; + readonly Flag: 2; + readonly Rate: 3; + readonly Precise: 4; + readonly Info: 5; + }; +}; + +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 type DirectionObject = typeof DirectionValues; + +export type ThemeObject = typeof ThemeValues; + +export type HttpStatusObject = typeof HttpStatusValues; + +export type APIResultObject = typeof APIResultValues; + +/// 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 Person extends SwiftHeapObject { +} +export interface TestProcessor extends SwiftHeapObject { + getTransform(): (arg0: string) => string; + processWithCustom(text: string, customTransform: (arg0: string) => string): string; + printTogether(person: Person, name: string, ratio: number, customTransform: (arg0: Person | null, arg1: string | null, arg2: number | null) => string): string; + roundtrip(personClosure: (arg0: Person) => string): (arg0: Person) => string; + roundtripOptional(personClosure: (arg0: Person | null) => string): (arg0: Person | null) => string; + processDirection(callback: (arg0: DirectionTag) => string): string; + processTheme(callback: (arg0: ThemeTag) => string): string; + processHttpStatus(callback: (arg0: HttpStatusTag) => number): number; + processAPIResult(callback: (arg0: APIResultTag) => string): string; + makeDirectionChecker(): (arg0: DirectionTag) => boolean; + makeThemeValidator(): (arg0: ThemeTag) => boolean; + makeStatusCodeExtractor(): (arg0: HttpStatusTag) => number; + makeAPIResultHandler(): (arg0: APIResultTag) => string; + processOptionalDirection(callback: (arg0: DirectionTag | null) => string): string; + processOptionalTheme(callback: (arg0: ThemeTag | null) => string): string; + processOptionalAPIResult(callback: (arg0: APIResultTag | null) => string): string; + makeOptionalDirectionFormatter(): (arg0: DirectionTag | null) => string; +} +export type Exports = { + Person: { + new(name: string): Person; + } + TestProcessor: { + new(transform: (arg0: string) => string): TestProcessor; + } + Direction: DirectionObject + Theme: ThemeObject + HttpStatus: HttpStatusObject + APIResult: APIResultObject +} +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/SwiftClosure.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.Export.js new file mode 100644 index 00000000..4d0a3ab2 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.Export.js @@ -0,0 +1,942 @@ +// 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 DirectionValues = { + North: 0, + South: 1, + East: 2, + West: 3, +}; + +export const ThemeValues = { + Light: "light", + Dark: "dark", + Auto: "auto", +}; + +export const HttpStatusValues = { + Ok: 200, + NotFound: 404, + ServerError: 500, + Unknown: -1, +}; + +export const APIResultValues = { + Tag: { + Success: 0, + Failure: 1, + Flag: 2, + Rate: 3, + Precise: 4, + Info: 5, + }, +}; + +const __bjs_createAPIResultValuesHelpers = () => { + return (tmpParamInts, tmpParamF32s, tmpParamF64s, textEncoder, swift) => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case APIResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); + const cleanup = () => { + swift.memory.release(id); + }; + return { caseId: APIResultValues.Tag.Success, cleanup }; + } + case APIResultValues.Tag.Failure: { + tmpParamInts.push((value.param0 | 0)); + const cleanup = undefined; + return { caseId: APIResultValues.Tag.Failure, cleanup }; + } + case APIResultValues.Tag.Flag: { + tmpParamInts.push(value.param0 ? 1 : 0); + const cleanup = undefined; + return { caseId: APIResultValues.Tag.Flag, cleanup }; + } + case APIResultValues.Tag.Rate: { + tmpParamF32s.push(Math.fround(value.param0)); + const cleanup = undefined; + return { caseId: APIResultValues.Tag.Rate, cleanup }; + } + case APIResultValues.Tag.Precise: { + tmpParamF64s.push(value.param0); + const cleanup = undefined; + return { caseId: APIResultValues.Tag.Precise, cleanup }; + } + case APIResultValues.Tag.Info: { + const cleanup = undefined; + return { caseId: APIResultValues.Tag.Info, cleanup }; + } + default: throw new Error("Unknown APIResultValues tag: " + String(enumTag)); + } + }, + raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s) => { + const tag = tmpRetTag | 0; + switch (tag) { + case APIResultValues.Tag.Success: { + const string = tmpRetStrings.pop(); + return { tag: APIResultValues.Tag.Success, param0: string }; + } + case APIResultValues.Tag.Failure: { + const int = tmpRetInts.pop(); + return { tag: APIResultValues.Tag.Failure, param0: int }; + } + case APIResultValues.Tag.Flag: { + const bool = tmpRetInts.pop(); + return { tag: APIResultValues.Tag.Flag, param0: bool }; + } + case APIResultValues.Tag.Rate: { + const f32 = tmpRetF32s.pop(); + return { tag: APIResultValues.Tag.Rate, param0: f32 }; + } + case APIResultValues.Tag.Precise: { + const f64 = tmpRetF64s.pop(); + return { tag: APIResultValues.Tag.Precise, param0: f64 }; + } + case APIResultValues.Tag.Info: return { tag: APIResultValues.Tag.Info }; + default: throw new Error("Unknown APIResultValues tag returned from Swift: " + String(tag)); + } + } + }); +}; +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + 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 tmpRetTag; + let tmpRetStrings = []; + let tmpRetInts = []; + let tmpRetF32s = []; + let tmpRetF64s = []; + let tmpParamInts = []; + let tmpParamF32s = []; + let tmpParamF64s = []; + const enumHelpers = {}; + + 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) { + const bytes = new Uint8Array(memory.buffer, ptr, len); + tmpRetString = textDecoder.decode(bytes); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr); + 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)); + } + 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_tag"] = function(tag) { + tmpRetTag = tag; + } + bjs["swift_js_push_int"] = function(v) { + tmpRetInts.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + tmpRetF32s.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + tmpRetF64s.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const bytes = new Uint8Array(memory.buffer, ptr, len); + const value = textDecoder.decode(bytes); + tmpRetStrings.push(value); + } + bjs["swift_js_pop_param_int32"] = function() { + return tmpParamInts.pop(); + } + bjs["swift_js_pop_param_f32"] = function() { + return tmpParamF32s.pop(); + } + bjs["swift_js_pop_param_f64"] = function() { + return tmpParamF64s.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 { + const bytes = new Uint8Array(memory.buffer, ptr, len); + tmpRetString = textDecoder.decode(bytes); + } + } + 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["invoke_js_callback_apiresult_to_string"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + let param0 = enumHelpers.APIResult.raise(param0Id, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s); + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_apiresult_to_string"] = function(closurePtr) { + return function(param0) { + try { + const { caseId: param0CaseId, cleanup: param0Cleanup } = enumHelpers.APIResult.lower(param0); + const resultLen = instance.exports.invoke_swift_closure_apiresult_to_string(closurePtr, param0CaseId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_direction_to_bool"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + let param0 = param0Id; + const result = callback(param0); + return result ? 1 : 0; + } catch (error) { + setException?.(error); + return 0; + } + }; + + bjs["lower_closure_direction_to_bool"] = function(closurePtr) { + return function(param0) { + try { + return instance.exports.invoke_swift_closure_direction_to_bool(closurePtr, param0) !== 0; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_direction_to_string"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + let param0 = param0Id; + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_direction_to_string"] = function(closurePtr) { + return function(param0) { + try { + const resultLen = instance.exports.invoke_swift_closure_direction_to_string(closurePtr, param0); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_httpstatus_to_int"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + let param0 = param0Id; + const result = callback(param0); + return result | 0; + } catch (error) { + setException?.(error); + return 0; + } + }; + + bjs["lower_closure_httpstatus_to_int"] = function(closurePtr) { + return function(param0) { + try { + return instance.exports.invoke_swift_closure_httpstatus_to_int(closurePtr, param0) | 0; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_optionalapiresult_to_string"] = function(callbackId, param0IsSome, param0Value) { + try { + const callback = swift.memory.getObject(callbackId); + let param0; + if (param0IsSome) { + param0 = enumHelpers.APIResult.raise(param0Value, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s); + } else { + param0 = null; + } + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_optionalapiresult_to_string"] = function(closurePtr) { + return function(param0) { + try { + const isSome = param0 != null; + let param0CaseId, param0Cleanup; + if (isSome) { + const enumResult = enumHelpers.APIResult.lower(param0); + param0CaseId = enumResult.caseId; + param0Cleanup = enumResult.cleanup; + } + const resultLen = instance.exports.invoke_swift_closure_optionalapiresult_to_string(closurePtr, +isSome, isSome ? param0CaseId : 0); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_optionaldirection_to_string"] = function(callbackId, param0IsSome, param0Value) { + try { + const callback = swift.memory.getObject(callbackId); + let param0; + if (param0IsSome) { + param0 = param0Value; + } else { + param0 = null; + } + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_optionaldirection_to_string"] = function(closurePtr) { + return function(param0) { + try { + const isSome = param0 != null; + const resultLen = instance.exports.invoke_swift_closure_optionaldirection_to_string(closurePtr, +isSome, isSome ? param0 : 0); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_optionalperson_optionalstring_optionaldouble_to_string"] = function(callbackId, param0IsSome, param0Value, param1IsSome, param1Value, param2IsSome, param2Value) { + try { + const callback = swift.memory.getObject(callbackId); + let param0; + if (param0IsSome) { + param0 = _exports['Person'].__construct(param0Value); + } else { + param0 = null; + } + let param1; + if (param1IsSome) { + const param1Object = swift.memory.getObject(param1Value); + swift.memory.release(param1Value); + param1 = String(param1Object); + } else { + param1 = null; + } + let param2; + if (param2IsSome) { + param2 = param2Value; + } else { + param2 = null; + } + const result = callback(param0, param1, param2); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_optionalperson_optionalstring_optionaldouble_to_string"] = function(closurePtr) { + return function(param0, param1, param2) { + try { + const isSome = param0 != null; + const isSome1 = param1 != null; + let param1Id, param1Bytes; + if (isSome1) { + param1Bytes = textEncoder.encode(param1); + param1Id = swift.memory.retain(param1Bytes); + } + const isSome2 = param2 != null; + const resultLen = instance.exports.invoke_swift_closure_optionalperson_optionalstring_optionaldouble_to_string(closurePtr, +isSome, isSome ? param0.pointer : 0, +isSome1, isSome1 ? param1Id : 0, isSome1 ? param1Bytes.length : 0, +isSome2, isSome2 ? param2 : 0); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_optionalperson_to_string"] = function(callbackId, param0IsSome, param0Value) { + try { + const callback = swift.memory.getObject(callbackId); + let param0; + if (param0IsSome) { + param0 = _exports['Person'].__construct(param0Value); + } else { + param0 = null; + } + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_optionalperson_to_string"] = function(closurePtr) { + return function(param0) { + try { + const isSome = param0 != null; + const resultLen = instance.exports.invoke_swift_closure_optionalperson_to_string(closurePtr, +isSome, isSome ? param0.pointer : 0); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_optionaltheme_to_string"] = function(callbackId, param0IsSome, param0Value) { + try { + const callback = swift.memory.getObject(callbackId); + let param0; + if (param0IsSome) { + const param0Object = swift.memory.getObject(param0Value); + swift.memory.release(param0Value); + param0 = String(param0Object); + } else { + param0 = null; + } + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_optionaltheme_to_string"] = function(closurePtr) { + return function(param0) { + try { + const isSome = param0 != null; + let param0Id, param0Bytes; + if (isSome) { + param0Bytes = textEncoder.encode(param0); + param0Id = swift.memory.retain(param0Bytes); + } + const resultLen = instance.exports.invoke_swift_closure_optionaltheme_to_string(closurePtr, +isSome, isSome ? param0Id : 0, isSome ? param0Bytes.length : 0); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_person_to_string"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + let param0 = _exports['Person'].__construct(param0Id); + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_person_to_string"] = function(closurePtr) { + return function(param0) { + try { + const resultLen = instance.exports.invoke_swift_closure_person_to_string(closurePtr, param0.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_string_to_string"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + const param0IdObject = swift.memory.getObject(param0Id); + swift.memory.release(param0Id); + let param0 = String(param0IdObject); + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_string_to_string"] = function(closurePtr) { + return function(param0) { + try { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const resultLen = instance.exports.invoke_swift_closure_string_to_string(closurePtr, param0Id, param0Bytes.length); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_theme_to_bool"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + const param0IdObject = swift.memory.getObject(param0Id); + swift.memory.release(param0Id); + let param0 = String(param0IdObject); + const result = callback(param0); + return result ? 1 : 0; + } catch (error) { + setException?.(error); + return 0; + } + }; + + bjs["lower_closure_theme_to_bool"] = function(closurePtr) { + return function(param0) { + try { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + return instance.exports.invoke_swift_closure_theme_to_bool(closurePtr, param0Id, param0Bytes.length) !== 0; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["invoke_js_callback_theme_to_string"] = function(callbackId, param0Id) { + try { + const callback = swift.memory.getObject(callbackId); + const param0IdObject = swift.memory.getObject(param0Id); + swift.memory.release(param0Id); + let param0 = String(param0IdObject); + const result = callback(param0); + if (typeof result !== "string") { + throw new TypeError("Callback must return a string"); + } + tmpRetBytes = textEncoder.encode(result); + return tmpRetBytes.length; + } catch (error) { + setException?.(error); + tmpRetBytes = new Uint8Array(0); + return 0; + } + }; + + bjs["lower_closure_theme_to_string"] = function(closurePtr) { + return function(param0) { + try { + const param0Bytes = textEncoder.encode(param0); + const param0Id = swift.memory.retain(param0Bytes); + const resultLen = instance.exports.invoke_swift_closure_theme_to_string(closurePtr, param0Id, param0Bytes.length); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } catch (error) { + setException?.(error); + throw error; + } + }; + }; + + bjs["release_js_callback"] = function(id) { + swift.memory.release(id); + }; + + bjs["release_swift_closure"] = function(boxPtr) { + instance.exports._release_swift_closure(boxPtr); + }; + // Wrapper functions for module: TestModule + if (!importObject["TestModule"]) { + importObject["TestModule"] = {}; + } + importObject["TestModule"]["bjs_Person_wrap"] = function(pointer) { + const obj = Person.__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_TestProcessor_wrap"] = function(pointer) { + const obj = TestProcessor.__construct(pointer); + return swift.memory.retain(obj); + }; + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + const APIResultHelpers = __bjs_createAPIResultValuesHelpers()(tmpParamInts, tmpParamF32s, tmpParamF64s, textEncoder, swift); + enumHelpers.APIResult = APIResultHelpers; + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + /// 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); + obj.pointer = pointer; + obj.hasReleased = false; + obj.deinit = deinit; + obj.registry = new FinalizationRegistry((pointer) => { + deinit(pointer); + }); + obj.registry.register(this, obj.pointer); + return obj; + } + + release() { + this.registry.unregister(this); + this.deinit(this.pointer); + } + } + class Person extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Person_deinit, Person.prototype); + } + + constructor(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const ret = instance.exports.bjs_Person_init(nameId, nameBytes.length); + swift.memory.release(nameId); + return Person.__construct(ret); + } + } + class TestProcessor extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_TestProcessor_deinit, TestProcessor.prototype); + } + + constructor(transform) { + const callbackId = swift.memory.retain(transform); + const ret = instance.exports.bjs_TestProcessor_init(callbackId); + return TestProcessor.__construct(ret); + } + getTransform() { + const ret = instance.exports.bjs_TestProcessor_getTransform(this.pointer); + const closure = bjs["lower_closure_string_to_string"](ret); + return closure; + } + processWithCustom(text, customTransform) { + const textBytes = textEncoder.encode(text); + const textId = swift.memory.retain(textBytes); + const callbackId = swift.memory.retain(customTransform); + instance.exports.bjs_TestProcessor_processWithCustom(this.pointer, textId, textBytes.length, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + swift.memory.release(textId); + return ret; + } + printTogether(person, name, ratio, customTransform) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const callbackId = swift.memory.retain(customTransform); + instance.exports.bjs_TestProcessor_printTogether(this.pointer, person.pointer, nameId, nameBytes.length, ratio, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + swift.memory.release(nameId); + return ret; + } + roundtrip(personClosure) { + const callbackId = swift.memory.retain(personClosure); + const ret = instance.exports.bjs_TestProcessor_roundtrip(this.pointer, callbackId); + const closure = bjs["lower_closure_person_to_string"](ret); + return closure; + } + roundtripOptional(personClosure) { + const callbackId = swift.memory.retain(personClosure); + const ret = instance.exports.bjs_TestProcessor_roundtripOptional(this.pointer, callbackId); + const closure = bjs["lower_closure_optionalperson_to_string"](ret); + return closure; + } + processDirection(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_TestProcessor_processDirection(this.pointer, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + processTheme(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_TestProcessor_processTheme(this.pointer, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + processHttpStatus(callback) { + const callbackId = swift.memory.retain(callback); + const ret = instance.exports.bjs_TestProcessor_processHttpStatus(this.pointer, callbackId); + return ret; + } + processAPIResult(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_TestProcessor_processAPIResult(this.pointer, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + makeDirectionChecker() { + const ret = instance.exports.bjs_TestProcessor_makeDirectionChecker(this.pointer); + const closure = bjs["lower_closure_direction_to_bool"](ret); + return closure; + } + makeThemeValidator() { + const ret = instance.exports.bjs_TestProcessor_makeThemeValidator(this.pointer); + const closure = bjs["lower_closure_theme_to_bool"](ret); + return closure; + } + makeStatusCodeExtractor() { + const ret = instance.exports.bjs_TestProcessor_makeStatusCodeExtractor(this.pointer); + const closure = bjs["lower_closure_httpstatus_to_int"](ret); + return closure; + } + makeAPIResultHandler() { + const ret = instance.exports.bjs_TestProcessor_makeAPIResultHandler(this.pointer); + const closure = bjs["lower_closure_apiresult_to_string"](ret); + return closure; + } + processOptionalDirection(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_TestProcessor_processOptionalDirection(this.pointer, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + processOptionalTheme(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_TestProcessor_processOptionalTheme(this.pointer, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + processOptionalAPIResult(callback) { + const callbackId = swift.memory.retain(callback); + instance.exports.bjs_TestProcessor_processOptionalAPIResult(this.pointer, callbackId); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + makeOptionalDirectionFormatter() { + const ret = instance.exports.bjs_TestProcessor_makeOptionalDirectionFormatter(this.pointer); + const closure = bjs["lower_closure_optionaldirection_to_string"](ret); + return closure; + } + } + const exports = { + Person, + TestProcessor, + Direction: DirectionValues, + Theme: ThemeValues, + HttpStatus: HttpStatusValues, + APIResult: APIResultValues, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js index a1d39cd2..4c3cbc21 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createTS2Skeleton"] = function bjs_createTS2Skeleton() { try { @@ -255,8 +263,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js index f2e0bfc9..059c9315 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -185,7 +193,7 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { throwsSomething: function bjs_throwsSomething() { instance.exports.bjs_throwsSomething(); if (tmpRetException) { @@ -196,6 +204,8 @@ export async function createInstantiator(options, swift) { } }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js index 7c4438b0..320609e1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkSimple"] = function bjs_checkSimple(a) { try { @@ -193,8 +201,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js index 49b0b331..783884ef 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_Greeter_init"] = function bjs_Greeter_init(name) { try { @@ -241,8 +249,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js index a0f6f0dd..b6d7a4ea 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } }, setInstance: (i) => { instance = i; @@ -185,11 +193,13 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { check: function bjs_check() { instance.exports.bjs_check(); }, }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js index bd1d9bfb..627dd140 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js @@ -26,13 +26,16 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + + let _exports = null; + let bjs = null; return { /** * @param {WebAssembly.Imports} importObject */ addImports: (importObject, importsContext) => { - const bjs = {}; + bjs = {}; importObject["bjs"] = bjs; const imports = options.getImports(importsContext); bjs["swift_js_return_string"] = function(ptr, len) { @@ -173,6 +176,11 @@ export async function createInstantiator(options, swift) { tmpRetOptionalDouble = undefined; return value; } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_check"] = function bjs_check() { try { @@ -193,8 +201,10 @@ export async function createInstantiator(options, swift) { /** @param {WebAssembly.Instance} instance */ createExports: (instance) => { const js = swift.memory.heap; - return { + const exports = { }; + _exports = exports; + return exports; }, } } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.json new file mode 100644 index 00000000..2354469c --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.json @@ -0,0 +1,1048 @@ +{ + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Person_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "explicitAccessControl" : "public", + "methods" : [ + + ], + "name" : "Person", + "properties" : [ + + ], + "swiftCallName" : "Person" + }, + { + "constructor" : { + "abiName" : "bjs_TestProcessor_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "transform", + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_TestProcessor_getTransform", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getTransform", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TestProcessor_processWithCustom", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processWithCustom", + "parameters" : [ + { + "label" : "_", + "name" : "text", + "type" : { + "string" : { + + } + } + }, + { + "label" : "customTransform", + "name" : "customTransform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_printTogether", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "printTogether", + "parameters" : [ + { + "label" : "person", + "name" : "person", + "type" : { + "swiftHeapObject" : { + "_0" : "Person" + } + } + }, + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + }, + { + "label" : "ratio", + "name" : "ratio", + "type" : { + "double" : { + + } + } + }, + { + "label" : "customTransform", + "name" : "customTransform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalPerson_OptionalString_OptionalDouble_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Person" + } + } + } + }, + { + "optional" : { + "_0" : { + "string" : { + + } + } + } + }, + { + "optional" : { + "_0" : { + "double" : { + + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_roundtrip", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtrip", + "parameters" : [ + { + "label" : "_", + "name" : "personClosure", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Person_To_String", + "parameters" : [ + { + "swiftHeapObject" : { + "_0" : "Person" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Person_To_String", + "parameters" : [ + { + "swiftHeapObject" : { + "_0" : "Person" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TestProcessor_roundtripOptional", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundtripOptional", + "parameters" : [ + { + "label" : "_", + "name" : "personClosure", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalPerson_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Person" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalPerson_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Person" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TestProcessor_processDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processDirection", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Direction_To_String", + "parameters" : [ + { + "caseEnum" : { + "_0" : "Direction" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_processTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processTheme", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Theme_To_String", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_processHttpStatus", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processHttpStatus", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "HttpStatus_To_Int", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + ], + "returnType" : { + "int" : { + + } + } + } + } + } + } + ], + "returnType" : { + "int" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_processAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processAPIResult", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "APIResult_To_String", + "parameters" : [ + { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_makeDirectionChecker", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeDirectionChecker", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Direction_To_Bool", + "parameters" : [ + { + "caseEnum" : { + "_0" : "Direction" + } + } + ], + "returnType" : { + "bool" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TestProcessor_makeThemeValidator", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeThemeValidator", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Theme_To_Bool", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + ], + "returnType" : { + "bool" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TestProcessor_makeStatusCodeExtractor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeStatusCodeExtractor", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "HttpStatus_To_Int", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + ], + "returnType" : { + "int" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TestProcessor_makeAPIResultHandler", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAPIResultHandler", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "APIResult_To_String", + "parameters" : [ + { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TestProcessor_processOptionalDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalDirection", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalDirection_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_processOptionalTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalTheme", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalTheme_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_processOptionalAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalAPIResult", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalAPIResult_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TestProcessor_makeOptionalDirectionFormatter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeOptionalDirectionFormatter", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalDirection_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "name" : "TestProcessor", + "properties" : [ + + ], + "swiftCallName" : "TestProcessor" + } + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "north" + }, + { + "associatedValues" : [ + + ], + "name" : "south" + }, + { + "associatedValues" : [ + + ], + "name" : "east" + }, + { + "associatedValues" : [ + + ], + "name" : "west" + } + ], + "emitStyle" : "const", + "name" : "Direction", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Direction" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "light", + "rawValue" : "light" + }, + { + "associatedValues" : [ + + ], + "name" : "dark", + "rawValue" : "dark" + }, + { + "associatedValues" : [ + + ], + "name" : "auto", + "rawValue" : "auto" + } + ], + "emitStyle" : "const", + "name" : "Theme", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Theme" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "ok", + "rawValue" : "200" + }, + { + "associatedValues" : [ + + ], + "name" : "notFound", + "rawValue" : "404" + }, + { + "associatedValues" : [ + + ], + "name" : "serverError", + "rawValue" : "500" + }, + { + "associatedValues" : [ + + ], + "name" : "unknown", + "rawValue" : "-1" + } + ], + "emitStyle" : "const", + "name" : "HttpStatus", + "rawType" : "Int", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "HttpStatus" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + }, + { + "associatedValues" : [ + { + "type" : { + "bool" : { + + } + } + } + ], + "name" : "flag" + }, + { + "associatedValues" : [ + { + "type" : { + "float" : { + + } + } + } + ], + "name" : "rate" + }, + { + "associatedValues" : [ + { + "type" : { + "double" : { + + } + } + } + ], + "name" : "precise" + }, + { + "associatedValues" : [ + + ], + "name" : "info" + } + ], + "emitStyle" : "const", + "name" : "APIResult", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "APIResult" + } + ], + "functions" : [ + + ], + "moduleName" : "TestModule", + "protocols" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.swift new file mode 100644 index 00000000..888dc515 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClosure.swift @@ -0,0 +1,915 @@ +// 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 + +private final class _BJS_ClosureBox_APIResult_To_String: _BridgedSwiftClosureBox { + let closure: (APIResult) -> String + init(_ closure: @escaping (APIResult) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_APIResult_To_String { + static func bridgeJSLower(_ closure: @escaping (APIResult) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_APIResult_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (APIResult) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_apiresult_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_apiresult_to_string") +@_cdecl("invoke_swift_closure_apiresult_to_string") +public func _invoke_swift_closure_apiresult_to_string(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_APIResult_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(APIResult.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Direction_To_Bool: _BridgedSwiftClosureBox { + let closure: (Direction) -> Bool + init(_ closure: @escaping (Direction) -> Bool) { + self.closure = closure + } +} + +private enum _BJS_Closure_Direction_To_Bool { + static func bridgeJSLower(_ closure: @escaping (Direction) -> Bool) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Direction_To_Bool(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Direction) -> Bool { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_direction_to_bool") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Bool.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_direction_to_bool") +@_cdecl("invoke_swift_closure_direction_to_bool") +public func _invoke_swift_closure_direction_to_bool(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Int32 { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Direction_To_Bool>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Direction.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Direction_To_String: _BridgedSwiftClosureBox { + let closure: (Direction) -> String + init(_ closure: @escaping (Direction) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_Direction_To_String { + static func bridgeJSLower(_ closure: @escaping (Direction) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Direction_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Direction) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_direction_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_direction_to_string") +@_cdecl("invoke_swift_closure_direction_to_string") +public func _invoke_swift_closure_direction_to_string(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Direction_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Direction.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_HttpStatus_To_Int: _BridgedSwiftClosureBox { + let closure: (HttpStatus) -> Int + init(_ closure: @escaping (HttpStatus) -> Int) { + self.closure = closure + } +} + +private enum _BJS_Closure_HttpStatus_To_Int { + static func bridgeJSLower(_ closure: @escaping (HttpStatus) -> Int) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_HttpStatus_To_Int(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (HttpStatus) -> Int { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_httpstatus_to_int") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Int.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_httpstatus_to_int") +@_cdecl("invoke_swift_closure_httpstatus_to_int") +public func _invoke_swift_closure_httpstatus_to_int(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Int32 { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_HttpStatus_To_Int>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(HttpStatus.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalAPIResult_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalAPIResult_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalAPIResult_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionalapiresult_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionalapiresult_to_string") +@_cdecl("invoke_swift_closure_optionalapiresult_to_string") +public func _invoke_swift_closure_optionalapiresult_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0CaseId: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalAPIResult_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0CaseId)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalDirection_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalDirection_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalDirection_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionaldirection_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionaldirection_to_string") +@_cdecl("invoke_swift_closure_optionaldirection_to_string") +public func _invoke_swift_closure_optionaldirection_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Value: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalDirection_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalPerson_OptionalString_OptionalDouble_To_String: _BridgedSwiftClosureBox { + let closure: (Optional, Optional, Optional) -> String + init(_ closure: @escaping (Optional, Optional, Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalPerson_OptionalString_OptionalDouble_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional, Optional, Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalPerson_OptionalString_OptionalDouble_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional, Optional, Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0, param1, param2 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionalperson_optionalstring_optionaldouble_to_string") + func _invoke(_: Int32, _: Int32, _: UnsafeMutableRawPointer, _: Int32, _: Int32, _: Int32, _: Float64) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithRetain() +let (param1IsSome, param1Value) = param1.bridgeJSLowerParameterWithPresence() +let (param2IsSome, param2Value) = param2.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value, param1IsSome, param1Value, param2IsSome, param2Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionalperson_optionalstring_optionaldouble_to_string") +@_cdecl("invoke_swift_closure_optionalperson_optionalstring_optionaldouble_to_string") +public func _invoke_swift_closure_optionalperson_optionalstring_optionaldouble_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Value: UnsafeMutableRawPointer, param1IsSome: Int32, param1Bytes: Int32, param1Length: Int32, param2IsSome: Int32, param2Value: Float64) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalPerson_OptionalString_OptionalDouble_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value), Optional.bridgeJSLiftParameter(param1IsSome, param1Bytes, param1Length), Optional.bridgeJSLiftParameter(param2IsSome, param2Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalPerson_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalPerson_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalPerson_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionalperson_to_string") + func _invoke(_: Int32, _: Int32, _: UnsafeMutableRawPointer) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithRetain() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionalperson_to_string") +@_cdecl("invoke_swift_closure_optionalperson_to_string") +public func _invoke_swift_closure_optionalperson_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Value: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalPerson_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalTheme_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalTheme_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalTheme_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionaltheme_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionaltheme_to_string") +@_cdecl("invoke_swift_closure_optionaltheme_to_string") +public func _invoke_swift_closure_optionaltheme_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Bytes: Int32, param0Length: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalTheme_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Person_To_String: _BridgedSwiftClosureBox { + let closure: (Person) -> String + init(_ closure: @escaping (Person) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_Person_To_String { + static func bridgeJSLower(_ closure: @escaping (Person) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Person_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Person) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_person_to_string") + func _invoke(_: Int32, _: UnsafeMutableRawPointer) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_person_to_string") +@_cdecl("invoke_swift_closure_person_to_string") +public func _invoke_swift_closure_person_to_string(boxPtr: UnsafeMutableRawPointer, param0: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Person_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Person.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_String_To_String: _BridgedSwiftClosureBox { + let closure: (String) -> String + init(_ closure: @escaping (String) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_String_To_String { + static func bridgeJSLower(_ closure: @escaping (String) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_String_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (String) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_string_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_string_to_string") +@_cdecl("invoke_swift_closure_string_to_string") +public func _invoke_swift_closure_string_to_string(boxPtr: UnsafeMutableRawPointer, param0Bytes: Int32, param0Length: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_String_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Theme_To_Bool: _BridgedSwiftClosureBox { + let closure: (Theme) -> Bool + init(_ closure: @escaping (Theme) -> Bool) { + self.closure = closure + } +} + +private enum _BJS_Closure_Theme_To_Bool { + static func bridgeJSLower(_ closure: @escaping (Theme) -> Bool) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Theme_To_Bool(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Theme) -> Bool { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_theme_to_bool") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Bool.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_theme_to_bool") +@_cdecl("invoke_swift_closure_theme_to_bool") +public func _invoke_swift_closure_theme_to_bool(boxPtr: UnsafeMutableRawPointer, param0Bytes: Int32, param0Length: Int32) -> Int32 { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Theme_To_Bool>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Theme.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Theme_To_String: _BridgedSwiftClosureBox { + let closure: (Theme) -> String + init(_ closure: @escaping (Theme) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_Theme_To_String { + static func bridgeJSLower(_ closure: @escaping (Theme) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Theme_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Theme) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_theme_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_theme_to_string") +@_cdecl("invoke_swift_closure_theme_to_string") +public func _invoke_swift_closure_theme_to_string(boxPtr: UnsafeMutableRawPointer, param0Bytes: Int32, param0Length: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Theme_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Theme.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Direction: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Direction { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Direction { + return Direction(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + private init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .north + case 1: + self = .south + case 2: + self = .east + case 3: + self = .west + default: + return nil + } + } + + private var bridgeJSRawValue: Int32 { + switch self { + case .north: + return 0 + case .south: + return 1 + case .east: + return 2 + case .west: + return 3 + } + } +} + +extension Theme: _BridgedSwiftEnumNoPayload { +} + +extension HttpStatus: _BridgedSwiftEnumNoPayload { +} + +extension APIResult: _BridgedSwiftAssociatedValueEnum { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIResult { + switch caseId { + case 0: + return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) + case 1: + return .failure(Int.bridgeJSLiftParameter(_swift_js_pop_param_int32())) + case 2: + return .flag(Bool.bridgeJSLiftParameter(_swift_js_pop_param_int32())) + case 3: + return .rate(Float.bridgeJSLiftParameter(_swift_js_pop_param_f32())) + case 4: + return .precise(Double.bridgeJSLiftParameter(_swift_js_pop_param_f64())) + case 5: + return .info + default: + fatalError("Unknown APIResult case ID: \(caseId)") + } + } + + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0): + _swift_js_push_int(Int32(param0)) + return Int32(1) + case .flag(let param0): + _swift_js_push_int(param0 ? 1 : 0) + return Int32(2) + case .rate(let param0): + _swift_js_push_f32(param0) + return Int32(3) + case .precise(let param0): + _swift_js_push_f64(param0) + return Int32(4) + case .info: + return Int32(5) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> APIResult { + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + return _bridgeJSLiftFromCaseId(caseId) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { + switch self { + case .success(let param0): + _swift_js_push_tag(Int32(0)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let param0): + _swift_js_push_tag(Int32(1)) + _swift_js_push_int(Int32(param0)) + case .flag(let param0): + _swift_js_push_tag(Int32(2)) + _swift_js_push_int(param0 ? 1 : 0) + case .rate(let param0): + _swift_js_push_tag(Int32(3)) + _swift_js_push_f32(param0) + case .precise(let param0): + _swift_js_push_tag(Int32(4)) + _swift_js_push_f64(param0) + case .info: + _swift_js_push_tag(Int32(5)) + } + } +} + +@_expose(wasm, "bjs_Person_init") +@_cdecl("bjs_Person_init") +public func _bjs_Person_init(nameBytes: Int32, nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Person(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Person_deinit") +@_cdecl("bjs_Person_deinit") +public func _bjs_Person_deinit(pointer: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(pointer).release() +} + +extension Person: ConvertibleToJSValue, _BridgedSwiftHeapObject { + public var jsValue: JSValue { + #if arch(wasm32) + @_extern(wasm, module: "TestModule", name: "bjs_Person_wrap") + func _bjs_Person_wrap(_: UnsafeMutableRawPointer) -> Int32 + #else + func _bjs_Person_wrap(_: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") + } + #endif + return .object(JSObject(id: UInt32(bitPattern: _bjs_Person_wrap(Unmanaged.passRetained(self).toOpaque())))) + } +} + +@_expose(wasm, "bjs_TestProcessor_init") +@_cdecl("bjs_TestProcessor_init") +public func _bjs_TestProcessor_init(transform: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor(transform: _BJS_Closure_String_To_String.bridgeJSLift(transform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_getTransform") +@_cdecl("bjs_TestProcessor_getTransform") +public func _bjs_TestProcessor_getTransform(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).getTransform() + return _BJS_Closure_String_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processWithCustom") +@_cdecl("bjs_TestProcessor_processWithCustom") +public func _bjs_TestProcessor_processWithCustom(_self: UnsafeMutableRawPointer, textBytes: Int32, textLength: Int32, customTransform: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processWithCustom(_: String.bridgeJSLiftParameter(textBytes, textLength), customTransform: _BJS_Closure_String_To_String.bridgeJSLift(customTransform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_printTogether") +@_cdecl("bjs_TestProcessor_printTogether") +public func _bjs_TestProcessor_printTogether(_self: UnsafeMutableRawPointer, person: UnsafeMutableRawPointer, nameBytes: Int32, nameLength: Int32, ratio: Float64, customTransform: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).printTogether(person: Person.bridgeJSLiftParameter(person), name: String.bridgeJSLiftParameter(nameBytes, nameLength), ratio: Double.bridgeJSLiftParameter(ratio), customTransform: _BJS_Closure_OptionalPerson_OptionalString_OptionalDouble_To_String.bridgeJSLift(customTransform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_roundtrip") +@_cdecl("bjs_TestProcessor_roundtrip") +public func _bjs_TestProcessor_roundtrip(_self: UnsafeMutableRawPointer, personClosure: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).roundtrip(_: _BJS_Closure_Person_To_String.bridgeJSLift(personClosure)) + return _BJS_Closure_Person_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_roundtripOptional") +@_cdecl("bjs_TestProcessor_roundtripOptional") +public func _bjs_TestProcessor_roundtripOptional(_self: UnsafeMutableRawPointer, personClosure: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).roundtripOptional(_: _BJS_Closure_OptionalPerson_To_String.bridgeJSLift(personClosure)) + return _BJS_Closure_OptionalPerson_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processDirection") +@_cdecl("bjs_TestProcessor_processDirection") +public func _bjs_TestProcessor_processDirection(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processDirection(_: _BJS_Closure_Direction_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processTheme") +@_cdecl("bjs_TestProcessor_processTheme") +public func _bjs_TestProcessor_processTheme(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processTheme(_: _BJS_Closure_Theme_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processHttpStatus") +@_cdecl("bjs_TestProcessor_processHttpStatus") +public func _bjs_TestProcessor_processHttpStatus(_self: UnsafeMutableRawPointer, callback: Int32) -> Int32 { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processHttpStatus(_: _BJS_Closure_HttpStatus_To_Int.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processAPIResult") +@_cdecl("bjs_TestProcessor_processAPIResult") +public func _bjs_TestProcessor_processAPIResult(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processAPIResult(_: _BJS_Closure_APIResult_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_makeDirectionChecker") +@_cdecl("bjs_TestProcessor_makeDirectionChecker") +public func _bjs_TestProcessor_makeDirectionChecker(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).makeDirectionChecker() + return _BJS_Closure_Direction_To_Bool.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_makeThemeValidator") +@_cdecl("bjs_TestProcessor_makeThemeValidator") +public func _bjs_TestProcessor_makeThemeValidator(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).makeThemeValidator() + return _BJS_Closure_Theme_To_Bool.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_makeStatusCodeExtractor") +@_cdecl("bjs_TestProcessor_makeStatusCodeExtractor") +public func _bjs_TestProcessor_makeStatusCodeExtractor(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).makeStatusCodeExtractor() + return _BJS_Closure_HttpStatus_To_Int.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_makeAPIResultHandler") +@_cdecl("bjs_TestProcessor_makeAPIResultHandler") +public func _bjs_TestProcessor_makeAPIResultHandler(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).makeAPIResultHandler() + return _BJS_Closure_APIResult_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processOptionalDirection") +@_cdecl("bjs_TestProcessor_processOptionalDirection") +public func _bjs_TestProcessor_processOptionalDirection(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processOptionalDirection(_: _BJS_Closure_OptionalDirection_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processOptionalTheme") +@_cdecl("bjs_TestProcessor_processOptionalTheme") +public func _bjs_TestProcessor_processOptionalTheme(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processOptionalTheme(_: _BJS_Closure_OptionalTheme_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_processOptionalAPIResult") +@_cdecl("bjs_TestProcessor_processOptionalAPIResult") +public func _bjs_TestProcessor_processOptionalAPIResult(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).processOptionalAPIResult(_: _BJS_Closure_OptionalAPIResult_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_makeOptionalDirectionFormatter") +@_cdecl("bjs_TestProcessor_makeOptionalDirectionFormatter") +public func _bjs_TestProcessor_makeOptionalDirectionFormatter(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TestProcessor.bridgeJSLiftParameter(_self).makeOptionalDirectionFormatter() + return _BJS_Closure_OptionalDirection_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TestProcessor_deinit") +@_cdecl("bjs_TestProcessor_deinit") +public func _bjs_TestProcessor_deinit(pointer: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(pointer).release() +} + +extension TestProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject { + var jsValue: JSValue { + #if arch(wasm32) + @_extern(wasm, module: "TestModule", name: "bjs_TestProcessor_wrap") + func _bjs_TestProcessor_wrap(_: UnsafeMutableRawPointer) -> Int32 + #else + func _bjs_TestProcessor_wrap(_: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") + } + #endif + return .object(JSObject(id: UInt32(bitPattern: _bjs_TestProcessor_wrap(Unmanaged.passRetained(self).toOpaque())))) + } +} \ No newline at end of file diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 5d74cc7e..dca50d08 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -61,6 +61,8 @@ async function createInstantiator(options, swift) { swift_js_get_optional_float_value: unexpectedBjsCall, swift_js_get_optional_double_presence: unexpectedBjsCall, swift_js_get_optional_double_value: unexpectedBjsCall, + swift_js_get_optional_heap_object_pointer: unexpectedBjsCall, + release_js_callback: unexpectedBjsCall, } }, /** @param {WebAssembly.Instance} instance */ diff --git a/Sources/JavaScriptKit/BridgeJSInstrincics.swift b/Sources/JavaScriptKit/BridgeJSInstrincics.swift index 9c97583c..5b160f77 100644 --- a/Sources/JavaScriptKit/BridgeJSInstrincics.swift +++ b/Sources/JavaScriptKit/BridgeJSInstrincics.swift @@ -29,6 +29,48 @@ import _CJavaScriptKit } #endif +// MARK: Closure Callback Management + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "release_js_callback") +@_spi(BridgeJS) public func _swift_js_release_callback(_ id: Int32) +#else +/// Releases a JavaScript callback registered from JavaScript side. +/// +/// This function is called by BridgeJS-generated code after consuming a closure +/// parameter to ensure the JavaScript callback is properly cleaned up and can be +/// garbage collected. +/// +/// - Parameter id: The callback ID to release +@_spi(BridgeJS) public func _swift_js_release_callback(_ id: Int32) { + _onlyAvailableOnWasm() +} +#endif + +/// Owns a JavaScript callback and automatically releases it on deinit. +/// This ensures the callback lives exactly as long as the Swift closure that uses it. +/// +/// When a JavaScript function is passed to Swift as a closure parameter, the callback +/// is stored in `swift.memory` with an ID. This owner class captures that ID and ensures +/// it's released when the Swift closure is deallocated, preventing memory leaks while +/// supporting both @escaping and non-escaping closures. +@_spi(BridgeJS) public final class _JSCallbackOwner { + public let callbackId: Int32 + private var isReleased: Bool = false + + public init(callbackId: Int32) { + self.callbackId = callbackId + } + + deinit { + guard !isReleased else { return } + #if arch(wasm32) + _swift_js_release_callback(callbackId) + #endif + isReleased = true + } +} + /// Retrieves and clears any pending JavaScript exception. /// /// This function checks for any JavaScript exceptions that were thrown during @@ -78,7 +120,8 @@ import _CJavaScriptKit // - `func bridgeJSLowerReturn() -> <#WasmCoreType#>`: lower the given higher-level return value to a Wasm core type // // Optional types (ExportSwift only) additionally define: -// - `func bridgeJSLowerParameterWithPresence()`: lower optional as (isSome, value) tuple for protocol setters/parameters +// - `func bridgeJSLowerParameterWithPresence()`: lower optional as (isSome, value) tuple for protocol setters/parameters (borrows object) +// - `func bridgeJSLowerParameterWithRetain()`: lower optional heap object with ownership transfer for escaping closures // - `func bridgeJSLiftReturnFromSideChannel()`: lift optional from side-channel storage for protocol property getters // // See JSGlueGen.swift in BridgeJSLink for JS-side lowering/lifting implementation. @@ -290,6 +333,26 @@ extension _BridgedSwiftHeapObject { return Unmanaged.passRetained(self).toOpaque() } } +// MARK: Closure Box Protocol + +/// A protocol that Swift closure box types must conform to. +/// +/// The conformance is automatically synthesized by the BridgeJS code generator. +@_spi(BridgeJS) public protocol _BridgedSwiftClosureBox: AnyObject {} + +/// Release function for closure boxes +/// - Parameter boxPtr: Opaque pointer to a closure box conforming to _BridgedSwiftClosureBox +#if arch(wasm32) +@_expose(wasm, "release_swift_closure") +@_cdecl("release_swift_closure") +public func _release_swift_closure(boxPtr: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(boxPtr).release() +} +#else +@_spi(BridgeJS) public func _release_swift_closure(boxPtr: UnsafeMutableRawPointer) { + _onlyAvailableOnWasm() +} +#endif extension _JSBridgedClass { // MARK: ImportTS @@ -748,17 +811,46 @@ extension Optional where Wrapped: _BridgedSwiftHeapObject { } } + /// Lowers optional Swift heap object as (isSome, pointer) tuple for protocol parameters. + /// + /// This method uses `passUnretained()` because the caller (JavaScript protocol implementation) + /// already owns the object and will not retain it. The pointer is only valid for the + /// duration of the call. + /// + /// - Returns: A tuple containing presence flag (0 for nil, 1 for some) and unretained pointer @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( isSome: Int32, pointer: UnsafeMutableRawPointer ) { switch consume self { case .none: - return (isSome: 0, pointer: UnsafeMutableRawPointer(bitPattern: 0)!) + return (isSome: 0, pointer: UnsafeMutableRawPointer(bitPattern: 1)!) case .some(let value): return (isSome: 1, pointer: value.bridgeJSLowerParameter()) } } + /// Lowers optional Swift heap object with ownership transfer for escaping closures. + /// + /// This method uses `passRetained()` to transfer ownership to JavaScript, ensuring the + /// object remains valid even if the JavaScript closure escapes and stores the parameter. + /// JavaScript must wrap the pointer with `__construct()` to create a managed reference + /// that will be cleaned up via FinalizationRegistry. + /// + /// Use this method when passing heap objects to @escaping closures that may outlive + /// the original call context. + /// + /// - Returns: A tuple containing presence flag (0 for nil, 1 for some) and retained pointer + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithRetain() -> ( + isSome: Int32, pointer: UnsafeMutableRawPointer + ) { + switch consume self { + case .none: + return (isSome: 0, pointer: UnsafeMutableRawPointer(bitPattern: 1)!) + case .some(let value): + return (isSome: 1, pointer: Unmanaged.passRetained(value).toOpaque()) + } + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ pointer: UnsafeMutableRawPointer) -> Wrapped? { if pointer == UnsafeMutableRawPointer(bitPattern: 0) { @@ -781,6 +873,24 @@ extension Optional where Wrapped: _BridgedSwiftHeapObject { } } + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_heap_object_pointer") + func _swift_js_get_optional_heap_object_pointer() -> UnsafeMutableRawPointer + #else + func _swift_js_get_optional_heap_object_pointer() -> UnsafeMutableRawPointer { + _onlyAvailableOnWasm() + } + #endif + + let pointer = _swift_js_get_optional_heap_object_pointer() + if pointer == UnsafeMutableRawPointer(bitPattern: 0) { + return nil + } else { + return Wrapped.bridgeJSLiftReturn(pointer) + } + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_return_optional_heap_object") diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift-to-JavaScript.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift-to-JavaScript.md index dbdfba78..44019bf6 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift-to-JavaScript.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift-to-JavaScript.md @@ -66,6 +66,7 @@ This command will: - - - +- - - - 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 new file mode 100644 index 00000000..83a1d9f4 --- /dev/null +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Closure.md @@ -0,0 +1,114 @@ +# Exporting Swift Closures + +Learn how to use closure/function types as parameters and return values in BridgeJS. + +## Overview + +> Tip: You can quickly preview what interfaces will be exposed on the Swift/TypeScript sides using the [BridgeJS Playground](https://swiftwasm.org/JavaScriptKit/PlayBridgeJS/). + +BridgeJS supports typed closure parameters and return values, allowing you to pass functions between Swift and JavaScript with full type safety. This enables functional programming patterns like callbacks, higher-order functions, and function composition across the language boundary. + +## Example + +```swift +import JavaScriptKit + +@JS class TextProcessor { + private var transform: (String) -> String + + @JS init(transform: @escaping (String) -> String) { + self.transform = transform + } + + @JS func processWithPerson(_ person: Person, formatter: (Person) -> String) -> String { + return formatter(person) + } + + @JS func makePersonCreator(defaultName: String) -> (String) -> Person { + return { name in + let fullName = name.isEmpty ? defaultName : name + return Person(name: fullName) + } + } + + @JS func getTransform() -> (String) -> String { + return transform + } +} +``` + +In JavaScript: + +```javascript +import { init } from "./.build/plugins/PackageToJS/outputs/Package/index.js"; +const { exports } = await init({}); + +// Pass closure to initializer +const processor = new exports.TextProcessor((text) => text.toUpperCase()); +console.log(processor.getTransform()("hello")); // "HELLO" + +// Pass closure with Swift class parameter +const person = new exports.Person("Alice"); +const result = processor.processWithPerson(person, (p) => { + return `${p.name}: ${p.greet()}`; +}); +console.log(result); // "Alice: Hello, Alice!" + +// Call returned closure +const creator = processor.makePersonCreator("Default"); +const p1 = creator("Bob"); +console.log(p1.greet()); // "Hello, Bob!" +p1.release(); + +const p2 = creator(""); // Empty uses default +console.log(p2.greet()); // "Hello, Default!" +p2.release(); + +person.release(); +processor.release(); +``` + +The generated TypeScript declarations: + +```typescript +export interface TextProcessor extends SwiftHeapObject { + processWithPerson( + person: Person, + formatter: (arg0: Person) => string + ): string; + makePersonCreator( + defaultName: string + ): (arg0: string) => Person; + getTransform(): (arg0: string) => string; +} + +export type Exports = { + TextProcessor: { + new(transform: (arg0: string) => string): TextProcessor + }; +} +``` + +## Memory Management + +When JavaScript passes a function to Swift, it's automatically stored in `swift.memory` with reference counting. When Swift's closure wrapper is deallocated by ARC, the JavaScript function is released. + +When Swift returns a closure to JavaScript, the Swift closure is boxed and automatically released when the JavaScript function is garbage collected. + +Both directions use automatic memory management - no manual cleanup required. + +## Supported Features + +| Feature | Status | +|:--------|:-------| +| Closure Parameters with Supported Types `(String, Int) -> Person` | ✅ | +| Closure Return Value with Supported Types `() -> Person` | ✅ | +| `@escaping` closures | ✅ | +| Optional types in closures | ✅ | +| Closure-typed `@JS` properties | ❌ | +| Async closures | ❌ | +| Throwing closures | ❌ | + +## See Also + +- - Complete list of supported types across BridgeJS diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 97ebcfd2..3875d37e 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -59,7 +59,7 @@ struct TestError: Error { @JS func asyncRoundTripSwiftHeapObject(v: Greeter) async -> Greeter { return v } @JS func asyncRoundTripJSObject(v: JSObject) async -> JSObject { return v } -@JS class Greeter { +@JS public class Greeter { @JS var name: String @JS let prefix: String = "Hello" @@ -76,6 +76,27 @@ struct TestError: Error { self.name = name } + @JS func greetWith(greeter: Greeter, customGreeting: (Greeter) -> String) -> String { + return customGreeting(greeter) + } + + @JS func makeFormatter(suffix: String) -> (String) -> String { + return { value in "\(self.greet()) - \(value) - \(suffix)" } + } + + @JS static func makeCreator(defaultName: String) -> (String) -> Greeter { + return { name in + let fullName = name.isEmpty ? defaultName : name + return Greeter(name: fullName) + } + } + + @JS func makeCustomGreeter() -> (Greeter) -> String { + return { otherGreeter in + return "\(self.name) greets \(otherGreeter.name): \(otherGreeter.greet())" + } + } + deinit { Self.onDeinit() } @@ -1039,6 +1060,161 @@ enum APIOptionalResult { } } +// MARK: - Closure Tests + +// @JS func makeFormatter(prefix: String) -> (String) -> String { +// return { value in "\(prefix) \(value)" } +// } + +@JS func formatName(_ name: String, transform: (String) -> String) -> String { + return transform(name) +} + +@JS func makeFormatter(prefix: String) -> (String) -> String { + return { value in "\(prefix) \(value)" } +} + +@JS func makeAdder(base: Int) -> (Int) -> Int { + return { value in base + value } +} + +@JS class TextProcessor { + private var transform: (String) -> String + + @JS init(transform: @escaping (String) -> String) { + self.transform = transform + } + + @JS func process(_ text: String) -> String { + return transform(text) + } + + @JS func processWithCustom(_ text: String, customTransform: (Int, String, Double) -> String) -> String { + return customTransform(42, text, 3.14) + } + + @JS func getTransform() -> (String) -> String { + return transform + } + + // Optional parameter in closure + @JS func processOptionalString(_ callback: (String?) -> String) -> String { + return callback("test") + " | " + callback(nil) + } + + @JS func processOptionalInt(_ callback: (Int?) -> String) -> String { + return callback(42) + " | " + callback(nil) + } + + @JS func processOptionalGreeter(_ callback: (Greeter?) -> String) -> String { + let greeter = Greeter(name: "Alice") + return callback(greeter) + " | " + callback(nil) + } + + // Return closure with optional parameter + @JS func makeOptionalStringFormatter() -> (String?) -> String { + return { value in + if let value = value { + return "Got: \(value)" + } else { + return "Got: nil" + } + } + } + + // Return closure with optional return type + @JS func makeOptionalGreeterCreator() -> () -> Greeter? { + var count = 0 + return { + count += 1 + if count % 2 == 0 { + return Greeter(name: "Greeter\(count)") + } else { + return nil + } + } + } + + @JS func processDirection(_ callback: (Direction) -> String) -> String { + return callback(.north) + } + + @JS func processTheme(_ callback: (Theme) -> String) -> String { + return callback(.dark) + } + + @JS func processHttpStatus(_ callback: (HttpStatus) -> Int) -> Int { + return callback(.ok) + } + + @JS func processAPIResult(_ callback: (APIResult) -> String) -> String { + return callback(.success("test")) + } + + @JS func makeDirectionChecker() -> (Direction) -> Bool { + return { direction in + direction == .north || direction == .south + } + } + + @JS func makeThemeValidator() -> (Theme) -> Bool { + return { theme in + theme == .dark + } + } + + @JS func makeStatusCodeExtractor() -> (HttpStatus) -> Int { + return { status in + switch status { + case .ok: return 200 + case .notFound: return 404 + case .serverError: return 500 + case .unknown: return -1 + } + } + } + + @JS func makeAPIResultHandler() -> (APIResult) -> String { + return { result in + switch result { + case .success(let message): return "Success: \(message)" + case .failure(let code): return "Failure: \(code)" + case .info: return "Info" + case .flag(let value): return "Flag: \(value)" + case .rate(let value): return "Rate: \(value)" + case .precise(let value): return "Precise: \(value)" + } + } + } + + @JS func processOptionalDirection(_ callback: (Direction?) -> String) -> String { + return callback(.north) + " | " + callback(nil) + } + + @JS func processOptionalTheme(_ callback: (Theme?) -> String) -> String { + return callback(.light) + " | " + callback(nil) + } + + @JS func processOptionalAPIResult(_ callback: (APIResult?) -> String) -> String { + return callback(.success("ok")) + " | " + callback(nil) + } + + @JS func makeOptionalDirectionFormatter() -> (Direction?) -> String { + return { direction in + if let direction = direction { + switch direction { + case .north: return "N" + case .south: return "S" + case .east: return "E" + case .west: return "W" + } + } else { + return "nil" + } + } + } +} + class ExportAPITests: XCTestCase { func testAll() { var hasDeinitGreeter = false diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 350ef7ae..67f05fde 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -6,6 +6,732 @@ @_spi(BridgeJS) import JavaScriptKit +private final class _BJS_ClosureBox_APIResult_To_String: _BridgedSwiftClosureBox { + let closure: (APIResult) -> String + init(_ closure: @escaping (APIResult) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_APIResult_To_String { + static func bridgeJSLower(_ closure: @escaping (APIResult) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_APIResult_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (APIResult) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_apiresult_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_apiresult_to_string") +@_cdecl("invoke_swift_closure_apiresult_to_string") +public func _invoke_swift_closure_apiresult_to_string(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_APIResult_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(APIResult.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Direction_To_Bool: _BridgedSwiftClosureBox { + let closure: (Direction) -> Bool + init(_ closure: @escaping (Direction) -> Bool) { + self.closure = closure + } +} + +private enum _BJS_Closure_Direction_To_Bool { + static func bridgeJSLower(_ closure: @escaping (Direction) -> Bool) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Direction_To_Bool(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Direction) -> Bool { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_direction_to_bool") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Bool.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_direction_to_bool") +@_cdecl("invoke_swift_closure_direction_to_bool") +public func _invoke_swift_closure_direction_to_bool(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Int32 { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Direction_To_Bool>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Direction.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Direction_To_String: _BridgedSwiftClosureBox { + let closure: (Direction) -> String + init(_ closure: @escaping (Direction) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_Direction_To_String { + static func bridgeJSLower(_ closure: @escaping (Direction) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Direction_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Direction) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_direction_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_direction_to_string") +@_cdecl("invoke_swift_closure_direction_to_string") +public func _invoke_swift_closure_direction_to_string(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Direction_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Direction.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Greeter_To_String: _BridgedSwiftClosureBox { + let closure: (Greeter) -> String + init(_ closure: @escaping (Greeter) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_Greeter_To_String { + static func bridgeJSLower(_ closure: @escaping (Greeter) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Greeter_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Greeter) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_greeter_to_string") + func _invoke(_: Int32, _: UnsafeMutableRawPointer) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_greeter_to_string") +@_cdecl("invoke_swift_closure_greeter_to_string") +public func _invoke_swift_closure_greeter_to_string(boxPtr: UnsafeMutableRawPointer, param0: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Greeter_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Greeter.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_HttpStatus_To_Int: _BridgedSwiftClosureBox { + let closure: (HttpStatus) -> Int + init(_ closure: @escaping (HttpStatus) -> Int) { + self.closure = closure + } +} + +private enum _BJS_Closure_HttpStatus_To_Int { + static func bridgeJSLower(_ closure: @escaping (HttpStatus) -> Int) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_HttpStatus_To_Int(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (HttpStatus) -> Int { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_httpstatus_to_int") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Int.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_httpstatus_to_int") +@_cdecl("invoke_swift_closure_httpstatus_to_int") +public func _invoke_swift_closure_httpstatus_to_int(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Int32 { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_HttpStatus_To_Int>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(HttpStatus.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Int_String_Double_To_String: _BridgedSwiftClosureBox { + let closure: (Int, String, Double) -> String + init(_ closure: @escaping (Int, String, Double) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_Int_String_Double_To_String { + static func bridgeJSLower(_ closure: @escaping (Int, String, Double) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Int_String_Double_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Int, String, Double) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0, param1, param2 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_int_string_double_to_string") + func _invoke(_: Int32, _: Int32, _: Int32, _: Float64) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter(), param1.bridgeJSLowerParameter(), param2.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_int_string_double_to_string") +@_cdecl("invoke_swift_closure_int_string_double_to_string") +public func _invoke_swift_closure_int_string_double_to_string(boxPtr: UnsafeMutableRawPointer, param0: Int32, param1Bytes: Int32, param1Length: Int32, param2: Float64) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Int_String_Double_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Int.bridgeJSLiftParameter(param0), String.bridgeJSLiftParameter(param1Bytes, param1Length), Double.bridgeJSLiftParameter(param2)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Int_To_Int: _BridgedSwiftClosureBox { + let closure: (Int) -> Int + init(_ closure: @escaping (Int) -> Int) { + self.closure = closure + } +} + +private enum _BJS_Closure_Int_To_Int { + static func bridgeJSLower(_ closure: @escaping (Int) -> Int) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Int_To_Int(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Int) -> Int { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_int_to_int") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Int.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_int_to_int") +@_cdecl("invoke_swift_closure_int_to_int") +public func _invoke_swift_closure_int_to_int(boxPtr: UnsafeMutableRawPointer, param0: Int32) -> Int32 { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Int_To_Int>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Int.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalAPIResult_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalAPIResult_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalAPIResult_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionalapiresult_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionalapiresult_to_string") +@_cdecl("invoke_swift_closure_optionalapiresult_to_string") +public func _invoke_swift_closure_optionalapiresult_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0CaseId: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalAPIResult_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0CaseId)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalDirection_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalDirection_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalDirection_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionaldirection_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionaldirection_to_string") +@_cdecl("invoke_swift_closure_optionaldirection_to_string") +public func _invoke_swift_closure_optionaldirection_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Value: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalDirection_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalGreeter_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalGreeter_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalGreeter_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionalgreeter_to_string") + func _invoke(_: Int32, _: Int32, _: UnsafeMutableRawPointer) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithRetain() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionalgreeter_to_string") +@_cdecl("invoke_swift_closure_optionalgreeter_to_string") +public func _invoke_swift_closure_optionalgreeter_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Value: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalGreeter_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalInt_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalInt_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalInt_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionalint_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionalint_to_string") +@_cdecl("invoke_swift_closure_optionalint_to_string") +public func _invoke_swift_closure_optionalint_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Value: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalInt_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Value)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalString_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalString_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalString_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionalstring_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionalstring_to_string") +@_cdecl("invoke_swift_closure_optionalstring_to_string") +public func _invoke_swift_closure_optionalstring_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Bytes: Int32, param0Length: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalString_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_OptionalTheme_To_String: _BridgedSwiftClosureBox { + let closure: (Optional) -> String + init(_ closure: @escaping (Optional) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_OptionalTheme_To_String { + static func bridgeJSLower(_ closure: @escaping (Optional) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_OptionalTheme_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Optional) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_optionaltheme_to_string") + func _invoke(_: Int32, _: Int32, _: Int32) -> Int32 + let (param0IsSome, param0Value) = param0.bridgeJSLowerParameterWithPresence() +let resultId = _invoke(owner.callbackId, param0IsSome, param0Value) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_optionaltheme_to_string") +@_cdecl("invoke_swift_closure_optionaltheme_to_string") +public func _invoke_swift_closure_optionaltheme_to_string(boxPtr: UnsafeMutableRawPointer, param0IsSome: Int32, param0Bytes: Int32, param0Length: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_OptionalTheme_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Optional.bridgeJSLiftParameter(param0IsSome, param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_String_To_Greeter: _BridgedSwiftClosureBox { + let closure: (String) -> Greeter + init(_ closure: @escaping (String) -> Greeter) { + self.closure = closure + } +} + +private enum _BJS_Closure_String_To_Greeter { + static func bridgeJSLower(_ closure: @escaping (String) -> Greeter) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_String_To_Greeter(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (String) -> Greeter { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_string_to_greeter") + func _invoke(_: Int32, _: Int32) -> UnsafeMutableRawPointer + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Greeter.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_string_to_greeter") +@_cdecl("invoke_swift_closure_string_to_greeter") +public func _invoke_swift_closure_string_to_greeter(boxPtr: UnsafeMutableRawPointer, param0Bytes: Int32, param0Length: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_String_To_Greeter>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_String_To_String: _BridgedSwiftClosureBox { + let closure: (String) -> String + init(_ closure: @escaping (String) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_String_To_String { + static func bridgeJSLower(_ closure: @escaping (String) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_String_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (String) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_string_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_string_to_string") +@_cdecl("invoke_swift_closure_string_to_string") +public func _invoke_swift_closure_string_to_string(boxPtr: UnsafeMutableRawPointer, param0Bytes: Int32, param0Length: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_String_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(String.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Theme_To_Bool: _BridgedSwiftClosureBox { + let closure: (Theme) -> Bool + init(_ closure: @escaping (Theme) -> Bool) { + self.closure = closure + } +} + +private enum _BJS_Closure_Theme_To_Bool { + static func bridgeJSLower(_ closure: @escaping (Theme) -> Bool) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Theme_To_Bool(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Theme) -> Bool { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_theme_to_bool") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return Bool.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_theme_to_bool") +@_cdecl("invoke_swift_closure_theme_to_bool") +public func _invoke_swift_closure_theme_to_bool(boxPtr: UnsafeMutableRawPointer, param0Bytes: Int32, param0Length: Int32) -> Int32 { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Theme_To_Bool>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Theme.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Theme_To_String: _BridgedSwiftClosureBox { + let closure: (Theme) -> String + init(_ closure: @escaping (Theme) -> String) { + self.closure = closure + } +} + +private enum _BJS_Closure_Theme_To_String { + static func bridgeJSLower(_ closure: @escaping (Theme) -> String) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Theme_To_String(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> (Theme) -> String { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] param0 in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_theme_to_string") + func _invoke(_: Int32, _: Int32) -> Int32 + let resultId = _invoke(owner.callbackId, param0.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(resultId) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_theme_to_string") +@_cdecl("invoke_swift_closure_theme_to_string") +public func _invoke_swift_closure_theme_to_string(boxPtr: UnsafeMutableRawPointer, param0Bytes: Int32, param0Length: Int32) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Theme_To_String>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure(Theme.bridgeJSLiftParameter(param0Bytes, param0Length)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +private final class _BJS_ClosureBox_Void_To_OptionalGreeter: _BridgedSwiftClosureBox { + let closure: () -> Optional + init(_ closure: @escaping () -> Optional) { + self.closure = closure + } +} + +private enum _BJS_Closure_Void_To_OptionalGreeter { + static func bridgeJSLower(_ closure: @escaping () -> Optional) -> UnsafeMutableRawPointer { + let box = _BJS_ClosureBox_Void_To_OptionalGreeter(closure) + return Unmanaged.passRetained(box).toOpaque() + } + + static func bridgeJSLift(_ callbackId: Int32) -> () -> Optional { + let owner = _JSCallbackOwner(callbackId: callbackId) + return { [owner] in + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "invoke_js_callback_void_to_optionalgreeter") + func _invoke(_: Int32) -> Void + _invoke(owner.callbackId) + return Optional.bridgeJSLiftReturnFromSideChannel() + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +@_expose(wasm, "invoke_swift_closure_void_to_optionalgreeter") +@_cdecl("invoke_swift_closure_void_to_optionalgreeter") +public func _invoke_swift_closure_void_to_optionalgreeter(boxPtr: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let box = Unmanaged<_BJS_ClosureBox_Void_To_OptionalGreeter>.fromOpaque(boxPtr).takeUnretainedValue() + let result = box.closure() + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { let jsObject: JSObject @@ -2502,6 +3228,39 @@ public func _bjs_getAllStaticPropertyValues() -> Void { #endif } +@_expose(wasm, "bjs_formatName") +@_cdecl("bjs_formatName") +public func _bjs_formatName(nameBytes: Int32, nameLength: Int32, transform: Int32) -> Void { + #if arch(wasm32) + let ret = formatName(_: String.bridgeJSLiftParameter(nameBytes, nameLength), transform: _BJS_Closure_String_To_String.bridgeJSLift(transform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeFormatter") +@_cdecl("bjs_makeFormatter") +public func _bjs_makeFormatter(prefixBytes: Int32, prefixLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = makeFormatter(prefix: String.bridgeJSLiftParameter(prefixBytes, prefixLength)) + return _BJS_Closure_String_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeAdder") +@_cdecl("bjs_makeAdder") +public func _bjs_makeAdder(base: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = makeAdder(base: Int.bridgeJSLiftParameter(base)) + return _BJS_Closure_Int_To_Int.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_init") @_cdecl("bjs_Greeter_init") public func _bjs_Greeter_init(nameBytes: Int32, nameLength: Int32) -> UnsafeMutableRawPointer { @@ -2534,6 +3293,50 @@ public func _bjs_Greeter_changeName(_self: UnsafeMutableRawPointer, nameBytes: I #endif } +@_expose(wasm, "bjs_Greeter_greetWith") +@_cdecl("bjs_Greeter_greetWith") +public func _bjs_Greeter_greetWith(_self: UnsafeMutableRawPointer, greeter: UnsafeMutableRawPointer, customGreeting: Int32) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetWith(greeter: Greeter.bridgeJSLiftParameter(greeter), customGreeting: _BJS_Closure_Greeter_To_String.bridgeJSLift(customGreeting)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_makeFormatter") +@_cdecl("bjs_Greeter_makeFormatter") +public func _bjs_Greeter_makeFormatter(_self: UnsafeMutableRawPointer, suffixBytes: Int32, suffixLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).makeFormatter(suffix: String.bridgeJSLiftParameter(suffixBytes, suffixLength)) + return _BJS_Closure_String_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_makeCreator") +@_cdecl("bjs_Greeter_static_makeCreator") +public func _bjs_Greeter_static_makeCreator(defaultNameBytes: Int32, defaultNameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter.makeCreator(defaultName: String.bridgeJSLiftParameter(defaultNameBytes, defaultNameLength)) + return _BJS_Closure_String_To_Greeter.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_makeCustomGreeter") +@_cdecl("bjs_Greeter_makeCustomGreeter") +public func _bjs_Greeter_makeCustomGreeter(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).makeCustomGreeter() + return _BJS_Closure_Greeter_To_String.bridgeJSLower(ret) + #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 { @@ -2573,7 +3376,7 @@ public func _bjs_Greeter_deinit(pointer: UnsafeMutableRawPointer) { } extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { - var jsValue: JSValue { + public var jsValue: JSValue { #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Greeter_wrap") func _bjs_Greeter_wrap(_: UnsafeMutableRawPointer) -> Int32 @@ -4340,4 +5143,255 @@ extension SwiftDataProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject { #endif return .object(JSObject(id: UInt32(bitPattern: _bjs_SwiftDataProcessor_wrap(Unmanaged.passRetained(self).toOpaque())))) } +} + +@_expose(wasm, "bjs_TextProcessor_init") +@_cdecl("bjs_TextProcessor_init") +public func _bjs_TextProcessor_init(transform: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor(transform: _BJS_Closure_String_To_String.bridgeJSLift(transform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_process") +@_cdecl("bjs_TextProcessor_process") +public func _bjs_TextProcessor_process(_self: UnsafeMutableRawPointer, textBytes: Int32, textLength: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).process(_: String.bridgeJSLiftParameter(textBytes, textLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processWithCustom") +@_cdecl("bjs_TextProcessor_processWithCustom") +public func _bjs_TextProcessor_processWithCustom(_self: UnsafeMutableRawPointer, textBytes: Int32, textLength: Int32, customTransform: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processWithCustom(_: String.bridgeJSLiftParameter(textBytes, textLength), customTransform: _BJS_Closure_Int_String_Double_To_String.bridgeJSLift(customTransform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_getTransform") +@_cdecl("bjs_TextProcessor_getTransform") +public func _bjs_TextProcessor_getTransform(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).getTransform() + return _BJS_Closure_String_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalString") +@_cdecl("bjs_TextProcessor_processOptionalString") +public func _bjs_TextProcessor_processOptionalString(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalString(_: _BJS_Closure_OptionalString_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalInt") +@_cdecl("bjs_TextProcessor_processOptionalInt") +public func _bjs_TextProcessor_processOptionalInt(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalInt(_: _BJS_Closure_OptionalInt_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalGreeter") +@_cdecl("bjs_TextProcessor_processOptionalGreeter") +public func _bjs_TextProcessor_processOptionalGreeter(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalGreeter(_: _BJS_Closure_OptionalGreeter_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeOptionalStringFormatter") +@_cdecl("bjs_TextProcessor_makeOptionalStringFormatter") +public func _bjs_TextProcessor_makeOptionalStringFormatter(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeOptionalStringFormatter() + return _BJS_Closure_OptionalString_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeOptionalGreeterCreator") +@_cdecl("bjs_TextProcessor_makeOptionalGreeterCreator") +public func _bjs_TextProcessor_makeOptionalGreeterCreator(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeOptionalGreeterCreator() + return _BJS_Closure_Void_To_OptionalGreeter.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processDirection") +@_cdecl("bjs_TextProcessor_processDirection") +public func _bjs_TextProcessor_processDirection(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processDirection(_: _BJS_Closure_Direction_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processTheme") +@_cdecl("bjs_TextProcessor_processTheme") +public func _bjs_TextProcessor_processTheme(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processTheme(_: _BJS_Closure_Theme_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processHttpStatus") +@_cdecl("bjs_TextProcessor_processHttpStatus") +public func _bjs_TextProcessor_processHttpStatus(_self: UnsafeMutableRawPointer, callback: Int32) -> Int32 { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processHttpStatus(_: _BJS_Closure_HttpStatus_To_Int.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processAPIResult") +@_cdecl("bjs_TextProcessor_processAPIResult") +public func _bjs_TextProcessor_processAPIResult(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processAPIResult(_: _BJS_Closure_APIResult_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeDirectionChecker") +@_cdecl("bjs_TextProcessor_makeDirectionChecker") +public func _bjs_TextProcessor_makeDirectionChecker(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeDirectionChecker() + return _BJS_Closure_Direction_To_Bool.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeThemeValidator") +@_cdecl("bjs_TextProcessor_makeThemeValidator") +public func _bjs_TextProcessor_makeThemeValidator(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeThemeValidator() + return _BJS_Closure_Theme_To_Bool.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeStatusCodeExtractor") +@_cdecl("bjs_TextProcessor_makeStatusCodeExtractor") +public func _bjs_TextProcessor_makeStatusCodeExtractor(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeStatusCodeExtractor() + return _BJS_Closure_HttpStatus_To_Int.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeAPIResultHandler") +@_cdecl("bjs_TextProcessor_makeAPIResultHandler") +public func _bjs_TextProcessor_makeAPIResultHandler(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeAPIResultHandler() + return _BJS_Closure_APIResult_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalDirection") +@_cdecl("bjs_TextProcessor_processOptionalDirection") +public func _bjs_TextProcessor_processOptionalDirection(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalDirection(_: _BJS_Closure_OptionalDirection_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalTheme") +@_cdecl("bjs_TextProcessor_processOptionalTheme") +public func _bjs_TextProcessor_processOptionalTheme(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalTheme(_: _BJS_Closure_OptionalTheme_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_processOptionalAPIResult") +@_cdecl("bjs_TextProcessor_processOptionalAPIResult") +public func _bjs_TextProcessor_processOptionalAPIResult(_self: UnsafeMutableRawPointer, callback: Int32) -> Void { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).processOptionalAPIResult(_: _BJS_Closure_OptionalAPIResult_To_String.bridgeJSLift(callback)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_makeOptionalDirectionFormatter") +@_cdecl("bjs_TextProcessor_makeOptionalDirectionFormatter") +public func _bjs_TextProcessor_makeOptionalDirectionFormatter(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = TextProcessor.bridgeJSLiftParameter(_self).makeOptionalDirectionFormatter() + return _BJS_Closure_OptionalDirection_To_String.bridgeJSLower(ret) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_TextProcessor_deinit") +@_cdecl("bjs_TextProcessor_deinit") +public func _bjs_TextProcessor_deinit(pointer: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(pointer).release() +} + +extension TextProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject { + var jsValue: JSValue { + #if arch(wasm32) + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_TextProcessor_wrap") + func _bjs_TextProcessor_wrap(_: UnsafeMutableRawPointer) -> Int32 + #else + func _bjs_TextProcessor_wrap(_: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") + } + #endif + return .object(JSObject(id: UInt32(bitPattern: _bjs_TextProcessor_wrap(Unmanaged.passRetained(self).toOpaque())))) + } } \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index c0e0a4a8..23d2afdc 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -20,6 +20,7 @@ } ] }, + "explicitAccessControl" : "public", "methods" : [ { "abiName" : "bjs_Greeter_greet", @@ -62,6 +63,176 @@ } } + }, + { + "abiName" : "bjs_Greeter_greetWith", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetWith", + "parameters" : [ + { + "label" : "greeter", + "name" : "greeter", + "type" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + }, + { + "label" : "customGreeting", + "name" : "customGreeting", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Greeter_To_String", + "parameters" : [ + { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_makeFormatter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeFormatter", + "parameters" : [ + { + "label" : "suffix", + "name" : "suffix", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_Greeter_static_makeCreator", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "makeCreator", + "parameters" : [ + { + "label" : "defaultName", + "name" : "defaultName", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_Greeter", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } + }, + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + } + }, + { + "abiName" : "bjs_Greeter_makeCustomGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeCustomGreeter", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Greeter_To_String", + "parameters" : [ + { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } } ], "name" : "Greeter", @@ -1986,103 +2157,943 @@ } }, { - "isReadonly" : false, - "isStatic" : false, - "name" : "optionalCount", - "type" : { - "optional" : { + "isReadonly" : false, + "isStatic" : false, + "name" : "optionalCount", + "type" : { + "optional" : { + "_0" : { + "int" : { + + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "direction", + "type" : { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "optionalTheme", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "httpStatus", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "apiResult", + "type" : { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "helper", + "type" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "optionalHelper", + "type" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } + } + ], + "swiftCallName" : "SwiftDataProcessor" + }, + { + "constructor" : { + "abiName" : "bjs_TextProcessor_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "transform", + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_TextProcessor_process", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "process", + "parameters" : [ + { + "label" : "_", + "name" : "text", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_processWithCustom", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processWithCustom", + "parameters" : [ + { + "label" : "_", + "name" : "text", + "type" : { + "string" : { + + } + } + }, + { + "label" : "customTransform", + "name" : "customTransform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Int_String_Double_To_String", + "parameters" : [ + { + "int" : { + + } + }, + { + "string" : { + + } + }, + { + "double" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_getTransform", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getTransform", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TextProcessor_processOptionalString", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalString", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalString_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "string" : { + + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_processOptionalInt", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalInt", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalInt_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "int" : { + + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_processOptionalGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalGreeter", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalGreeter_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_makeOptionalStringFormatter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeOptionalStringFormatter", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalString_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "string" : { + + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TextProcessor_makeOptionalGreeterCreator", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeOptionalGreeterCreator", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Void_To_OptionalGreeter", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } + } + } + } + }, + { + "abiName" : "bjs_TextProcessor_processDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processDirection", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Direction_To_String", + "parameters" : [ + { + "caseEnum" : { + "_0" : "Direction" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_processTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processTheme", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Theme_To_String", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_processHttpStatus", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processHttpStatus", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "HttpStatus_To_Int", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + ], + "returnType" : { + "int" : { + + } + } + } + } + } + } + ], + "returnType" : { + "int" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_processAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processAPIResult", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "APIResult_To_String", + "parameters" : [ + { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_TextProcessor_makeDirectionChecker", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeDirectionChecker", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Direction_To_Bool", + "parameters" : [ + { + "caseEnum" : { + "_0" : "Direction" + } + } + ], + "returnType" : { + "bool" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TextProcessor_makeThemeValidator", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeThemeValidator", + "parameters" : [ + + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Theme_To_Bool", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + ], + "returnType" : { + "bool" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_TextProcessor_makeStatusCodeExtractor", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeStatusCodeExtractor", + "parameters" : [ + + ], + "returnType" : { + "closure" : { "_0" : { - "int" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "HttpStatus_To_Int", + "parameters" : [ + { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + ], + "returnType" : { + "int" : { + } } } } } }, { - "isReadonly" : false, - "isStatic" : false, - "name" : "direction", - "type" : { - "optional" : { + "abiName" : "bjs_TextProcessor_makeAPIResultHandler", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAPIResultHandler", + "parameters" : [ + + ], + "returnType" : { + "closure" : { "_0" : { - "caseEnum" : { - "_0" : "Direction" + "isAsync" : false, + "isThrows" : false, + "mangleName" : "APIResult_To_String", + "parameters" : [ + { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + ], + "returnType" : { + "string" : { + + } } } } } }, { - "isReadonly" : false, - "isStatic" : false, - "name" : "optionalTheme", - "type" : { - "optional" : { - "_0" : { - "rawValueEnum" : { - "_0" : "Theme", - "_1" : "String" + "abiName" : "bjs_TextProcessor_processOptionalDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalDirection", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalDirection_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } } } } + ], + "returnType" : { + "string" : { + + } } }, { - "isReadonly" : false, - "isStatic" : false, - "name" : "httpStatus", - "type" : { - "optional" : { - "_0" : { - "rawValueEnum" : { - "_0" : "HttpStatus", - "_1" : "Int" + "abiName" : "bjs_TextProcessor_processOptionalTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalTheme", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalTheme_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } } } } + ], + "returnType" : { + "string" : { + + } } }, { - "isReadonly" : false, - "isStatic" : false, - "name" : "apiResult", - "type" : { - "optional" : { - "_0" : { - "associatedValueEnum" : { - "_0" : "APIResult" + "abiName" : "bjs_TextProcessor_processOptionalAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalAPIResult", + "parameters" : [ + { + "label" : "_", + "name" : "callback", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalAPIResult_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + } } } } - } - }, - { - "isReadonly" : false, - "isStatic" : false, - "name" : "helper", - "type" : { - "swiftHeapObject" : { - "_0" : "Greeter" + ], + "returnType" : { + "string" : { + } } }, { - "isReadonly" : false, - "isStatic" : false, - "name" : "optionalHelper", - "type" : { - "optional" : { + "abiName" : "bjs_TextProcessor_makeOptionalDirectionFormatter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeOptionalDirectionFormatter", + "parameters" : [ + + ], + "returnType" : { + "closure" : { "_0" : { - "swiftHeapObject" : { - "_0" : "Greeter" + "isAsync" : false, + "isThrows" : false, + "mangleName" : "OptionalDirection_To_String", + "parameters" : [ + { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + ], + "returnType" : { + "string" : { + + } } } } } } ], - "swiftCallName" : "SwiftDataProcessor" + "name" : "TextProcessor", + "properties" : [ + + ], + "swiftCallName" : "TextProcessor" } ], "enums" : [ @@ -6354,6 +7365,138 @@ } } + }, + { + "abiName" : "bjs_formatName", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "formatName", + "parameters" : [ + { + "label" : "_", + "name" : "name", + "type" : { + "string" : { + + } + } + }, + { + "label" : "transform", + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_makeFormatter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeFormatter", + "parameters" : [ + { + "label" : "prefix", + "name" : "prefix", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "String_To_String", + "parameters" : [ + { + "string" : { + + } + } + ], + "returnType" : { + "string" : { + + } + } + } + } + } + }, + { + "abiName" : "bjs_makeAdder", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeAdder", + "parameters" : [ + { + "label" : "base", + "name" : "base", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "Int_To_Int", + "parameters" : [ + { + "int" : { + + } + } + ], + "returnType" : { + "int" : { + + } + } + } + } + } } ], "moduleName" : "BridgeJSRuntimeTests", diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 10c390af..f6e9cb85 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -707,7 +707,202 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { cd5.release(); testProtocolSupport(exports); + testClosureSupport(exports); } +/** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ +function testClosureSupport(exports) { + const upperTransform = (text) => text.toUpperCase(); + const processor = new exports.TextProcessor(upperTransform); + + assert.equal(processor.process("hello"), "HELLO"); + + 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.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); + 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"); + + const addDr = exports.makeFormatter("Dr."); + assert.equal(addDr("Ada"), "Dr. Ada"); + assert.equal(addDr("Grace"), "Dr. Grace"); + + const addProf = exports.makeFormatter("Prof."); + assert.equal(addProf("Hopper"), "Prof. Hopper"); + + const add10 = exports.makeAdder(10); + assert.equal(add10(5), 15); + assert.equal(add10(32), 42); + + const add100 = exports.makeAdder(100); + assert.equal(add100(23), 123); + + const storedTransform = processor.getTransform(); + assert.equal(storedTransform("hello"), "HELLO"); + assert.equal(storedTransform("world"), "WORLD"); + + 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]"); + greeterForFormatter.release(); + + const greeterCreator = exports.Greeter.makeCreator("Default"); + const createdG1 = greeterCreator("Alice"); + assert.equal(createdG1.name, "Alice"); + assert.equal(createdG1.greet(), "Hello, Alice!"); + const createdG2 = greeterCreator(""); + assert.equal(createdG2.name, "Default"); + assert.equal(createdG2.greet(), "Hello, Default!"); + createdG1.release(); + createdG2.release(); + + const greeterHost = new exports.Greeter("Host"); + const greeterGreeter = greeterHost.makeCustomGreeter(); + const guest1 = new exports.Greeter("Guest1"); + const guest2 = new exports.Greeter("Guest2"); + assert.equal(greeterGreeter(guest1), "Host greets Guest1: Hello, Guest1!"); + assert.equal(greeterGreeter(guest2), "Host greets Guest2: Hello, Guest2!"); + greeterHost.release(); + guest1.release(); + guest2.release(); + + const greeterForMethod = new exports.Greeter("Method"); + const greeterParam = new exports.Greeter("Param"); + const methodResult = greeterForMethod.greetWith(greeterParam, (g) => { + return `Custom: ${g.name} says ${g.greet()}`; + }); + assert.equal(methodResult, "Custom: Param says Hello, Param!"); + greeterForMethod.release(); + greeterParam.release(); + + const optResult1 = processor.processOptionalString((value) => { + return value !== null ? `Got: ${value}` : `Got: null`; + }); + assert.equal(optResult1, "Got: test | Got: null"); + + const optResult2 = processor.processOptionalInt((value) => { + return value !== null ? `Number: ${value}` : `Number: null`; + }); + assert.equal(optResult2, "Number: 42 | Number: null"); + + const optResult3 = processor.processOptionalGreeter((greeter) => { + return greeter !== null ? `Greeter: ${greeter.name}` : `Greeter: null`; + }); + assert.equal(optResult3, "Greeter: Alice | Greeter: null"); + + const optFormatter = processor.makeOptionalStringFormatter(); + assert.equal(optFormatter("world"), "Got: world"); + assert.equal(optFormatter(null), "Got: nil"); + + const optCreator = processor.makeOptionalGreeterCreator(); + const opt1 = optCreator(); + assert.equal(opt1, null); + const opt2 = optCreator(); + assert.notEqual(opt2, null); + assert.equal(opt2.name, "Greeter2"); + assert.equal(opt2.greet(), "Hello, Greeter2!"); + opt2.release(); + const opt3 = optCreator(); + assert.equal(opt3, null); + const opt4 = optCreator(); + assert.notEqual(opt4, null); + assert.equal(opt4.name, "Greeter4"); + opt4.release(); + + 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"; + } + }); + assert.equal(dirResult, "Going North"); + + const themeResult = processor.processTheme((theme) => { + return theme === exports.Theme.Dark ? "Dark mode" : "Light mode"; + }); + assert.equal(themeResult, "Dark mode"); + + const statusResult = processor.processHttpStatus((status) => { + return status; + }); + assert.equal(statusResult, exports.HttpStatus.Ok); + + const apiResult = processor.processAPIResult((result) => { + if (result.tag === exports.APIResult.Tag.Success) { + return `API Success: ${result.param0}`; + } + return "API Other"; + }); + assert.equal(apiResult, "API Success: test"); + + const dirChecker = processor.makeDirectionChecker(); + assert.equal(dirChecker(exports.Direction.North), true); + assert.equal(dirChecker(exports.Direction.South), true); + assert.equal(dirChecker(exports.Direction.East), false); + assert.equal(dirChecker(exports.Direction.West), false); + + const themeValidator = processor.makeThemeValidator(); + assert.equal(themeValidator(exports.Theme.Dark), true); + assert.equal(themeValidator(exports.Theme.Light), false); + assert.equal(themeValidator(exports.Theme.Auto), false); + + const statusExtractor = processor.makeStatusCodeExtractor(); + assert.equal(statusExtractor(exports.HttpStatus.Ok), 200); + assert.equal(statusExtractor(exports.HttpStatus.NotFound), 404); + assert.equal(statusExtractor(exports.HttpStatus.ServerError), 500); + 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.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"); + + const optDirResult = processor.processOptionalDirection((dir) => { + return dir !== null ? `Dir: ${dir}` : "Dir: null"; + }); + assert.equal(optDirResult, `Dir: ${exports.Direction.North} | Dir: null`); + + const optThemeResult = processor.processOptionalTheme((theme) => { + return theme !== null ? `Theme: ${theme}` : "Theme: null"; + }); + assert.equal(optThemeResult, `Theme: ${exports.Theme.Light} | Theme: null`); + + const optApiResult = processor.processOptionalAPIResult((result) => { + if (result === null) return "Result: null"; + if (result.tag === exports.APIResult.Tag.Success) { + return `Result: Success(${result.param0})`; + } + return "Result: other"; + }); + assert.equal(optApiResult, "Result: Success(ok) | Result: null"); + + const optDirFormatter = processor.makeOptionalDirectionFormatter(); + assert.equal(optDirFormatter(exports.Direction.North), "N"); + assert.equal(optDirFormatter(exports.Direction.South), "S"); + assert.equal(optDirFormatter(exports.Direction.East), "E"); + assert.equal(optDirFormatter(exports.Direction.West), "W"); + assert.equal(optDirFormatter(null), "nil"); + + processor.release(); +} + /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ async function BridgeJSRuntimeTests_runAsyncWorks(exports) {