From f0b865211bf0ca5d9dd3a85ba6670ee9a060f07a Mon Sep 17 00:00:00 2001 From: William Taylor Date: Fri, 6 Mar 2026 14:03:33 +1100 Subject: [PATCH] BridgeJS: Correctly emit @JS methods in extensions --- .../BridgeJSCore/SwiftToSkeleton.swift | 60 +++++++++++++- .../BridgeJSCodegenTests.swift | 18 ++++ .../Multifile/CrossFileExtension.swift | 5 ++ .../Multifile/CrossFileExtensionClass.swift | 4 + .../Inputs/MacroSwift/StaticFunctions.swift | 12 +++ .../Inputs/MacroSwift/SwiftClass.swift | 6 ++ .../Inputs/MacroSwift/SwiftStruct.swift | 6 ++ .../CrossFileExtension.json | 82 +++++++++++++++++++ .../CrossFileExtension.swift | 60 ++++++++++++++ .../StaticFunctions.Global.json | 69 ++++++++++++++++ .../StaticFunctions.Global.swift | 22 +++++ .../BridgeJSCodegenTests/StaticFunctions.json | 69 ++++++++++++++++ .../StaticFunctions.swift | 22 +++++ .../BridgeJSCodegenTests/SwiftClass.json | 17 ++++ .../BridgeJSCodegenTests/SwiftClass.swift | 11 +++ .../BridgeJSCodegenTests/SwiftStruct.json | 16 ++++ .../BridgeJSCodegenTests/SwiftStruct.swift | 11 +++ .../BridgeJSLinkTests/SwiftClass.d.ts | 1 + .../BridgeJSLinkTests/SwiftClass.js | 6 ++ 19 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 8f1b3fa35..2ff5cecba 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -43,12 +43,14 @@ public final class SwiftToSkeleton { var perSourceErrors: [(inputFilePath: String, errors: [DiagnosticError])] = [] var importedFiles: [ImportedFileSkeleton] = [] var exported = ExportedSkeleton(functions: [], classes: [], enums: [], exposeToGlobal: exposeToGlobal) + var exportCollectors: [ExportSwiftAPICollector] = [] for (sourceFile, inputFilePath) in sourceFiles { progress.print("Processing \(inputFilePath)") let exportCollector = ExportSwiftAPICollector(parent: self) exportCollector.walk(sourceFile) + exportCollectors.append(exportCollector) let typeNameCollector = ImportSwiftMacrosJSImportTypeNameCollector(viewMode: .sourceAccurate) typeNameCollector.walk(sourceFile) @@ -74,7 +76,15 @@ public final class SwiftToSkeleton { if !importedFile.isEmpty { importedFiles.append(importedFile) } - exportCollector.finalize(&exported) + } + + // Resolve extensions against all collectors. This needs to happen at this point so we can resolve both same file and cross file extensions. + for source in exportCollectors { + source.resolveDeferredExtensions(against: exportCollectors) + } + + for collector in exportCollectors { + collector.finalize(&exported) } if !perSourceErrors.isEmpty { @@ -486,6 +496,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { var exportedStructNames: [String] = [] var exportedStructByName: [String: ExportedStruct] = [:] var errors: [DiagnosticError] = [] + /// Extensions collected during the walk, to be resolved after all files have been walked + var deferredExtensions: [ExtensionDeclSyntax] = [] func finalize(_ result: inout ExportedSkeleton) { result.functions.append(contentsOf: exportedFunctions) @@ -1388,6 +1400,52 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } + override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + // Defer until all type declarations in the module have been collected. + deferredExtensions.append(node) + return .skipChildren + } + + func resolveDeferredExtensions(against collectors: [ExportSwiftAPICollector]) { + for ext in deferredExtensions { + var resolved = false + for collector in collectors { + if collector.resolveExtension(ext) { + resolved = true + break + } + } + if !resolved { + diagnose( + node: ext.extendedType, + message: "Unsupported type '\(ext.extendedType.trimmedDescription)'.", + hint: "You can only extend `@JS` annotated types defined in the same module" + ) + } + } + } + + /// Walks extension members under the matching type’s state, returning whether the type was found + func resolveExtension(_ ext: ExtensionDeclSyntax) -> Bool { + let name = ext.extendedType.trimmedDescription + let state: State + if let entry = exportedClassByName.first(where: { $0.value.name == name }) { + state = .classBody(name: name, key: entry.key) + } else if let entry = exportedStructByName.first(where: { $0.value.name == name }) { + state = .structBody(name: name, key: entry.key) + } else if let entry = exportedEnumByName.first(where: { $0.value.name == name }) { + state = .enumBody(name: name, key: entry.key) + } else { + return false + } + stateStack.push(state: state) + for member in ext.memberBlock.members { + walk(member) + } + stateStack.pop() + return true + } + override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index 9754fbced..1b1f95f76 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -167,6 +167,24 @@ import Testing try snapshotCodegen(skeleton: skeleton, name: "CrossFileFunctionTypes.ReverseOrder") } + @Test + func codegenCrossFileExtension() throws { + let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) + let classURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtensionClass.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: classURL, encoding: .utf8)), + inputFilePath: "CrossFileExtensionClass.swift" + ) + let extensionURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtension.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: extensionURL, encoding: .utf8)), + inputFilePath: "CrossFileExtension.swift" + ) + let skeleton = try swiftAPI.finalize() + try snapshotCodegen(skeleton: skeleton, name: "CrossFileExtension") + } + + @Test func codegenSkipsEmptySkeletons() throws { let swiftAPI = SwiftToSkeleton(progress: .silent, moduleName: "TestModule", exposeToGlobal: false) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift new file mode 100644 index 000000000..ce9e8e2b0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtension.swift @@ -0,0 +1,5 @@ +extension Greeter { + @JS func greetFormally() -> String { + return "Good day, " + self.name + "." + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift new file mode 100644 index 000000000..48625d42a --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionClass.swift @@ -0,0 +1,4 @@ +@JS class Greeter { + @JS init(name: String) {} + @JS func greet() -> String { return "" } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift index 1d42cf415..25196d773 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift @@ -38,3 +38,15 @@ enum APIResult { } } } + +extension MathUtils { + @JS static func divide(a: Int, b: Int) -> Int { + return a / b + } +} + +extension Calculator { + @JS static func cube(value: Int) -> Int { + return value * value * value + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift index d7b5a5b8e..12004ffa8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift @@ -12,6 +12,12 @@ } } +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, " + self.name + "!!!" + } +} + @JS func takeGreeter(greeter: Greeter) { print(greeter.greet()) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift index 0d84f4736..d42b2e202 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift @@ -60,3 +60,9 @@ } @JS func roundtripContainer(_ container: Container) -> Container + +extension DataPoint { + @JS func distanceFromOrigin() -> Double { + return (x * x + y * y).squareRoot() + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json new file mode 100644 index 000000000..f77d39ad9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.json @@ -0,0 +1,82 @@ +{ + "exported" : { + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Greeter_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Greeter_greet", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greet", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_greetFormally", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetFormally", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Greeter", + "properties" : [ + + ], + "swiftCallName" : "Greeter" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule" +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift new file mode 100644 index 000000000..ab73df508 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtension.swift @@ -0,0 +1,60 @@ +@_expose(wasm, "bjs_Greeter_init") +@_cdecl("bjs_Greeter_init") +public func _bjs_Greeter_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Greeter(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_greet") +@_cdecl("bjs_Greeter_greet") +public func _bjs_Greeter_greet(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greet() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_greetFormally") +@_cdecl("bjs_Greeter_greetFormally") +public func _bjs_Greeter_greetFormally(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetFormally() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_deinit") +@_cdecl("bjs_Greeter_deinit") +public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Greeter: ConvertibleToJSValue, _BridgedSwiftHeapObject { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Greeter_wrap(Unmanaged.passRetained(self).toOpaque())))) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Greeter_wrap") +fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Greeter_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Greeter_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Greeter_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json index b0eac3313..a5fc4e7e1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -125,6 +125,45 @@ } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "int" : { + + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", @@ -182,6 +221,36 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index b6d35a215..3478eb883 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -44,6 +44,17 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +145,17 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index e4ec22855..b620fb0e2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -125,6 +125,45 @@ } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "int" : { + + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", @@ -182,6 +221,36 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index b6d35a215..3478eb883 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -44,6 +44,17 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +145,17 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index 7cebdd5e6..0245bf208 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -61,6 +61,23 @@ "returnType" : { "void" : { + } + } + }, + { + "abiName" : "bjs_Greeter_greetEnthusiastically", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetEnthusiastically", + "parameters" : [ + + ], + "returnType" : { + "string" : { + } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index 0e9434832..9f927da13 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -40,6 +40,17 @@ public func _bjs_Greeter_changeName(_ _self: UnsafeMutableRawPointer, _ nameByte #endif } +@_expose(wasm, "bjs_Greeter_greetEnthusiastically") +@_cdecl("bjs_Greeter_greetEnthusiastically") +public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 00c6af5cb..d216f10c6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -211,7 +211,23 @@ ] }, "methods" : [ + { + "abiName" : "bjs_DataPoint_distanceFromOrigin", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "distanceFromOrigin", + "parameters" : [ + ], + "returnType" : { + "double" : { + + } + } + } ], "name" : "DataPoint", "properties" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 6fccb3280..5e867f179 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -66,6 +66,17 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_distanceFromOrigin") +@_cdecl("bjs_DataPoint_distanceFromOrigin") +public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { + #if arch(wasm32) + let ret = DataPoint.bridgeJSLiftParameter().distanceFromOrigin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Address { let zipCode = Optional.bridgeJSStackPop() diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 05fc97fee..72f816bd5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -14,6 +14,7 @@ export interface SwiftHeapObject { export interface Greeter extends SwiftHeapObject { greet(): string; changeName(name: string): void; + greetEnthusiastically(): string; name: string; } export interface PublicGreeter extends SwiftHeapObject { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index a74d49327..fb29cf8c0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -283,6 +283,12 @@ export async function createInstantiator(options, swift) { const nameId = swift.memory.retain(nameBytes); instance.exports.bjs_Greeter_changeName(this.pointer, nameId, nameBytes.length); } + greetEnthusiastically() { + instance.exports.bjs_Greeter_greetEnthusiastically(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } get name() { instance.exports.bjs_Greeter_name_get(this.pointer); const ret = tmpRetString;