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..4f6296d2e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/StaticFunctions.swift @@ -38,3 +38,19 @@ enum APIResult { } } } + +extension MathUtils { + @JS static func divide(a: Int, b: Int) -> Int { + return a / b + } + + @JS static var pi: Double { 3.14159 } +} + +extension Calculator { + @JS static func cube(value: Int) -> Int { + return value * value * value + } + + @JS static var version: String { "1.0" } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift index d7b5a5b8e..2fb050eeb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftClass.swift @@ -12,6 +12,20 @@ } } +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, " + self.name + "!!!" + } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } +} + @JS func takeGreeter(greeter: Greeter) { print(greeter.greet()) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift index 0d84f4736..4ec6525e3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/SwiftStruct.swift @@ -60,3 +60,15 @@ } @JS func roundtripContainer(_ container: Container) -> Container + +extension DataPoint { + @JS func distanceFromOrigin() -> Double { + return (x * x + y * y).squareRoot() + } + + @JS static func origin() -> DataPoint { + return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) + } + + @JS static var dimensions: Int { 2 } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/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..3e07317ac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.json @@ -125,11 +125,64 @@ } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "int" : { + + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "pi", + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + }, + "type" : { + "double" : { + } + } + } ], "swiftCallName" : "MathUtils" } @@ -182,10 +235,54 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift index b6d35a215..aa7af111f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.Global.swift @@ -44,6 +44,28 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Calculator_static_version_get") +@_cdecl("bjs_Calculator_static_version_get") +public func _bjs_Calculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = Calculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +156,28 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_MathUtils_static_pi_get") +@_cdecl("bjs_MathUtils_static_pi_get") +public func _bjs_MathUtils_static_pi_get() -> Float64 { + #if arch(wasm32) + let ret = MathUtils.pi + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json index e4ec22855..a6540015f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.json @@ -125,11 +125,64 @@ } } + }, + { + "abiName" : "bjs_MathUtils_static_divide", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "divide", + "parameters" : [ + { + "label" : "a", + "name" : "a", + "type" : { + "int" : { + + } + } + }, + { + "label" : "b", + "name" : "b", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + } } ], "name" : "MathUtils", "properties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "pi", + "staticContext" : { + "className" : { + "_0" : "MathUtils" + } + }, + "type" : { + "double" : { + } + } + } ], "swiftCallName" : "MathUtils" } @@ -182,10 +235,54 @@ "_0" : "Calculator" } } + }, + { + "abiName" : "bjs_Calculator_static_cube", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "cube", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + } } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "Calculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "Calculator", "tsFullPath" : "Calculator" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift index b6d35a215..aa7af111f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/StaticFunctions.swift @@ -44,6 +44,28 @@ public func _bjs_Calculator_static_square(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_Calculator_static_cube") +@_cdecl("bjs_Calculator_static_cube") +public func _bjs_Calculator_static_cube(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = Calculator.cube(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Calculator_static_version_get") +@_cdecl("bjs_Calculator_static_version_get") +public func _bjs_Calculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = Calculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension APIResult: _BridgedSwiftAssociatedValueEnum { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> APIResult { switch caseId { @@ -134,6 +156,28 @@ public func _bjs_MathUtils_multiply(_ _self: UnsafeMutableRawPointer, _ x: Int32 #endif } +@_expose(wasm, "bjs_MathUtils_static_divide") +@_cdecl("bjs_MathUtils_static_divide") +public func _bjs_MathUtils_static_divide(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = MathUtils.divide(a: Int.bridgeJSLiftParameter(a), b: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_MathUtils_static_pi_get") +@_cdecl("bjs_MathUtils_static_pi_get") +public func _bjs_MathUtils_static_pi_get() -> Float64 { + #if arch(wasm32) + let ret = MathUtils.pi + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MathUtils_deinit") @_cdecl("bjs_MathUtils_deinit") public func _bjs_MathUtils_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json index 7cebdd5e6..cf5156d8d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.json @@ -63,6 +63,45 @@ } } + }, + { + "abiName" : "bjs_Greeter_greetEnthusiastically", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetEnthusiastically", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_static_greetAnonymously", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "greetAnonymously", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + } } ], "name" : "Greeter", @@ -74,6 +113,31 @@ "type" : { "string" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "nameCount", + "type" : { + "int" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + }, + "type" : { + "string" : { + } } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift index 0e9434832..cb61e263d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClass.swift @@ -40,6 +40,28 @@ public func _bjs_Greeter_changeName(_ _self: UnsafeMutableRawPointer, _ nameByte #endif } +@_expose(wasm, "bjs_Greeter_greetEnthusiastically") +@_cdecl("bjs_Greeter_greetEnthusiastically") +public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_greetAnonymously") +@_cdecl("bjs_Greeter_static_greetAnonymously") +public func _bjs_Greeter_static_greetAnonymously() -> Void { + #if arch(wasm32) + let ret = Greeter.greetAnonymously() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -61,6 +83,28 @@ public func _bjs_Greeter_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes #endif } +@_expose(wasm, "bjs_Greeter_nameCount_get") +@_cdecl("bjs_Greeter_nameCount_get") +public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).nameCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") +@_cdecl("bjs_Greeter_static_defaultGreeting_get") +public func _bjs_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json index 00c6af5cb..7a6421668 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.json @@ -211,7 +211,45 @@ ] }, "methods" : [ + { + "abiName" : "bjs_DataPoint_distanceFromOrigin", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "distanceFromOrigin", + "parameters" : [ + + ], + "returnType" : { + "double" : { + } + } + }, + { + "abiName" : "bjs_DataPoint_static_origin", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "origin", + "parameters" : [ + + ], + "returnType" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + } + } ], "name" : "DataPoint", "properties" : [ @@ -274,6 +312,21 @@ "_1" : "null" } } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "dimensions", + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + }, + "type" : { + "int" : { + + } + } } ], "swiftCallName" : "DataPoint" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift index 6fccb3280..5e17b6db2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStruct.swift @@ -66,6 +66,39 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_static_dimensions_get") +@_cdecl("bjs_DataPoint_static_dimensions_get") +public func _bjs_DataPoint_static_dimensions_get() -> Int32 { + #if arch(wasm32) + let ret = DataPoint.dimensions + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_distanceFromOrigin") +@_cdecl("bjs_DataPoint_distanceFromOrigin") +public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { + #if arch(wasm32) + let ret = DataPoint.bridgeJSLiftParameter().distanceFromOrigin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_static_origin") +@_cdecl("bjs_DataPoint_static_origin") +public func _bjs_DataPoint_static_origin() -> Void { + #if arch(wasm32) + let ret = DataPoint.origin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension Address: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Address { let zipCode = Optional.bridgeJSStackPop() diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts index a2f1c7d6d..5916e1648 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.d.ts @@ -22,6 +22,8 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; + cube(value: number): number; + readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -53,6 +55,8 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; + divide(a: number, b: number): number; + readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index 800b07107..df2a34ff1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -297,6 +297,14 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } + static divide(a, b) { + const ret = instance.exports.bjs_MathUtils_static_divide(a, b); + return ret; + } + static get pi() { + const ret = instance.exports.bjs_MathUtils_static_pi_get(); + return ret; + } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -314,6 +322,16 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; + }, + cube: function(value) { + const ret = instance.exports.bjs_Calculator_static_cube(value); + return ret; + }, + get version() { + instance.exports.bjs_Calculator_static_version_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts index e938ddb9a..c9cb26910 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.d.ts @@ -22,6 +22,8 @@ export type APIResultTag = export type CalculatorObject = typeof CalculatorValues & { square(value: number): number; + cube(value: number): number; + readonly version: string; }; export type APIResultObject = typeof APIResultValues & { @@ -43,6 +45,8 @@ export type Exports = { new(): MathUtils; subtract(a: number, b: number): number; add(a: number, b: number): number; + divide(a: number, b: number): number; + readonly pi: number; } Calculator: CalculatorObject APIResult: APIResultObject diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index a4290f828..2e5b6e7f1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -297,6 +297,14 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MathUtils_multiply(this.pointer, x, y); return ret; } + static divide(a, b) { + const ret = instance.exports.bjs_MathUtils_static_divide(a, b); + return ret; + } + static get pi() { + const ret = instance.exports.bjs_MathUtils_static_pi_get(); + return ret; + } } const APIResultHelpers = __bjs_createAPIResultValuesHelpers(); enumHelpers.APIResult = APIResultHelpers; @@ -308,6 +316,16 @@ export async function createInstantiator(options, swift) { square: function(value) { const ret = instance.exports.bjs_Calculator_static_square(value); return ret; + }, + cube: function(value) { + const ret = instance.exports.bjs_Calculator_static_cube(value); + return ret; + }, + get version() { + instance.exports.bjs_Calculator_static_version_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; } }, APIResult: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts index 05fc97fee..6d590950c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.d.ts @@ -14,7 +14,9 @@ export interface SwiftHeapObject { export interface Greeter extends SwiftHeapObject { greet(): string; changeName(name: string): void; + greetEnthusiastically(): string; name: string; + readonly nameCount: number; } export interface PublicGreeter extends SwiftHeapObject { } @@ -23,6 +25,8 @@ export interface PackageGreeter extends SwiftHeapObject { export type Exports = { Greeter: { new(name: string): Greeter; + greetAnonymously(): string; + readonly defaultGreeting: string; } PublicGreeter: { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 9acf70de2..f6293f12a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -282,6 +282,18 @@ export async function createInstantiator(options, swift) { const nameId = swift.memory.retain(nameBytes); instance.exports.bjs_Greeter_changeName(this.pointer, nameId, nameBytes.length); } + greetEnthusiastically() { + instance.exports.bjs_Greeter_greetEnthusiastically(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + static greetAnonymously() { + instance.exports.bjs_Greeter_static_greetAnonymously(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } get name() { instance.exports.bjs_Greeter_name_get(this.pointer); const ret = tmpRetString; @@ -293,6 +305,16 @@ export async function createInstantiator(options, swift) { const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } + get nameCount() { + const ret = instance.exports.bjs_Greeter_nameCount_get(this.pointer); + return ret; + } + static get defaultGreeting() { + instance.exports.bjs_Greeter_static_defaultGreeting_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } } class PublicGreeter extends SwiftHeapObject { static __construct(ptr) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts index 4a61a26e3..211661d5f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.d.ts @@ -16,6 +16,7 @@ export interface DataPoint { label: string; optCount: number | null; optFlag: boolean | null; + distanceFromOrigin(): number; } export interface Address { street: string; @@ -65,6 +66,8 @@ export type Exports = { Precision: PrecisionObject DataPoint: { init(x: number, y: number, label: string, optCount: number | null, optFlag: boolean | null): DataPoint; + readonly dimensions: number; + origin(): DataPoint; } ConfigStruct: { readonly maxRetries: number; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index cd2d396df..099f4ccc3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -73,7 +73,13 @@ export async function createInstantiator(options, swift) { const string = strStack.pop(); const f64 = f64Stack.pop(); const f641 = f64Stack.pop(); - return { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; + const instance1 = { x: f641, y: f64, label: string, optCount: optValue1, optFlag: optValue }; + instance1.distanceFromOrigin = function() { + structHelpers.DataPoint.lower(this); + const ret = instance.exports.bjs_DataPoint_distanceFromOrigin(); + return ret; + }.bind(instance1); + return instance1; } }); const __bjs_createAddressHelpers = () => ({ @@ -546,6 +552,15 @@ export async function createInstantiator(options, swift) { const structValue = structHelpers.DataPoint.lift(); return structValue; }, + get dimensions() { + const ret = instance.exports.bjs_DataPoint_static_dimensions_get(); + return ret; + }, + origin: function() { + instance.exports.bjs_DataPoint_static_origin(); + const structValue = structHelpers.DataPoint.lift(); + return structValue; + }, }, ConfigStruct: { get maxRetries() { diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index c8ebbc8ce..6997cfd3b 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -150,6 +150,20 @@ struct TestError: Error { } } +extension Greeter { + @JS func greetEnthusiastically() -> String { + return "Hey, \(name)!!!" + } + + @JS var nameCount: Int { name.count } + + @JS static func greetAnonymously() -> String { + return "Hello." + } + + @JS static var defaultGreeting: String { "Hello, world!" } +} + @JS func takeGreeter(g: Greeter, name: String) { g.changeName(name: name) } @@ -250,6 +264,14 @@ struct TestError: Error { case auto = "auto" } +extension StaticCalculator { + @JS static func doubleValue(_ value: Int) -> Int { + return value * 2 + } + + @JS static var version: String { "1.0" } +} + @JS func setDirection(_ direction: Direction) -> Direction { return direction } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 13aab1455..cde1afc59 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -3418,6 +3418,28 @@ public func _bjs_StaticCalculator_static_roundtrip(_ value: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_StaticCalculator_static_doubleValue") +@_cdecl("bjs_StaticCalculator_static_doubleValue") +public func _bjs_StaticCalculator_static_doubleValue(_ value: Int32) -> Int32 { + #if arch(wasm32) + let ret = StaticCalculator.doubleValue(_: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_StaticCalculator_static_version_get") +@_cdecl("bjs_StaticCalculator_static_version_get") +public func _bjs_StaticCalculator_static_version_get() -> Void { + #if arch(wasm32) + let ret = StaticCalculator.version + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_StaticUtils_Nested_static_roundtrip") @_cdecl("bjs_StaticUtils_Nested_static_roundtrip") public func _bjs_StaticUtils_Nested_static_roundtrip(_ valueBytes: Int32, _ valueLength: Int32) -> Void { @@ -4233,6 +4255,39 @@ public func _bjs_DataPoint_init(_ x: Float64, _ y: Float64, _ labelBytes: Int32, #endif } +@_expose(wasm, "bjs_DataPoint_static_dimensions_get") +@_cdecl("bjs_DataPoint_static_dimensions_get") +public func _bjs_DataPoint_static_dimensions_get() -> Int32 { + #if arch(wasm32) + let ret = DataPoint.dimensions + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_distanceFromOrigin") +@_cdecl("bjs_DataPoint_distanceFromOrigin") +public func _bjs_DataPoint_distanceFromOrigin() -> Float64 { + #if arch(wasm32) + let ret = DataPoint.bridgeJSLiftParameter().distanceFromOrigin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataPoint_static_origin") +@_cdecl("bjs_DataPoint_static_origin") +public func _bjs_DataPoint_static_origin() -> Void { + #if arch(wasm32) + let ret = DataPoint.origin() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension PublicPoint: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PublicPoint { let y = Int.bridgeJSStackPop() @@ -6934,6 +6989,28 @@ public func _bjs_Greeter_makeCustomGreeter(_ _self: UnsafeMutableRawPointer) -> #endif } +@_expose(wasm, "bjs_Greeter_greetEnthusiastically") +@_cdecl("bjs_Greeter_greetEnthusiastically") +public func _bjs_Greeter_greetEnthusiastically(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).greetEnthusiastically() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_greetAnonymously") +@_cdecl("bjs_Greeter_static_greetAnonymously") +public func _bjs_Greeter_static_greetAnonymously() -> Void { + #if arch(wasm32) + let ret = Greeter.greetAnonymously() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_name_get") @_cdecl("bjs_Greeter_name_get") public func _bjs_Greeter_name_get(_ _self: UnsafeMutableRawPointer) -> Void { @@ -6966,6 +7043,28 @@ public func _bjs_Greeter_prefix_get(_ _self: UnsafeMutableRawPointer) -> Void { #endif } +@_expose(wasm, "bjs_Greeter_nameCount_get") +@_cdecl("bjs_Greeter_nameCount_get") +public func _bjs_Greeter_nameCount_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = Greeter.bridgeJSLiftParameter(_self).nameCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Greeter_static_defaultGreeting_get") +@_cdecl("bjs_Greeter_static_defaultGreeting_get") +public func _bjs_Greeter_static_defaultGreeting_get() -> Void { + #if arch(wasm32) + let ret = Greeter.defaultGreeting + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Greeter_deinit") @_cdecl("bjs_Greeter_deinit") public func _bjs_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 746e0cd3c..137fb6087 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -705,6 +705,45 @@ "useJSTypedClosure" : false } } + }, + { + "abiName" : "bjs_Greeter_greetEnthusiastically", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "greetEnthusiastically", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Greeter_static_greetAnonymously", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "greetAnonymously", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + }, + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + } } ], "name" : "Greeter", @@ -726,6 +765,31 @@ "type" : { "string" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "nameCount", + "type" : { + "int" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "defaultGreeting", + "staticContext" : { + "className" : { + "_0" : "Greeter" + } + }, + "type" : { + "string" : { + } } } @@ -7620,10 +7684,54 @@ "_0" : "StaticCalculator" } } + }, + { + "abiName" : "bjs_StaticCalculator_static_doubleValue", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "doubleValue", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "returnType" : { + "int" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "StaticCalculator" + } + } } ], "staticProperties" : [ + { + "isReadonly" : true, + "isStatic" : true, + "name" : "version", + "staticContext" : { + "enumName" : { + "_0" : "StaticCalculator" + } + }, + "type" : { + "string" : { + } + } + } ], "swiftCallName" : "StaticCalculator", "tsFullPath" : "StaticCalculator" @@ -13342,7 +13450,45 @@ ] }, "methods" : [ + { + "abiName" : "bjs_DataPoint_distanceFromOrigin", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "distanceFromOrigin", + "parameters" : [ + + ], + "returnType" : { + "double" : { + } + } + }, + { + "abiName" : "bjs_DataPoint_static_origin", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "name" : "origin", + "parameters" : [ + + ], + "returnType" : { + "swiftStruct" : { + "_0" : "DataPoint" + } + }, + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + } + } ], "name" : "DataPoint", "properties" : [ @@ -13405,6 +13551,21 @@ "_1" : "null" } } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "dimensions", + "staticContext" : { + "structName" : { + "_0" : "DataPoint" + } + }, + "type" : { + "int" : { + + } + } } ], "swiftCallName" : "DataPoint" diff --git a/Tests/BridgeJSRuntimeTests/StructAPIs.swift b/Tests/BridgeJSRuntimeTests/StructAPIs.swift index 0a05a517d..af925cb77 100644 --- a/Tests/BridgeJSRuntimeTests/StructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/StructAPIs.swift @@ -174,6 +174,18 @@ import JavaScriptKit } } +extension DataPoint { + @JS func distanceFromOrigin() -> Double { + return (x * x + y * y).squareRoot() + } + + @JS static func origin() -> DataPoint { + return DataPoint(x: 0, y: 0, label: "origin", optCount: nil, optFlag: nil) + } + + @JS static var dimensions: Int { 2 } +} + @JS func roundTripDataPoint(_ data: DataPoint) -> DataPoint { return data } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 4c211e91c..94d33057d 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -269,6 +269,12 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(g.name, "Bob"); assert.equal(g.greet(), "Hello, Bob!"); + // Test class extension members + assert.equal(g.greetEnthusiastically(), "Hey, Bob!!!"); + assert.equal(g.nameCount, 3); + assert.equal(exports.Greeter.greetAnonymously(), "Hello."); + assert.equal(exports.Greeter.defaultGreeting, "Hello, world!"); + const g2 = exports.roundTripSwiftHeapObject(g) assert.equal(g2.greet(), "Hello, Bob!"); assert.equal(g2.name, "Bob"); @@ -761,6 +767,10 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(StaticCalculatorValues.Basic, 1); assert.equal(StaticCalculatorValues.Scientific, exports.StaticCalculator.Scientific); assert.equal(StaticCalculatorValues.Basic, exports.StaticCalculator.Basic); + + // Test enum extension static members + assert.equal(exports.StaticCalculator.doubleValue(21), 42); + assert.equal(exports.StaticCalculator.version, "1.0"); assert.equal(exports.StaticUtils.Nested.roundtrip("hello world"), "hello world"); assert.equal(exports.StaticUtils.Nested.roundtrip("test"), "test"); @@ -779,6 +789,15 @@ function testStructSupport(exports) { const data2 = { x: 0.0, y: 0.0, label: "", optCount: null, optFlag: null }; assert.deepEqual(exports.roundTripDataPoint(data2), data2); + // Test struct extension members + const data3 = { x: 3.0, y: 4.0, label: "Test", optCount: null, optFlag: null }; + assert.equal(exports.DataPoint.distanceFromOrigin(data3), 5.0); + const origin = exports.DataPoint.origin(); + assert.equal(origin.x, 0.0); + assert.equal(origin.y, 0.0); + assert.equal(origin.label, "origin"); + assert.equal(exports.DataPoint.dimensions, 2); + const publicPoint = { x: 9, y: -3 }; assert.deepEqual(exports.roundTripPublicPoint(publicPoint), publicPoint);