From 30d994d137395cb97bb460c2cfa67cbfcfe92496 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Tue, 11 Aug 2026 16:55:43 +1000 Subject: [PATCH 1/3] BridgeJS: Add runtime test for instance method String returns on a struct (#800) --- .../Generated/BridgeJS.swift | 11 +++++++++++ .../Generated/JavaScript/BridgeJS.json | 17 +++++++++++++++++ Tests/BridgeJSRuntimeTests/StructAPIs.swift | 4 ++++ Tests/prelude.mjs | 1 + 4 files changed, 33 insertions(+) diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index ad6f3fa24..c9db5b2ac 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -7861,6 +7861,17 @@ public func _bjs_Vector2D_scaled(_ factor: Float64) -> Void { #endif } +@_expose(wasm, "bjs_Vector2D_describe") +@_cdecl("bjs_Vector2D_describe") +public func _bjs_Vector2D_describe() -> Void { + #if arch(wasm32) + let ret = Vector2D.bridgeJSLiftParameter().describe() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension JSObjectContainer: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> JSObjectContainer { let optionalObject = Optional.bridgeJSStackPop() diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index e2a8575e1..c68d264e2 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -19680,6 +19680,23 @@ "_0" : "Vector2D" } } + }, + { + "abiName" : "bjs_Vector2D_describe", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describe", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } } ], "name" : "Vector2D", diff --git a/Tests/BridgeJSRuntimeTests/StructAPIs.swift b/Tests/BridgeJSRuntimeTests/StructAPIs.swift index c2216c808..e11856d41 100644 --- a/Tests/BridgeJSRuntimeTests/StructAPIs.swift +++ b/Tests/BridgeJSRuntimeTests/StructAPIs.swift @@ -200,6 +200,10 @@ extension Vector2D { @JS func scaled(by factor: Double) -> Vector2D { return Vector2D(dx: dx * factor, dy: dy * factor) } + + @JS func describe() -> String { + return "Vector2D(\(dx), \(dy))" + } } @JS func roundTripDataPoint(_ data: DataPoint) -> DataPoint { diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 42a0e3ea4..931d42561 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -871,6 +871,7 @@ function testStructSupport(exports) { const scaled = vec.scaled(2.0); assert.equal(scaled.dx, 6.0); assert.equal(scaled.dy, 8.0); + assert.equal(vec.describe(), "Vector2D(3.0, 4.0)"); const publicPoint = { x: 9, y: -3 }; assert.deepEqual(exports.roundTripPublicPoint(publicPoint), publicPoint); From e10836b71f0f270c8334e825e6920192e806dc6a Mon Sep 17 00:00:00 2001 From: William Taylor Date: Tue, 11 Aug 2026 16:57:06 +1000 Subject: [PATCH 2/3] BridgeJS: Export with a different JS name (#801) --- .../BridgeJSCore/SwiftToSkeleton.swift | 88 ++- .../Sources/BridgeJSLink/BridgeJSLink.swift | 122 ++-- .../ImportedJSModuleRegistry.swift | 6 +- .../Sources/BridgeJSLink/JSGlueGen.swift | 2 +- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 18 + .../BridgeJSToolTests/DiagnosticsTests.swift | 81 +++ .../Inputs/MacroSwift/JSNameOverride.swift | 40 ++ .../BridgeJSCodegenTests/JSNameOverride.json | 524 ++++++++++++++++++ .../BridgeJSCodegenTests/JSNameOverride.swift | 351 ++++++++++++ .../BridgeJSLinkTests/JSNameOverride.d.ts | 68 +++ .../BridgeJSLinkTests/JSNameOverride.js | 442 +++++++++++++++ .../Exporting-Swift-Function.md | 21 + Sources/JavaScriptKit/Macros.swift | 2 + .../Generated/BridgeJS.swift | 118 ++++ .../Generated/JavaScript/BridgeJS.json | 180 ++++++ Tests/BridgeJSRuntimeTests/JSNameAPIs.swift | 34 ++ Tests/prelude.mjs | 12 + 17 files changed, 2049 insertions(+), 60 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSNameOverride.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js create mode 100644 Tests/BridgeJSRuntimeTests/JSNameAPIs.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index d327de307..bfd639ee6 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -731,6 +731,23 @@ public final class SwiftToSkeleton { return String(name.dropFirst().dropLast()) } + fileprivate static func isValidJSIdentifier(_ name: String) -> Bool { + func isIdentifierPart(_ scalar: Unicode.Scalar, isStart: Bool) -> Bool { + switch scalar { + case "a"..."z", "A"..."Z", "_", "$": + return true + case "0"..."9": + return !isStart + default: + return false + } + } + guard let first = name.unicodeScalars.first, isIdentifierPart(first, isStart: true) else { + return false + } + return name.unicodeScalars.dropFirst().allSatisfy { isIdentifierPart($0, isStart: false) } + } + } private enum ExportSwiftConstants { @@ -1291,6 +1308,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } let name = node.name.text + let jsName = extractValidatedJSName(from: jsAttribute) let attributeNamespace = extractNamespace(from: jsAttribute) let computedNamespace = computeNamespace(for: node) @@ -1378,7 +1396,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { classNameForABI = nil } abiName = ABINameGenerator.generateABIName( - baseName: name, + baseName: jsName ?? name, namespace: finalNamespace, staticContext: isStatic ? staticContext : nil, className: classNameForABI @@ -1390,6 +1408,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return ExportedFunction( name: name, + jsName: jsName, abiName: abiName, parameters: parameters, returnType: returnType, @@ -1469,6 +1488,45 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return Effects(isAsync: isAsync, isThrows: isThrows, isStatic: isStatic) } + private func extractJSName( + from jsAttribute: AttributeSyntax + ) -> String? { + guard let arguments = jsAttribute.arguments?.as(LabeledExprListSyntax.self), + let nameArg = arguments.first, + nameArg.label == nil, + let stringLiteral = nameArg.expression.as(StringLiteralExprSyntax.self), + stringLiteral.segments.count == 1, + let name = stringLiteral.segments.first?.as(StringSegmentSyntax.self)?.content.text + else { + return nil + } + return name + } + + private func extractValidatedJSName( + from jsAttribute: AttributeSyntax + ) -> String? { + guard let jsName = extractJSName(from: jsAttribute) else { return nil } + guard SwiftToSkeleton.isValidJSIdentifier(jsName) else { + diagnose( + node: jsAttribute, + message: "`\(jsName)` is not a valid JavaScript identifier" + ) + return nil + } + return jsName + } + + private func diagnoseUnsupportedJSName( + from jsAttribute: AttributeSyntax + ) { + guard extractJSName(from: jsAttribute) != nil else { return } + diagnose( + node: jsAttribute, + message: "A separate name for JavaScript is not supported here" + ) + } + private func extractNamespace( from jsAttribute: AttributeSyntax ) -> [String]? { @@ -1515,6 +1573,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren } + diagnoseUnsupportedJSName(from: jsAttribute) + switch state { case .classBody(_, let classKey): if extractNamespace(from: jsAttribute) != nil { @@ -1636,6 +1696,15 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } + let jsName = extractValidatedJSName(from: jsAttribute) + if jsName != nil, node.bindings.count > 1 { + diagnose( + node: jsAttribute, + message: "Name targets declaration with multiple bindings", + hint: "Declare each property with a different JS name separately" + ) + } + // Process each binding (variable declaration) for binding in node.bindings { guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { @@ -1663,6 +1732,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { let exportedProperty = ExportedProperty( name: propertyName, + jsName: jsName, type: propertyType, isReadonly: isReadonly, isStatic: isStatic, @@ -1693,6 +1763,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return .skipChildren } + diagnoseUnsupportedJSName(from: jsAttribute) + if let aliasTarget = parent.extractAliasTarget(from: jsAttribute) { recordAlias(node: node, jsAttribute: jsAttribute, aliasTarget: aliasTarget) return .skipChildren @@ -1843,6 +1915,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return .skipChildren } + diagnoseUnsupportedJSName(from: jsAttribute) + if let aliasTarget = parent.extractAliasTarget(from: jsAttribute) { recordAlias(node: node, jsAttribute: jsAttribute, aliasTarget: aliasTarget) return .skipChildren @@ -1968,6 +2042,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return .skipChildren } + diagnoseUnsupportedJSName(from: jsAttribute) + let name = node.name.text let namespaceResult = resolveNamespace(from: jsAttribute, for: node, declarationType: "protocol") @@ -2031,6 +2107,8 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return .skipChildren } + diagnoseUnsupportedJSName(from: jsAttribute) + if let aliasTarget = parent.extractAliasTarget(from: jsAttribute) { recordAlias(node: node, jsAttribute: jsAttribute, aliasTarget: aliasTarget) return .skipChildren @@ -2169,6 +2247,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { protocolName: String, namespace: [String]? ) -> ExportedFunction? { + if let jsAttribute = node.attributes.firstJSAttribute { + diagnoseUnsupportedJSName(from: jsAttribute) + } + let name = node.name.text let parameters = parseParameters(from: node.signature.parameterClause, allowDefaults: false) @@ -2215,6 +2297,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { protocolName: String, protocolKey: String ) -> SyntaxVisitorContinueKind { + if let jsAttribute = node.attributes.firstJSAttribute { + diagnoseUnsupportedJSName(from: jsAttribute) + } + for binding in node.bindings { guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { diagnose(node: binding.pattern, message: "Complex patterns not supported for protocol properties") diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 1b6300595..6043f3cd1 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -235,7 +235,7 @@ public struct BridgeJSLink { for function in skeleton.functions { if function.namespace == nil { var (js, dts) = try renderExportedFunction(function: function) - js[0] = "\(function.name): " + js[0] + js[0] = "\(function.resolvedJSName): " + js[0] js[js.count - 1] += "," data.exportsLines.append(contentsOf: js) data.dtsExportLines.append(contentsOf: dts) @@ -973,13 +973,15 @@ public struct BridgeJSLink { ) ) printer.write( - "\(function.name)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + "\(function.resolvedJSName)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ) } for property in enumDefinition.staticProperties { let readonly = property.isReadonly ? "readonly " : "" printer.write(lines: renderJSDoc(documentation: property.documentation, parameters: [])) - printer.write("\(readonly)\(property.name): \(resolveTypeScriptType(property.type));") + printer.write( + "\(readonly)\(property.resolvedJSName): \(resolveTypeScriptType(property.type));" + ) } } printer.write("};") @@ -1025,13 +1027,13 @@ public struct BridgeJSLink { renderFunctionEntry: { function in self.renderJSDoc(documentation: function.documentation, parameters: function.parameters) + [ - "\(function.name)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + "\(function.resolvedJSName)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ] }, renderPropertyEntry: { property in let readonly = property.isReadonly ? "readonly " : "" return self.renderJSDoc(documentation: property.documentation, parameters: []) - + ["\(readonly)\(property.name): \(property.type.tsType);"] + + ["\(readonly)\(property.resolvedJSName): \(property.type.tsType);"] } ) printer.write("export type Exports = {") @@ -1370,7 +1372,7 @@ public struct BridgeJSLink { // Add methods for method in type.methods { - let methodName = method.jsName ?? method.name + let methodName = method.resolvedJSName let methodSignature = "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" printer.write(methodSignature) @@ -1379,9 +1381,9 @@ public struct BridgeJSLink { // Add properties from getters var propertyNames = Set() for getter in type.getters { - let propertyName = getter.jsName ?? getter.name + let propertyName = getter.resolvedJSName propertyNames.insert(propertyName) - let hasSetter = type.setters.contains { ($0.jsName ?? $0.name) == propertyName } + let hasSetter = type.setters.contains { $0.resolvedJSName == propertyName } let propertySignature = hasSetter ? "\(renderTSPropertyName(propertyName)): \(resolveTypeScriptType(getter.type));" @@ -1390,7 +1392,7 @@ public struct BridgeJSLink { } // Add setters that don't have corresponding getters for setter in type.setters { - let propertyName = setter.jsName ?? setter.name + let propertyName = setter.resolvedJSName guard !propertyNames.contains(propertyName) else { continue } printer.write("\(renderTSPropertyName(propertyName)): \(resolveTypeScriptType(setter.type));") } @@ -1628,7 +1630,7 @@ public struct BridgeJSLink { returnType: method.returnType, effects: method.effects ) - dtsTypePrinter.write("\(method.name)\(signature);") + dtsTypePrinter.write("\(method.resolvedJSName)\(signature);") } } dtsTypePrinter.write("}") @@ -1649,13 +1651,15 @@ public struct BridgeJSLink { for property in structDefinition.properties where property.isStatic { let readonly = property.isReadonly ? "readonly " : "" dtsExportEntryPrinter.write(lines: renderJSDoc(documentation: property.documentation, parameters: [])) - dtsExportEntryPrinter.write("\(readonly)\(property.name): \(resolveTypeScriptType(property.type));") + dtsExportEntryPrinter.write( + "\(readonly)\(property.resolvedJSName): \(resolveTypeScriptType(property.type));" + ) } for method in structDefinition.methods where method.effects.isStatic { let jsDocLines = renderJSDoc(documentation: method.documentation, parameters: method.parameters) dtsExportEntryPrinter.write(lines: jsDocLines) dtsExportEntryPrinter.write( - "\(method.name)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(method.resolvedJSName)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" ) } @@ -1914,7 +1918,7 @@ extension BridgeJSLink { dtsLines.append(contentsOf: renderJSDoc(documentation: function.documentation, parameters: function.parameters)) dtsLines.append( - "\(function.name)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + "\(function.resolvedJSName)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ) return (funcLines, dtsLines) @@ -1955,7 +1959,7 @@ extension BridgeJSLink { let returnExpr = try thunkBuilder.call(abiName: function.abiName, returnType: function.returnType) let funcLines = thunkBuilder.renderFunction( - name: function.name, + name: function.resolvedJSName, parameters: function.parameters, returnExpr: returnExpr, declarationPrefixKeyword: "static" @@ -1966,7 +1970,7 @@ extension BridgeJSLink { dtsLines.append(contentsOf: renderJSDoc(documentation: function.documentation, parameters: function.parameters)) dtsLines.append( - "static \(function.name)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + "static \(function.resolvedJSName)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ) return (funcLines, dtsLines) @@ -1986,7 +1990,7 @@ extension BridgeJSLink { let returnExpr = try thunkBuilder.call(abiName: function.abiName, returnType: function.returnType) let printer = CodeFragmentPrinter() - printer.write("\(function.name)(\(DefaultValueUtils.formatParameterList(function.parameters))) {") + printer.write("\(function.resolvedJSName)(\(DefaultValueUtils.formatParameterList(function.parameters))) {") printer.indent { thunkBuilder.renderFunctionBody(into: printer, returnExpr: returnExpr) } @@ -1997,7 +2001,7 @@ extension BridgeJSLink { dtsLines.append(contentsOf: renderJSDoc(documentation: function.documentation, parameters: function.parameters)) dtsLines.append( - "\(function.name)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" + "\(function.resolvedJSName)\(renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));" ) return (printer.lines, dtsLines) @@ -2043,7 +2047,7 @@ extension BridgeJSLink { let methodPrinter = CodeFragmentPrinter() methodPrinter.write( - "\(method.name): function(\(DefaultValueUtils.formatParameterList(method.parameters))) {" + "\(method.resolvedJSName): function(\(DefaultValueUtils.formatParameterList(method.parameters))) {" ) methodPrinter.indent { thunkBuilder.renderFunctionBody(into: methodPrinter, returnExpr: returnExpr) @@ -2071,7 +2075,7 @@ extension BridgeJSLink { returnType: property.type ) - propertyPrinter.write("get \(property.name)() {") + propertyPrinter.write("get \(property.resolvedJSName)() {") propertyPrinter.indent { getterThunkBuilder.renderFunctionBody(into: propertyPrinter, returnExpr: getterReturnExpr) } @@ -2093,7 +2097,7 @@ extension BridgeJSLink { returnType: .void ) - propertyPrinter.write("set \(property.name)(value) {") + propertyPrinter.write("set \(property.resolvedJSName)(value) {") propertyPrinter.indent { setterThunkBuilder.renderFunctionBody(into: propertyPrinter, returnExpr: nil) } @@ -2177,7 +2181,7 @@ extension BridgeJSLink { jsPrinter.indent { jsPrinter.write( lines: thunkBuilder.renderFunction( - name: method.name, + name: method.resolvedJSName, parameters: method.parameters, returnExpr: returnExpr, declarationPrefixKeyword: "static" @@ -2198,7 +2202,7 @@ extension BridgeJSLink { jsPrinter.indent { jsPrinter.write( lines: thunkBuilder.renderFunction( - name: method.name, + name: method.resolvedJSName, parameters: method.parameters, returnExpr: returnExpr, declarationPrefixKeyword: nil @@ -2214,7 +2218,7 @@ extension BridgeJSLink { dtsTypePrinter.write(line) } dtsTypePrinter.write( - "\(method.name)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(method.resolvedJSName)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" ) } } @@ -2252,13 +2256,13 @@ extension BridgeJSLink { for method in klass.methods where method.effects.isStatic { printer.write(lines: renderJSDoc(documentation: method.documentation, parameters: method.parameters)) printer.write( - "\(method.name)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(method.resolvedJSName)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" ) } for property in klass.properties where property.isStatic { let readonly = property.isReadonly ? "readonly " : "" printer.write(lines: renderJSDoc(documentation: property.documentation, parameters: [])) - printer.write("\(readonly)\(property.name): \(resolveTypeScriptType(property.type));") + printer.write("\(readonly)\(property.resolvedJSName): \(resolveTypeScriptType(property.type));") } return printer.lines } @@ -2280,18 +2284,20 @@ extension BridgeJSLink { ) printer.write("constructor(\(paramSignatures.joined(separator: ", ")));") } - for method in klass.methods.sorted(by: { $0.name < $1.name }) { + for method in klass.methods.sorted(by: { $0.resolvedJSName < $1.resolvedJSName }) { let staticKeyword = method.effects.isStatic ? "static " : "" printer.write(lines: renderJSDoc(documentation: method.documentation, parameters: method.parameters)) printer.write( - "\(staticKeyword)\(method.name)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" + "\(staticKeyword)\(method.resolvedJSName)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" ) } - for property in klass.properties.sorted(by: { $0.name < $1.name }) { + for property in klass.properties.sorted(by: { $0.resolvedJSName < $1.resolvedJSName }) { let staticKeyword = property.isStatic ? "static " : "" let readonly = property.isReadonly ? "readonly " : "" printer.write(lines: renderJSDoc(documentation: property.documentation, parameters: [])) - printer.write("\(staticKeyword)\(readonly)\(property.name): \(resolveTypeScriptType(property.type));") + printer.write( + "\(staticKeyword)\(readonly)\(property.resolvedJSName): \(resolveTypeScriptType(property.type));" + ) } printer.write("release(): void;") } @@ -2321,7 +2327,7 @@ extension BridgeJSLink { jsPrinter.indent { jsPrinter.write( lines: getterThunkBuilder.renderFunction( - name: property.name, + name: property.resolvedJSName, parameters: [], returnExpr: getterReturnExpr, declarationPrefixKeyword: getterKeyword @@ -2349,7 +2355,7 @@ extension BridgeJSLink { jsPrinter.indent { jsPrinter.write( lines: setterThunkBuilder.renderFunction( - name: property.name, + name: property.resolvedJSName, parameters: [.init(label: nil, name: "value", type: property.type)], returnExpr: nil, declarationPrefixKeyword: setterKeyword @@ -2365,7 +2371,7 @@ extension BridgeJSLink { for line in renderJSDoc(documentation: property.documentation, parameters: []) { dtsPrinter.write(line) } - dtsPrinter.write("\(readonly)\(property.name): \(resolveTypeScriptType(property.type));") + dtsPrinter.write("\(readonly)\(property.resolvedJSName): \(resolveTypeScriptType(property.type));") } } } @@ -2738,7 +2744,7 @@ extension BridgeJSLink { for function in skeleton.functions where function.namespace != nil { let namespacePath = function.namespace!.joined(separator: ".") printer.write( - "globalThis.\(namespacePath).\(function.name) = exports.\(namespacePath).\(function.name);" + "globalThis.\(namespacePath).\(function.resolvedJSName) = exports.\(namespacePath).\(function.resolvedJSName);" ) } for enumDef in skeleton.enums where enumDef.enumType == .namespace { @@ -2746,7 +2752,7 @@ extension BridgeJSLink { let fullNamespace = (enumDef.namespace ?? []) + [enumDef.name] let namespacePath = fullNamespace.joined(separator: ".") printer.write( - "globalThis.\(namespacePath).\(function.name) = exports.\(namespacePath).\(function.name);" + "globalThis.\(namespacePath).\(function.resolvedJSName) = exports.\(namespacePath).\(function.resolvedJSName);" ) } for property in enumDef.staticProperties { @@ -2754,11 +2760,13 @@ extension BridgeJSLink { let namespacePath = fullNamespace.joined(separator: ".") let exportsPath = "exports.\(namespacePath)" - printer.write("Object.defineProperty(globalThis.\(namespacePath), '\(property.name)', {") + printer.write( + "Object.defineProperty(globalThis.\(namespacePath), '\(property.resolvedJSName)', {" + ) printer.indent { - printer.write("get: () => \(exportsPath).\(property.name),") + printer.write("get: () => \(exportsPath).\(property.resolvedJSName),") if !property.isReadonly { - printer.write("set: (value) => { \(exportsPath).\(property.name) = value; }") + printer.write("set: (value) => { \(exportsPath).\(property.resolvedJSName) = value; }") } } printer.write("});") @@ -2940,7 +2948,7 @@ extension BridgeJSLink { renderPropertyEntry: (ExportedProperty) -> [String] ) { for function in node.content.functions { - node.content.functionDtsLines.append((function.name, renderFunctionEntry(function))) + node.content.functionDtsLines.append((function.resolvedJSName, renderFunctionEntry(function))) } switch node.content.declaration { @@ -2953,7 +2961,7 @@ extension BridgeJSLink { } for property in node.content.staticProperties { - node.content.staticPropertyDtsLines.append((property.name, renderPropertyEntry(property))) + node.content.staticPropertyDtsLines.append((property.resolvedJSName, renderPropertyEntry(property))) } for enumDef in node.content.enums { @@ -3005,7 +3013,7 @@ extension BridgeJSLink { ) throws { for function in node.content.functions { let impl = try renderFunctionImpl(function) - node.content.functionJsLines.append((function.name, impl)) + node.content.functionJsLines.append((function.resolvedJSName, impl)) } switch node.content.declaration { @@ -3039,7 +3047,7 @@ extension BridgeJSLink { ) let getterPrinter = CodeFragmentPrinter() - getterPrinter.write("get \(property.name)() {") + getterPrinter.write("get \(property.resolvedJSName)() {") getterPrinter.indent { getterPrinter.write(contentsOf: getterThunkBuilder.body) getterPrinter.write(lines: getterThunkBuilder.checkExceptionLines()) @@ -3066,7 +3074,7 @@ extension BridgeJSLink { ) let setterPrinter = CodeFragmentPrinter() - setterPrinter.write("set \(property.name)(value) {") + setterPrinter.write("set \(property.resolvedJSName)(value) {") setterPrinter.indent { setterPrinter.write(contentsOf: setterThunkBuilder.body) setterPrinter.write(lines: setterThunkBuilder.checkExceptionLines()) @@ -3431,18 +3439,22 @@ extension BridgeJSLink { // Only include functions and properties when exposeToGlobal is true if exposeToGlobal { - let sortedFunctions = childNode.content.functions.sorted { $0.name < $1.name } + let sortedFunctions = childNode.content.functions.sorted { + $0.resolvedJSName < $1.resolvedJSName + } for function in sortedFunctions { let signature = - "function \(function.name)\(renderTSSignatureCallback(function.parameters, function.returnType, function.effects));" + "function \(function.resolvedJSName)\(renderTSSignatureCallback(function.parameters, function.returnType, function.effects));" printer.write(lines: renderDocCallback(function.documentation, function.parameters)) printer.write(signature) } - let sortedProperties = childNode.content.staticProperties.sorted { $0.name < $1.name } + let sortedProperties = childNode.content.staticProperties.sorted { + $0.resolvedJSName < $1.resolvedJSName + } for property in sortedProperties { let readonly = property.isReadonly ? "var " : "let " printer.write(lines: renderDocCallback(property.documentation, [])) - printer.write("\(readonly)\(property.name): \(property.type.tsType);") + printer.write("\(readonly)\(property.resolvedJSName): \(property.type.tsType);") } } @@ -3479,7 +3491,7 @@ extension BridgeJSLink { for param in function.parameters { try thunkBuilder.liftParameter(param: param) } - let jsName = function.jsName ?? function.name + let jsName = function.resolvedJSName let calleeExpr = try importedModuleRegistry.memberExpression( swiftModuleName: importObjectBuilder.moduleName, from: function.from, @@ -3507,7 +3519,7 @@ extension BridgeJSLink { returnType: getter.type, intrinsicRegistry: intrinsicRegistry ) - let jsName = getter.jsName ?? getter.name + let jsName = getter.resolvedJSName let accessExpr = try importedModuleRegistry.memberExpression( swiftModuleName: importObjectBuilder.moduleName, from: getter.from, @@ -3542,7 +3554,7 @@ extension BridgeJSLink { getter: getter, abiName: getterAbiName, emitCall: { thunkBuilder in - return try thunkBuilder.callPropertyGetter(name: getter.jsName ?? getter.name) + return try thunkBuilder.callPropertyGetter(name: getter.resolvedJSName) } ) importObjectBuilder.assignToImportObject(name: getterAbiName, function: js) @@ -3558,7 +3570,7 @@ extension BridgeJSLink { try thunkBuilder.liftParameter( param: Parameter(label: nil, name: "newValue", type: setter.type) ) - thunkBuilder.callPropertySetter(name: setter.jsName ?? setter.name) + thunkBuilder.callPropertySetter(name: setter.resolvedJSName) } ) importObjectBuilder.assignToImportObject(name: setterAbiName, function: js) @@ -3585,7 +3597,7 @@ extension BridgeJSLink { ) } for method in type.staticMethods { - let methodName = method.jsName ?? method.name + let methodName = method.resolvedJSName let signature = "\(renderTSPropertyName(methodName))\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" dtsPrinter.write(signature) @@ -3617,7 +3629,7 @@ extension BridgeJSLink { let ctorExpr = try importedModuleRegistry.memberExpression( swiftModuleName: importObjectBuilder.moduleName, from: type.from, - memberName: type.jsName ?? type.name + memberName: type.resolvedJSName ) try thunkBuilder.callConstructor( ctorExpr: ctorExpr, @@ -3676,10 +3688,10 @@ extension BridgeJSLink { let constructorExpr = try importedModuleRegistry.memberExpression( swiftModuleName: swiftModuleName, from: context.from, - memberName: context.jsName ?? context.name + memberName: context.resolvedJSName ) - try thunkBuilder.callStaticMethod(on: constructorExpr, name: method.jsName ?? method.name) + try thunkBuilder.callStaticMethod(on: constructorExpr, name: method.resolvedJSName) let funcLines = thunkBuilder.renderFunction(name: method.abiName(context: context, operation: "static")) return (funcLines, []) } @@ -3698,7 +3710,7 @@ extension BridgeJSLink { try thunkBuilder.liftParameter(param: param) } - try thunkBuilder.callMethod(name: method.jsName ?? method.name) + try thunkBuilder.callMethod(name: method.resolvedJSName) let funcLines = thunkBuilder.renderFunction(name: method.abiName(context: context)) return (funcLines, []) } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/ImportedJSModuleRegistry.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/ImportedJSModuleRegistry.swift index 96efcd1d4..daf220d7f 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/ImportedJSModuleRegistry.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/ImportedJSModuleRegistry.swift @@ -133,14 +133,14 @@ final class ImportedJSModuleRegistry { } for file in skeleton.imported?.children ?? [] { for function in file.functions { - visit(from: function.from, memberName: function.jsName ?? function.name) + visit(from: function.from, memberName: function.resolvedJSName) } for getter in file.globalGetters { - visit(from: getter.from, memberName: getter.jsName ?? getter.name) + visit(from: getter.from, memberName: getter.resolvedJSName) } for type in file.types { guard type.constructor != nil || !type.staticMethods.isEmpty else { continue } - visit(from: type.from, memberName: type.jsName ?? type.name) + visit(from: type.from, memberName: type.resolvedJSName) } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 1cf0fa298..2bf656708 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -2353,7 +2353,7 @@ struct IntrinsicJSFragment: Sendable { for method in structDef.methods where !method.effects.isStatic { let paramList = DefaultValueUtils.formatParameterList(method.parameters) printer.write( - "\(instanceVar).\(method.name) = function(\(paramList)) {" + "\(instanceVar).\(method.resolvedJSName) = function(\(paramList)) {" ) try printer.indent { printer.write( diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 5507f39c2..21704d1c9 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -861,6 +861,7 @@ public struct ExportedProtocol: Codable, Equatable { public struct ExportedFunction: Codable, Equatable, Sendable { public var name: String + public var jsName: String? public var abiName: String public var parameters: [Parameter] public var returnType: BridgeType @@ -869,8 +870,11 @@ public struct ExportedFunction: Codable, Equatable, Sendable { public var staticContext: StaticContext? public var documentation: String? + public var resolvedJSName: String { jsName ?? name } + public init( name: String, + jsName: String? = nil, abiName: String, parameters: [Parameter], returnType: BridgeType, @@ -880,6 +884,7 @@ public struct ExportedFunction: Codable, Equatable, Sendable { documentation: String? = nil ) { self.name = name + self.jsName = jsName self.abiName = abiName self.parameters = parameters self.returnType = returnType @@ -948,6 +953,7 @@ public struct ExportedConstructor: Codable, Equatable, Sendable { public struct ExportedProperty: Codable, Equatable, Sendable { public var name: String + public var jsName: String? public var type: BridgeType public var isReadonly: Bool public var isStatic: Bool @@ -955,8 +961,11 @@ public struct ExportedProperty: Codable, Equatable, Sendable { public var staticContext: StaticContext? public var documentation: String? + public var resolvedJSName: String { jsName ?? name } + public init( name: String, + jsName: String? = nil, type: BridgeType, isReadonly: Bool = false, isStatic: Bool = false, @@ -965,6 +974,7 @@ public struct ExportedProperty: Codable, Equatable, Sendable { documentation: String? = nil ) { self.name = name + self.jsName = jsName self.type = type self.isReadonly = isReadonly self.isStatic = isStatic @@ -1245,6 +1255,8 @@ public struct ImportedFunctionSkeleton: Codable { /// closure inits) that surface through this function's signature. public let accessLevel: BridgeJSAccessLevel + public var resolvedJSName: String { jsName ?? name } + public init( name: String, jsName: String? = nil, @@ -1336,6 +1348,8 @@ public struct ImportedGetterSkeleton: Codable { /// Source access level of the originating Swift declaration. public let accessLevel: BridgeJSAccessLevel + public var resolvedJSName: String { jsName ?? name } + public init( name: String, jsName: String? = nil, @@ -1396,6 +1410,8 @@ public struct ImportedSetterSkeleton: Codable { /// Source access level of the originating Swift declaration. public let accessLevel: BridgeJSAccessLevel + public var resolvedJSName: String { jsName ?? name } + public init( name: String, jsName: String? = nil, @@ -1458,6 +1474,8 @@ public struct ImportedTypeSkeleton: Codable { /// Source access level of the originating Swift `@JSClass` declaration. public let accessLevel: BridgeJSAccessLevel + public var resolvedJSName: String { jsName ?? name } + public init( name: String, jsName: String? = nil, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift index 316d51b41..5abdf8fb2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift @@ -658,6 +658,87 @@ import Testing } } + @Test + func jsNameOnClassDiagnostic() throws { + let source = """ + @JS("Renamed") class Box { @JS init() {} } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("A separate name for JavaScript is not supported here")) + } + + @Test + func jsNameOnStructDiagnostic() throws { + let source = """ + @JS("Renamed") struct Box { var x: Int } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("A separate name for JavaScript is not supported here")) + } + + @Test + func jsNameOnEnumDiagnostic() throws { + let source = """ + @JS("Renamed") enum Box { case a } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("A separate name for JavaScript is not supported here")) + } + + @Test + func jsNameOnProtocolDiagnostic() throws { + let source = """ + @JS("Renamed") protocol Box { func run() } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("A separate name for JavaScript is not supported here")) + } + + @Test + func jsNameOnInitializerDiagnostic() throws { + let source = """ + @JS class Box { @JS("create") init() {} } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("A separate name for JavaScript is not supported here")) + } + + @Test + func jsNameOnProtocolRequirementDiagnostic() throws { + let source = """ + @JS protocol Box { @JS("run") func run() } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("A separate name for JavaScript is not supported here")) + } + + @Test + func invalidJSNameDiagnostic() throws { + let source = """ + @JS("1notAnIdentifier") func a() -> Int { 42 } + @JS("has space") func b() -> Int { 42 } + @JS("has-dash") func c() -> Int { 42 } + @JS("") func d() -> Int { 42 } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("`1notAnIdentifier` is not a valid JavaScript identifier")) + #expect(diagnostics.description.contains("`has space` is not a valid JavaScript identifier")) + #expect(diagnostics.description.contains("`has-dash` is not a valid JavaScript identifier")) + #expect(diagnostics.description.contains("`` is not a valid JavaScript identifier")) + } + + @Test + func jsNameOnMultipleBindingsDiagnostic() throws { + let source = """ + @JS class Box { + @JS init() {} + @JS("renamed") var first: Int = 1, second: Int = 2 + } + """ + let diagnostics = try #require(moduleDiagnostics(source: source)) + #expect(diagnostics.description.contains("Name targets declaration with multiple bindings")) + } + @Test func omitsNextLineWhenErrorIsOnLastLine() throws { let source = """ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSNameOverride.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSNameOverride.swift new file mode 100644 index 000000000..fc5777a15 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/JSNameOverride.swift @@ -0,0 +1,40 @@ +@JS("makeGreeting") func renderGreeting(name: String) -> String + +@JS("greetName") func greet(_ name: String) -> String + +@JS("greetCount") func greet(_ count: Int) -> String + +@JS("namespacedRenamed", namespace: "Utils.Text") func namespacedFunction() -> Int + +@JS class RenamedMembers { + @JS("label") var title: String + @JS("total") let count: Int + @JS("sharedTotal") nonisolated(unsafe) static var sharedCount: Int = 0 + @JS("readOnlyLimit") static let limit: Int = 10 + + @JS init(title: String, count: Int) + @JS("makeGreeting") func greet() -> String + @JS("makeDefault") static func createDefault() -> RenamedMembers +} + +@JS struct RenamedVector { + var dx: Double + var dy: Double + + @JS("originVector") static let origin: RenamedVector = RenamedVector(dx: 0, dy: 0) + @JS("magnitude") func length() -> Double + @JS("fromPolar") static func polar(radius: Double, angle: Double) -> RenamedVector +} + +@JS enum RenamedEnumMembers { + case active + case inactive + + @JS("describeCase") static func describe() -> String + @JS("currentDefault") nonisolated(unsafe) static var defaultValue: String = "active" +} + +@JS enum RenamedNamespaceMembers { + @JS("plus") static func add(_ a: Int, _ b: Int) -> Int + @JS("theAnswer") nonisolated(unsafe) static var answer: Int = 42 +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.json new file mode 100644 index 000000000..c5cd01631 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.json @@ -0,0 +1,524 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_RenamedMembers_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "title", + "name" : "title", + "type" : { + "string" : { + + } + } + }, + { + "label" : "count", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_RenamedMembers_makeGreeting", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "makeGreeting", + "name" : "greet", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_RenamedMembers_static_makeDefault", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "jsName" : "makeDefault", + "name" : "createDefault", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "RenamedMembers" + } + }, + "staticContext" : { + "className" : { + "_0" : "RenamedMembers" + } + } + } + ], + "name" : "RenamedMembers", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "jsName" : "label", + "name" : "title", + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "jsName" : "total", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : true, + "jsName" : "sharedTotal", + "name" : "sharedCount", + "staticContext" : { + "className" : { + "_0" : "RenamedMembers" + } + }, + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "jsName" : "readOnlyLimit", + "name" : "limit", + "staticContext" : { + "className" : { + "_0" : "RenamedMembers" + } + }, + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "RenamedMembers" + } + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "active" + }, + { + "associatedValues" : [ + + ], + "name" : "inactive" + } + ], + "emitStyle" : "const", + "name" : "RenamedEnumMembers", + "staticMethods" : [ + { + "abiName" : "bjs_RenamedEnumMembers_static_describeCase", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "jsName" : "describeCase", + "name" : "describe", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + }, + "staticContext" : { + "enumName" : { + "_0" : "RenamedEnumMembers" + } + } + } + ], + "staticProperties" : [ + { + "isReadonly" : false, + "isStatic" : true, + "jsName" : "currentDefault", + "name" : "defaultValue", + "staticContext" : { + "enumName" : { + "_0" : "RenamedEnumMembers" + } + }, + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "RenamedEnumMembers", + "tsFullPath" : "RenamedEnumMembers" + }, + { + "cases" : [ + + ], + "emitStyle" : "const", + "name" : "RenamedNamespaceMembers", + "staticMethods" : [ + { + "abiName" : "bjs_RenamedNamespaceMembers_static_plus", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "jsName" : "plus", + "name" : "add", + "namespace" : [ + "RenamedNamespaceMembers" + ], + "parameters" : [ + { + "label" : "_", + "name" : "a", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "label" : "_", + "name" : "b", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + }, + "staticContext" : { + "namespaceEnum" : { + "_0" : "RenamedNamespaceMembers" + } + } + } + ], + "staticProperties" : [ + { + "isReadonly" : false, + "isStatic" : true, + "jsName" : "theAnswer", + "name" : "answer", + "namespace" : [ + "RenamedNamespaceMembers" + ], + "staticContext" : { + "namespaceEnum" : { + "_0" : "RenamedNamespaceMembers" + } + }, + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "RenamedNamespaceMembers", + "tsFullPath" : "RenamedNamespaceMembers" + } + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_makeGreeting", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "makeGreeting", + "name" : "renderGreeting", + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_greetName", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "greetName", + "name" : "greet", + "parameters" : [ + { + "label" : "_", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_greetCount", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "greetCount", + "name" : "greet", + "parameters" : [ + { + "label" : "_", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Utils_Text_namespacedRenamed", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "namespacedRenamed", + "name" : "namespacedFunction", + "namespace" : [ + "Utils", + "Text" + ], + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + { + "methods" : [ + { + "abiName" : "bjs_RenamedVector_magnitude", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "magnitude", + "name" : "length", + "parameters" : [ + + ], + "returnType" : { + "double" : { + + } + } + }, + { + "abiName" : "bjs_RenamedVector_static_fromPolar", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "jsName" : "fromPolar", + "name" : "polar", + "parameters" : [ + { + "label" : "radius", + "name" : "radius", + "type" : { + "double" : { + + } + } + }, + { + "label" : "angle", + "name" : "angle", + "type" : { + "double" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "RenamedVector" + } + }, + "staticContext" : { + "structName" : { + "_0" : "RenamedVector" + } + } + } + ], + "name" : "RenamedVector", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dx", + "type" : { + "double" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "dy", + "type" : { + "double" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "jsName" : "originVector", + "name" : "origin", + "staticContext" : { + "structName" : { + "_0" : "RenamedVector" + } + }, + "type" : { + "swiftStruct" : { + "_0" : "RenamedVector" + } + } + } + ], + "swiftCallName" : "RenamedVector" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift new file mode 100644 index 000000000..b525b5152 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/JSNameOverride.swift @@ -0,0 +1,351 @@ +extension RenamedEnumMembers: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> RenamedEnumMembers { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> RenamedEnumMembers { + return RenamedEnumMembers(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .active + case 1: + self = .inactive + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .active: + return 0 + case .inactive: + return 1 + } + } +} + +@_expose(wasm, "bjs_RenamedEnumMembers_static_describeCase") +@_cdecl("bjs_RenamedEnumMembers_static_describeCase") +public func _bjs_RenamedEnumMembers_static_describeCase() -> Void { + #if arch(wasm32) + let ret = RenamedEnumMembers.describe() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedEnumMembers_static_defaultValue_get") +@_cdecl("bjs_RenamedEnumMembers_static_defaultValue_get") +public func _bjs_RenamedEnumMembers_static_defaultValue_get() -> Void { + #if arch(wasm32) + let ret = RenamedEnumMembers.defaultValue + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedEnumMembers_static_defaultValue_set") +@_cdecl("bjs_RenamedEnumMembers_static_defaultValue_set") +public func _bjs_RenamedEnumMembers_static_defaultValue_set(_ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + RenamedEnumMembers.defaultValue = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedNamespaceMembers_static_plus") +@_cdecl("bjs_RenamedNamespaceMembers_static_plus") +public func _bjs_RenamedNamespaceMembers_static_plus(_ a: Int32, _ b: Int32) -> Int32 { + #if arch(wasm32) + let ret = RenamedNamespaceMembers.add(_: Int.bridgeJSLiftParameter(a), _: Int.bridgeJSLiftParameter(b)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedNamespaceMembers_static_answer_get") +@_cdecl("bjs_RenamedNamespaceMembers_static_answer_get") +public func _bjs_RenamedNamespaceMembers_static_answer_get() -> Int32 { + #if arch(wasm32) + let ret = RenamedNamespaceMembers.answer + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedNamespaceMembers_static_answer_set") +@_cdecl("bjs_RenamedNamespaceMembers_static_answer_set") +public func _bjs_RenamedNamespaceMembers_static_answer_set(_ value: Int32) -> Void { + #if arch(wasm32) + RenamedNamespaceMembers.answer = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension RenamedVector: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> RenamedVector { + let dy = Double.bridgeJSStackPop() + let dx = Double.bridgeJSStackPop() + return RenamedVector(dx: dx, dy: dy) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.dx.bridgeJSStackPush() + self.dy.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_RenamedVector(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_RenamedVector())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_RenamedVector") +fileprivate func _bjs_struct_lower_RenamedVector_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_RenamedVector_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_RenamedVector(_ objectId: Int32) -> Void { + return _bjs_struct_lower_RenamedVector_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_RenamedVector") +fileprivate func _bjs_struct_lift_RenamedVector_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_RenamedVector_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_RenamedVector() -> Int32 { + return _bjs_struct_lift_RenamedVector_extern() +} + +@_expose(wasm, "bjs_RenamedVector_static_origin_get") +@_cdecl("bjs_RenamedVector_static_origin_get") +public func _bjs_RenamedVector_static_origin_get() -> Void { + #if arch(wasm32) + let ret = RenamedVector.origin + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedVector_magnitude") +@_cdecl("bjs_RenamedVector_magnitude") +public func _bjs_RenamedVector_magnitude() -> Float64 { + #if arch(wasm32) + let ret = RenamedVector.bridgeJSLiftParameter().length() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedVector_static_fromPolar") +@_cdecl("bjs_RenamedVector_static_fromPolar") +public func _bjs_RenamedVector_static_fromPolar(_ radius: Float64, _ angle: Float64) -> Void { + #if arch(wasm32) + let ret = RenamedVector.polar(radius: Double.bridgeJSLiftParameter(radius), angle: Double.bridgeJSLiftParameter(angle)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_makeGreeting") +@_cdecl("bjs_makeGreeting") +public func _bjs_makeGreeting(_ nameBytes: Int32, _ nameLength: Int32) -> Void { + #if arch(wasm32) + let ret = renderGreeting(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_greetName") +@_cdecl("bjs_greetName") +public func _bjs_greetName(_ nameBytes: Int32, _ nameLength: Int32) -> Void { + #if arch(wasm32) + let ret = greet(_: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_greetCount") +@_cdecl("bjs_greetCount") +public func _bjs_greetCount(_ count: Int32) -> Void { + #if arch(wasm32) + let ret = greet(_: Int.bridgeJSLiftParameter(count)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Utils_Text_namespacedRenamed") +@_cdecl("bjs_Utils_Text_namespacedRenamed") +public func _bjs_Utils_Text_namespacedRenamed() -> Int32 { + #if arch(wasm32) + let ret = namespacedFunction() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_init") +@_cdecl("bjs_RenamedMembers_init") +public func _bjs_RenamedMembers_init(_ titleBytes: Int32, _ titleLength: Int32, _ count: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = RenamedMembers(title: String.bridgeJSLiftParameter(titleBytes, titleLength), count: Int.bridgeJSLiftParameter(count)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_makeGreeting") +@_cdecl("bjs_RenamedMembers_makeGreeting") +public func _bjs_RenamedMembers_makeGreeting(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = RenamedMembers.bridgeJSLiftParameter(_self).greet() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_static_makeDefault") +@_cdecl("bjs_RenamedMembers_static_makeDefault") +public func _bjs_RenamedMembers_static_makeDefault() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = RenamedMembers.createDefault() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_title_get") +@_cdecl("bjs_RenamedMembers_title_get") +public func _bjs_RenamedMembers_title_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = RenamedMembers.bridgeJSLiftParameter(_self).title + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_title_set") +@_cdecl("bjs_RenamedMembers_title_set") +public func _bjs_RenamedMembers_title_set(_ _self: UnsafeMutableRawPointer, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + RenamedMembers.bridgeJSLiftParameter(_self).title = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_count_get") +@_cdecl("bjs_RenamedMembers_count_get") +public func _bjs_RenamedMembers_count_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = RenamedMembers.bridgeJSLiftParameter(_self).count + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_static_sharedCount_get") +@_cdecl("bjs_RenamedMembers_static_sharedCount_get") +public func _bjs_RenamedMembers_static_sharedCount_get() -> Int32 { + #if arch(wasm32) + let ret = RenamedMembers.sharedCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_static_sharedCount_set") +@_cdecl("bjs_RenamedMembers_static_sharedCount_set") +public func _bjs_RenamedMembers_static_sharedCount_set(_ value: Int32) -> Void { + #if arch(wasm32) + RenamedMembers.sharedCount = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_static_limit_get") +@_cdecl("bjs_RenamedMembers_static_limit_get") +public func _bjs_RenamedMembers_static_limit_get() -> Int32 { + #if arch(wasm32) + let ret = RenamedMembers.limit + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_RenamedMembers_deinit") +@_cdecl("bjs_RenamedMembers_deinit") +public func _bjs_RenamedMembers_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension RenamedMembers: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_RenamedMembers_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_RenamedMembers_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_RenamedMembers_wrap") +fileprivate func _bjs_RenamedMembers_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_RenamedMembers_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_RenamedMembers_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_RenamedMembers_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts new file mode 100644 index 000000000..d31aeebe3 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.d.ts @@ -0,0 +1,68 @@ +// 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 RenamedEnumMembersValues: { + readonly Active: 0; + readonly Inactive: 1; +}; +export type RenamedEnumMembersTag = typeof RenamedEnumMembersValues[keyof typeof RenamedEnumMembersValues]; + +export interface RenamedVector { + dx: number; + dy: number; + magnitude(): number; +} +export type RenamedEnumMembersObject = typeof RenamedEnumMembersValues & { + describeCase(): string; + currentDefault: string; +}; + +/// Represents a Swift heap object like a class instance or an actor instance. +export interface SwiftHeapObject { + /// Release the heap object. + /// + /// Note: Calling this method will release the heap object and it will no longer be accessible. + release(): void; +} +export interface RenamedMembers extends SwiftHeapObject { + makeGreeting(): string; + label: string; + readonly total: number; +} +export type Exports = { + makeGreeting(name: string): string; + greetName(name: string): string; + greetCount(count: number): string; + RenamedEnumMembers: RenamedEnumMembersObject + RenamedMembers: { + new(title: string, count: number): RenamedMembers; + makeDefault(): RenamedMembers; + sharedTotal: number; + readonly readOnlyLimit: number; + }, + RenamedNamespaceMembers: { + theAnswer: number; + plus(a: number, b: number): number; + }, + RenamedVector: { + readonly originVector: RenamedVector; + fromPolar(radius: number, angle: number): RenamedVector; + }, + Utils: { + Text: { + namespacedRenamed(): number; + }, + }, +} +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/JSNameOverride.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js new file mode 100644 index 000000000..543ae05f0 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSNameOverride.js @@ -0,0 +1,442 @@ +// 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 RenamedEnumMembersValues = { + Active: 0, + Inactive: 1, +}; + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const __bjs_createRenamedVectorHelpers = () => ({ + lower: (value) => { + f64Stack.push(value.dx); + f64Stack.push(value.dy); + }, + lift: () => { + const f64 = f64Stack.pop(); + const f641 = f64Stack.pop(); + const instance1 = { dx: f641, dy: f64 }; + instance1.magnitude = function() { + structHelpers.RenamedVector.lower(this); + const ret = instance.exports.bjs_RenamedVector_magnitude(); + return ret; + }.bind(instance1); + return instance1; + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr >>> 0); + bytes.set(source); + } + bjs["swift_js_make_js_string"] = function(ptr, len) { + return swift.memory.retain(decodeString(ptr, len)); + } + bjs["swift_js_init_memory_with_result"] = function(ptr, len) { + const target = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); + target.set(tmpRetBytes); + tmpRetBytes = undefined; + } + bjs["swift_js_throw"] = function(id) { + tmpRetException = swift.memory.retainByRef(id); + } + bjs["swift_js_retain"] = function(id) { + return swift.memory.retainByRef(id); + } + bjs["swift_js_release"] = function(id) { + swift.memory.release(id); + } + bjs["swift_js_push_i32"] = function(v) { + i32Stack.push(v | 0); + } + bjs["swift_js_push_f32"] = function(v) { + f32Stack.push(Math.fround(v)); + } + bjs["swift_js_push_f64"] = function(v) { + f64Stack.push(v); + } + bjs["swift_js_push_string"] = function(ptr, len) { + const value = decodeString(ptr, len); + strStack.push(value); + } + bjs["swift_js_pop_i32"] = function() { + return i32Stack.pop(); + } + bjs["swift_js_pop_f32"] = function() { + return f32Stack.pop(); + } + bjs["swift_js_pop_f64"] = function() { + return f64Stack.pop(); + } + bjs["swift_js_push_pointer"] = function(pointer) { + ptrStack.push(pointer); + } + bjs["swift_js_pop_pointer"] = function() { + return ptrStack.pop(); + } + bjs["swift_js_push_i64"] = function(v) { + i64Stack.push(v); + } + bjs["swift_js_pop_i64"] = function() { + return i64Stack.pop(); + } + const taCtors = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; + bjs["swift_js_push_typed_array"] = function(kind, ptr, count) { + const Ctor = taCtors[kind]; + const byteLen = count * Ctor.BYTES_PER_ELEMENT; + const copy = memory.buffer.slice(ptr, ptr + byteLen); + taStack.push(Array.from(new Ctor(copy))); + } + bjs["swift_js_struct_lower_RenamedVector"] = function(objectId) { + structHelpers.RenamedVector.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_RenamedVector"] = function() { + const value = structHelpers.RenamedVector.lift(); + return swift.memory.retain(value); + } + const __bjs_promiseSettlers = Symbol("JavaScriptKit.promiseSettlers"); + bjs["swift_js_make_promise"] = function() { + let resolve, reject; + const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); + promise[__bjs_promiseSettlers] = { resolve, reject }; + return swift.memory.retain(promise); + } + bjs["swift_js_return_optional_bool"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalBool = null; + } else { + tmpRetOptionalBool = value !== 0; + } + } + bjs["swift_js_return_optional_int"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalInt = null; + } else { + tmpRetOptionalInt = value | 0; + } + } + bjs["swift_js_return_optional_float"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalFloat = null; + } else { + tmpRetOptionalFloat = Math.fround(value); + } + } + bjs["swift_js_return_optional_double"] = function(isSome, value) { + if (isSome === 0) { + tmpRetOptionalDouble = null; + } else { + tmpRetOptionalDouble = value; + } + } + bjs["swift_js_return_optional_string"] = function(isSome, ptr, len) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = decodeString(ptr, len); + } + } + bjs["swift_js_return_optional_object"] = function(isSome, objectId) { + if (isSome === 0) { + tmpRetString = null; + } else { + tmpRetString = swift.memory.getObject(objectId); + } + } + bjs["swift_js_return_optional_heap_object"] = function(isSome, pointer) { + if (isSome === 0) { + tmpRetOptionalHeapObject = null; + } else { + tmpRetOptionalHeapObject = pointer; + } + } + bjs["swift_js_get_optional_int_presence"] = function() { + return tmpRetOptionalInt != null ? 1 : 0; + } + bjs["swift_js_get_optional_int_value"] = function() { + const value = tmpRetOptionalInt; + tmpRetOptionalInt = undefined; + return value; + } + bjs["swift_js_get_optional_string"] = function() { + const str = tmpRetString; + tmpRetString = undefined; + if (str == null) { + return -1; + } else { + const bytes = textEncoder.encode(str); + tmpRetBytes = bytes; + return bytes.length; + } + } + bjs["swift_js_get_optional_float_presence"] = function() { + return tmpRetOptionalFloat != null ? 1 : 0; + } + bjs["swift_js_get_optional_float_value"] = function() { + const value = tmpRetOptionalFloat; + tmpRetOptionalFloat = undefined; + return value; + } + bjs["swift_js_get_optional_double_presence"] = function() { + return tmpRetOptionalDouble != null ? 1 : 0; + } + bjs["swift_js_get_optional_double_value"] = function() { + const value = tmpRetOptionalDouble; + tmpRetOptionalDouble = undefined; + return value; + } + bjs["swift_js_get_optional_heap_object_pointer"] = function() { + const pointer = tmpRetOptionalHeapObject; + tmpRetOptionalHeapObject = undefined; + return pointer || 0; + } + bjs["swift_js_closure_unregister"] = function(funcRef) {} + // Wrapper functions for module: TestModule + if (!importObject["TestModule"]) { + importObject["TestModule"] = {}; + } + importObject["TestModule"]["bjs_RenamedMembers_wrap"] = function(pointer) { + const obj = _exports['RenamedMembers'].__construct(pointer); + return swift.memory.retain(obj); + }; + }, + setInstance: (i) => { + instance = i; + memory = instance.exports.memory; + + decodeString = (ptr, len) => { const bytes = new Uint8Array(memory.buffer, ptr >>> 0, len >>> 0); return textDecoder.decode(bytes); } + + setException = (error) => { + instance.exports._swift_js_exception.value = swift.memory.retain(error) + } + }, + /** @param {WebAssembly.Instance} instance */ + createExports: (instance) => { + const js = swift.memory.heap; + const swiftHeapObjectFinalizationRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.hasReleased) { + return; + } + state.hasReleased = true; + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + }); + + /// Represents a Swift heap object like a class instance or an actor instance. + class SwiftHeapObject { + static __wrap(pointer, deinit, prototype, identityCache) { + pointer = pointer >>> 0; + const makeFresh = (identityMap) => { + const obj = Object.create(prototype); + const state = { pointer, deinit, hasReleased: false, identityMap }; + obj.pointer = pointer; + obj.__swiftHeapObjectState = state; + swiftHeapObjectFinalizationRegistry.register(obj, state, state); + if (identityMap) { + identityMap.set(pointer, new WeakRef(obj)); + } + return obj; + }; + + if (!identityCache) { + return makeFresh(null); + } + + const cached = identityCache.get(pointer)?.deref(); + if (cached && !cached.__swiftHeapObjectState.hasReleased) { + deinit(pointer); + return cached; + } + if (identityCache.has(pointer)) { + identityCache.delete(pointer); + } + + return makeFresh(identityCache); + } + + release() { + const state = this.__swiftHeapObjectState; + if (state.hasReleased) { + return; + } + state.hasReleased = true; + swiftHeapObjectFinalizationRegistry.unregister(state); + state.identityMap?.delete(state.pointer); + state.deinit(state.pointer); + } + } + class RenamedMembers extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_RenamedMembers_deinit, RenamedMembers.prototype, null); + } + + constructor(title, count) { + const titleBytes = textEncoder.encode(title); + const titleId = swift.memory.retain(titleBytes); + const ret = instance.exports.bjs_RenamedMembers_init(titleId, titleBytes.length, count); + return RenamedMembers.__construct(ret); + } + makeGreeting() { + instance.exports.bjs_RenamedMembers_makeGreeting(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + static makeDefault() { + const ret = instance.exports.bjs_RenamedMembers_static_makeDefault(); + return RenamedMembers.__construct(ret); + } + get label() { + instance.exports.bjs_RenamedMembers_title_get(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + set label(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_RenamedMembers_title_set(this.pointer, valueId, valueBytes.length); + } + get total() { + const ret = instance.exports.bjs_RenamedMembers_count_get(this.pointer); + return ret; + } + static get sharedTotal() { + const ret = instance.exports.bjs_RenamedMembers_static_sharedCount_get(); + return ret; + } + static set sharedTotal(value) { + instance.exports.bjs_RenamedMembers_static_sharedCount_set(value); + } + static get readOnlyLimit() { + const ret = instance.exports.bjs_RenamedMembers_static_limit_get(); + return ret; + } + } + const RenamedVectorHelpers = __bjs_createRenamedVectorHelpers(); + structHelpers.RenamedVector = RenamedVectorHelpers; + + const exports = { + makeGreeting: function bjs_makeGreeting(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + instance.exports.bjs_makeGreeting(nameId, nameBytes.length); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + greetName: function bjs_greetName(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + instance.exports.bjs_greetName(nameId, nameBytes.length); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + greetCount: function bjs_greetCount(count) { + instance.exports.bjs_greetCount(count); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + RenamedEnumMembers: { + ...RenamedEnumMembersValues, + describeCase: function() { + instance.exports.bjs_RenamedEnumMembers_static_describeCase(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + get currentDefault() { + instance.exports.bjs_RenamedEnumMembers_static_defaultValue_get(); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + }, + set currentDefault(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_RenamedEnumMembers_static_defaultValue_set(valueId, valueBytes.length); + } + }, + RenamedMembers, + RenamedNamespaceMembers: { + get theAnswer() { + const ret = instance.exports.bjs_RenamedNamespaceMembers_static_answer_get(); + return ret; + }, + set theAnswer(value) { + instance.exports.bjs_RenamedNamespaceMembers_static_answer_set(value); + }, + plus: function bjs_RenamedNamespaceMembers_static_plus(a, b) { + const ret = instance.exports.bjs_RenamedNamespaceMembers_static_plus(a, b); + return ret; + }, + }, + RenamedVector: { + get originVector() { + instance.exports.bjs_RenamedVector_static_origin_get(); + const structValue = structHelpers.RenamedVector.lift(); + return structValue; + }, + fromPolar: function(radius, angle) { + instance.exports.bjs_RenamedVector_static_fromPolar(radius, angle); + const structValue = structHelpers.RenamedVector.lift(); + return structValue; + }, + }, + Utils: { + Text: { + namespacedRenamed: function bjs_Utils_Text_namespacedRenamed() { + const ret = instance.exports.bjs_Utils_Text_namespacedRenamed(); + return ret; + }, + }, + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Function.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Function.md index c26841041..098a931af 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Function.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Function.md @@ -37,6 +37,27 @@ export type Exports = { } ``` +### Renaming functions in JavaScript + +If a different name is more appropriate in JavaScript or to export multiple overloaded Swift functions with distinct JavaScript names, you can pass a JavaScript identifier as the first argument to `@JS`. + +```swift +import JavaScriptKit + +@JS("greetName") public func greet(_ name: String) -> String { + return "Hello, \(name)!" +} + +@JS("greetPerson") public func greet(_ person: Person) -> String { + return "Hello, \(person.name)!" +} +``` + +```javascript +exports.greetName("World"); +exports.greetPerson({ name: "World" }); +``` + ### Throwing functions Swift functions can throw JavaScript errors using `throws(JSException)`. diff --git a/Sources/JavaScriptKit/Macros.swift b/Sources/JavaScriptKit/Macros.swift index 2750f8268..a1cdc0c44 100644 --- a/Sources/JavaScriptKit/Macros.swift +++ b/Sources/JavaScriptKit/Macros.swift @@ -140,6 +140,7 @@ public enum JSName: ExpressibleByStringLiteral { /// /// For detailed usage information, see the article . /// +/// - Parameter name: A different name to use in the exported JavaScript. /// - Parameter namespace: A dot-separated string that defines the namespace hierarchy in JavaScript. /// Each segment becomes a nested object in the resulting JavaScript structure. /// - Parameter enumStyle: Controls how enums are emitted to TypeScript for this declaration: @@ -151,6 +152,7 @@ public enum JSName: ExpressibleByStringLiteral { /// - Important: This feature is still experimental. No API stability is guaranteed, and the API may change in future releases. @attached(peer) public macro JS( + _ name: String? = nil, as aliasOf: Any.Type? = nil, namespace: String? = nil, enumStyle: JSEnumStyle = .const, diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index c9db5b2ac..6c5fe3b05 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -9825,6 +9825,39 @@ public func _bjs_makeAdder(_ base: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_renamedEcho") +@_cdecl("bjs_renamedEcho") +public func _bjs_renamedEcho(_ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + let ret = jsNameEcho(_: String.bridgeJSLiftParameter(valueBytes, valueLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_greetName") +@_cdecl("bjs_greetName") +public func _bjs_greetName(_ nameBytes: Int32, _ nameLength: Int32) -> Void { + #if arch(wasm32) + let ret = greet(_: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_greetCount") +@_cdecl("bjs_greetCount") +public func _bjs_greetCount(_ count: Int32) -> Void { + #if arch(wasm32) + let ret = greet(_: Int.bridgeJSLiftParameter(count)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_roundTripPointerFields") @_cdecl("bjs_roundTripPointerFields") public func _bjs_roundTripPointerFields() -> Void { @@ -13173,6 +13206,91 @@ fileprivate func _bjs_NestedTypeHost_wrap_extern(_ pointer: UnsafeMutableRawPoin return _bjs_NestedTypeHost_wrap_extern(pointer) } +@_expose(wasm, "bjs_JSNameRenamedClass_init") +@_cdecl("bjs_JSNameRenamedClass_init") +public func _bjs_JSNameRenamedClass_init(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = JSNameRenamedClass(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSNameRenamedClass_doubled") +@_cdecl("bjs_JSNameRenamedClass_doubled") +public func _bjs_JSNameRenamedClass_doubled(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = JSNameRenamedClass.bridgeJSLiftParameter(_self).timesTwo() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSNameRenamedClass_static_makeWithValue") +@_cdecl("bjs_JSNameRenamedClass_static_makeWithValue") +public func _bjs_JSNameRenamedClass_static_makeWithValue(_ value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = JSNameRenamedClass.create(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSNameRenamedClass_value_get") +@_cdecl("bjs_JSNameRenamedClass_value_get") +public func _bjs_JSNameRenamedClass_value_get(_ _self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = JSNameRenamedClass.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSNameRenamedClass_value_set") +@_cdecl("bjs_JSNameRenamedClass_value_set") +public func _bjs_JSNameRenamedClass_value_set(_ _self: UnsafeMutableRawPointer, _ value: Int32) -> Void { + #if arch(wasm32) + JSNameRenamedClass.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_JSNameRenamedClass_deinit") +@_cdecl("bjs_JSNameRenamedClass_deinit") +public func _bjs_JSNameRenamedClass_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension JSNameRenamedClass: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_JSNameRenamedClass_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_JSNameRenamedClass_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_JSNameRenamedClass_wrap") +fileprivate func _bjs_JSNameRenamedClass_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_JSNameRenamedClass_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_JSNameRenamedClass_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_JSNameRenamedClass_wrap_extern(pointer) +} + @_expose(wasm, "bjs_OptionalHolder_init") @_cdecl("bjs_OptionalHolder_init") public func _bjs_OptionalHolder_init(_ nullableGreeterIsSome: Int32, _ nullableGreeterValue: UnsafeMutableRawPointer, _ undefinedNumberIsSome: Int32, _ undefinedNumberValue: Float64) -> UnsafeMutableRawPointer { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index c68d264e2..d4e1878e1 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -4840,6 +4840,105 @@ ], "swiftCallName" : "NestedTypeHost" }, + { + "constructor" : { + "abiName" : "bjs_JSNameRenamedClass_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_JSNameRenamedClass_doubled", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "doubled", + "name" : "timesTwo", + "parameters" : [ + + ], + "returnType" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + }, + { + "abiName" : "bjs_JSNameRenamedClass_static_makeWithValue", + "effects" : { + "isAsync" : false, + "isStatic" : true, + "isThrows" : false + }, + "jsName" : "makeWithValue", + "name" : "create", + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "JSNameRenamedClass" + } + }, + "staticContext" : { + "className" : { + "_0" : "JSNameRenamedClass" + } + } + } + ], + "name" : "JSNameRenamedClass", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "jsName" : "current", + "name" : "value", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "JSNameRenamedClass" + }, { "constructor" : { "abiName" : "bjs_OptionalHolder_init", @@ -16832,6 +16931,87 @@ } } }, + { + "abiName" : "bjs_renamedEcho", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "renamedEcho", + "name" : "jsNameEcho", + "parameters" : [ + { + "label" : "_", + "name" : "value", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_greetName", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "greetName", + "name" : "greet", + "parameters" : [ + { + "label" : "_", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_greetCount", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "jsName" : "greetCount", + "name" : "greet", + "parameters" : [ + { + "label" : "_", + "name" : "count", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, { "abiName" : "bjs_roundTripPointerFields", "effects" : { diff --git a/Tests/BridgeJSRuntimeTests/JSNameAPIs.swift b/Tests/BridgeJSRuntimeTests/JSNameAPIs.swift new file mode 100644 index 000000000..48efcff59 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/JSNameAPIs.swift @@ -0,0 +1,34 @@ +import JavaScriptKit + +@JS("renamedEcho") func jsNameEcho(_ value: String) -> String { + return "echo: \(value)" +} + +@JS("greetName") func greet(_ name: String) -> String { + return "Hello, \(name)!" +} + +@JS("greetCount") func greet(_ count: Int) -> String { + return "Hello, \(count) people!" +} + +@JS class JSNameRenamedClass { + private var storage: Int + + @JS init(value: Int) { + self.storage = value + } + + @JS("current") var value: Int { + get { storage } + set { storage = newValue } + } + + @JS("doubled") func timesTwo() -> Int { + return storage * 2 + } + + @JS("makeWithValue") static func create(value: Int) -> JSNameRenamedClass { + return JSNameRenamedClass(value: value) + } +} diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 931d42561..9ca873301 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -281,6 +281,18 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(exports.roundTripUnsafeMutablePointer(p), p); } + assert.equal(exports.renamedEcho("hi"), "echo: hi"); + assert.equal(exports.jsNameEcho, undefined); + assert.equal(exports.greetName("John"), "Hello, John!"); + assert.equal(exports.greetCount(3), "Hello, 3 people!"); + const renamed = new exports.JSNameRenamedClass(21); + assert.equal(renamed.doubled(), 42); + assert.equal(renamed.current, 21); + renamed.current = 5; + assert.equal(renamed.doubled(), 10); + const madeRenamed = exports.JSNameRenamedClass.makeWithValue(7); + assert.equal(madeRenamed.current, 7); + const g = new exports.Greeter("John"); assert.equal(g.greet(), "Hello, John!"); From 129a15de730c4919e1fb70f32cb2719211f6d3c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 11 Aug 2026 12:03:24 +0200 Subject: [PATCH 3/3] BridgeJS: Lower imported optional stack parameters fully on the stack An imported optional whose payload is stack-only ([T]?, [String: V]?, @JS struct?) used a hybrid convention: the isSome flag crossed as a wasm i32 parameter while the payload was conditionally pushed onto the shared stacks. Optional returns and optional array elements of the same types already travel entirely on the stacks: payload first, then a 0/1 flag on the i32 stack. This lowers those parameters the same way. The Swift thunk pushes the payload (if some) followed by the flag, the wasm signature carries no argument for the parameter, and the JS handler pops the flag before conditionally lifting the payload, through the same fragment already used for optional returns and elements. The hybrid shape was the last parameter category that both passed a wasm argument and pushed stack data, which is what enabled the argument transposition fixed in #794. Every stack-touching parameter is now flagless and reverse-ordered, matching returns and elements. All other optional parameter ABIs (scalars, strings, JSObject, closures, enums, heap objects) are unchanged. --- .../Sources/BridgeJSCore/ImportTS.swift | 3 + .../Sources/BridgeJSLink/JSGlueGen.swift | 23 +--- .../BridgeJSCodegenTests/Async.swift | 12 +- .../BridgeJSCodegenTests/ImportArray.swift | 24 ++-- .../BridgeJSCodegenTests/SwiftClosure.swift | 12 +- .../SwiftStructImports.swift | 12 +- .../__Snapshots__/BridgeJSLinkTests/Async.js | 15 +-- .../BridgeJSLinkTests/ImportArray.js | 30 ++--- .../BridgeJSLinkTests/SwiftClosure.js | 21 ++-- .../BridgeJSLinkTests/SwiftStructImports.js | 21 ++-- .../JavaScriptKit/BridgeJSIntrinsics.swift | 63 +--------- .../Generated/BridgeJS.swift | 108 +++++++++--------- 12 files changed, 141 insertions(+), 203 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 286352915..e85fae221 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -939,6 +939,9 @@ extension BridgeType { throw BridgeJSCoreError("Namespace enums cannot be used as parameters") case .nullable(let wrappedType, _): let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) + if wrappedInfo.loweredParameters.isEmpty { + return LoweringParameterInfo(loweredParameters: []) + } var params = [("isSome", WasmCoreType.i32)] params.append(contentsOf: wrappedInfo.loweredParameters) return LoweringParameterInfo(loweredParameters: params, useBorrowing: wrappedInfo.useBorrowing) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 2bf656708..1602c3f45 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -668,16 +668,13 @@ struct IntrinsicJSFragment: Sendable { ) } - let innerFragment = - if wrappedType.optionalParameterUsesStackABI { - try stackLiftFragment(elementType: wrappedType) - } else { - try liftParameter(type: wrappedType, context: bridgeContext) - } + if wrappedType.optionalParameterUsesStackABI { + return try optionalElementRaiseFragment(wrappedType: wrappedType, kind: kind) + } return compositeOptionalLiftParameter( wrappedType: wrappedType, kind: kind, - innerFragment: innerFragment + innerFragment: try liftParameter(type: wrappedType, context: bridgeContext) ) } @@ -686,22 +683,14 @@ struct IntrinsicJSFragment: Sendable { kind: JSOptionalKind, innerFragment: IntrinsicJSFragment ) -> IntrinsicJSFragment { - let isStackConvention = wrappedType.optionalParameterUsesStackABI let absenceLiteral = kind.absenceLiteral - let outerParams: [String] - if isStackConvention { - outerParams = ["isSome"] - } else { - outerParams = ["isSome"] + innerFragment.parameters - } - return IntrinsicJSFragment( - parameters: outerParams, + parameters: ["isSome"] + innerFragment.parameters, printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) let isSome = arguments[0] - let innerArgs = isStackConvention ? [] : Array(arguments.dropFirst()) + let innerArgs = Array(arguments.dropFirst()) let bufferPrinter = CodeFragmentPrinter() let innerResults = try innerFragment.printCode( diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift index f2223ee7c..540ccac55 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Async.swift @@ -614,20 +614,20 @@ func _$Promise_resolve_Sq10AsyncThemeO(_ promise: JSObject, _ value: Optional Void +fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32) -> Void #else -fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32, _ value: Int32) -> Void { +fileprivate func promise_resolve_TestModule_Sq10AsyncPointV_extern(_ promise: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func promise_resolve_TestModule_Sq10AsyncPointV(_ promise: Int32, _ value: Int32) -> Void { - return promise_resolve_TestModule_Sq10AsyncPointV_extern(promise, value) +@inline(never) fileprivate func promise_resolve_TestModule_Sq10AsyncPointV(_ promise: Int32) -> Void { + return promise_resolve_TestModule_Sq10AsyncPointV_extern(promise) } func _$Promise_resolve_Sq10AsyncPointV(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { - let valueIsSome = value.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() let promiseValue = promise.bridgeJSLowerParameter() - promise_resolve_TestModule_Sq10AsyncPointV(promiseValue, valueIsSome) + promise_resolve_TestModule_Sq10AsyncPointV(promiseValue) if let error = _swift_js_take_exception() { throw error } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.swift index 9c4b49e3c..12abbd1e6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ImportArray.swift @@ -41,20 +41,20 @@ func _$logStrings(_ items: [String]) throws(JSException) -> Void { #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_optionalArrayThenArray") -fileprivate func bjs_optionalArrayThenArray_extern(_ a: Int32) -> Int32 +fileprivate func bjs_optionalArrayThenArray_extern() -> Int32 #else -fileprivate func bjs_optionalArrayThenArray_extern(_ a: Int32) -> Int32 { +fileprivate func bjs_optionalArrayThenArray_extern() -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_optionalArrayThenArray(_ a: Int32) -> Int32 { - return bjs_optionalArrayThenArray_extern(a) +@inline(never) fileprivate func bjs_optionalArrayThenArray() -> Int32 { + return bjs_optionalArrayThenArray_extern() } func _$optionalArrayThenArray(_ a: Optional<[Int]>, _ b: [Int]) throws(JSException) -> Int { let _ = b.bridgeJSLowerParameter() - let aIsSome = a.bridgeJSLowerParameter() - let ret = bjs_optionalArrayThenArray(aIsSome) + let _ = a.bridgeJSLowerParameter() + let ret = bjs_optionalArrayThenArray() if let error = _swift_js_take_exception() { throw error } @@ -63,21 +63,21 @@ func _$optionalArrayThenArray(_ a: Optional<[Int]>, _ b: [Int]) throws(JSExcepti #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_borrowedStringAroundStackParams") -fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 +fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32) -> Int32 #else -fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 { +fileprivate func bjs_borrowedStringAroundStackParams_extern(_ sBytes: Int32, _ sLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_borrowedStringAroundStackParams(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 { - return bjs_borrowedStringAroundStackParams_extern(sBytes, sLength, a) +@inline(never) fileprivate func bjs_borrowedStringAroundStackParams(_ sBytes: Int32, _ sLength: Int32) -> Int32 { + return bjs_borrowedStringAroundStackParams_extern(sBytes, sLength) } func _$borrowedStringAroundStackParams(_ s: String, _ a: Optional<[Int]>, _ b: [Int]) throws(JSException) -> Int { let ret0 = s.bridgeJSWithLoweredParameter { (sBytes, sLength) in let _ = b.bridgeJSLowerParameter() - let aIsSome = a.bridgeJSLowerParameter() - let ret = bjs_borrowedStringAroundStackParams(sBytes, sLength, aIsSome) + let _ = a.bridgeJSLowerParameter() + let ret = bjs_borrowedStringAroundStackParams(sBytes, sLength) return ret } let ret = ret0 diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift index c7ac02fb1..460ed699f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftClosure.swift @@ -992,14 +992,14 @@ public func _invoke_swift_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO(_ b #if arch(wasm32) @_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV") -fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32, _ param0: Int32) -> Void +fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32) -> Void #else -fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32, _ param0: Int32) -> Void { +fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(_ callback: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(_ callback: Int32, _ param0: Int32) -> Void { - return invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(_ callback: Int32) -> Void { + return invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV_extern(callback) } #if arch(wasm32) @@ -1019,9 +1019,9 @@ private enum _BJS_Closure_10TestModuleSq6AnimalV_Sq6AnimalV { let callback = JSObject.bridgeJSLiftParameter(callbackId) return { [callback] param0 in #if arch(wasm32) - let param0IsSome = param0.bridgeJSLowerParameter() + let _ = param0.bridgeJSLowerParameter() let callbackValue = callback.bridgeJSLowerParameter() - invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(callbackValue, param0IsSome) + invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV(callbackValue) return Optional.bridgeJSLiftReturn() #else fatalError("Only available on WebAssembly") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift index 38ec94c0d..a9c0b4481 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/SwiftStructImports.swift @@ -71,19 +71,19 @@ func _$translate(_ point: Point, _ dx: Int, _ dy: Int) throws(JSException) -> Po #if arch(wasm32) @_extern(wasm, module: "TestModule", name: "bjs_roundTripOptional") -fileprivate func bjs_roundTripOptional_extern(_ point: Int32) -> Void +fileprivate func bjs_roundTripOptional_extern() -> Void #else -fileprivate func bjs_roundTripOptional_extern(_ point: Int32) -> Void { +fileprivate func bjs_roundTripOptional_extern() -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_roundTripOptional(_ point: Int32) -> Void { - return bjs_roundTripOptional_extern(point) +@inline(never) fileprivate func bjs_roundTripOptional() -> Void { + return bjs_roundTripOptional_extern() } func _$roundTripOptional(_ point: Optional) throws(JSException) -> Optional { - let pointIsSome = point.bridgeJSLowerParameter() - bjs_roundTripOptional(pointIsSome) + let _ = point.bridgeJSLowerParameter() + bjs_roundTripOptional() if let error = _swift_js_take_exception() { throw error } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index 9f2faf589..b9f3e5e1a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -324,16 +324,17 @@ export async function createInstantiator(options, swift) { setException(error); } } - bjs["promise_resolve_TestModule_Sq10AsyncPointV"] = function(promise, value) { + bjs["promise_resolve_TestModule_Sq10AsyncPointV"] = function(promise) { try { - let optResult; - if (value) { - const struct = structHelpers.AsyncPoint.lift(); - optResult = struct; + const isSome = i32Stack.pop(); + let optValue; + if (isSome === 0) { + optValue = null; } else { - optResult = null; + const struct = structHelpers.AsyncPoint.lift(); + optValue = struct; } - swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(optResult); + swift.memory.getObject(promise)[__bjs_promiseSettlers].resolve(optValue); } catch (error) { setException(error); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 07341894e..dedcc6272 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -247,10 +247,13 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_optionalArrayThenArray"] = function bjs_optionalArrayThenArray(a) { + TestModule["bjs_optionalArrayThenArray"] = function bjs_optionalArrayThenArray() { try { - let optResult; - if (a) { + const isSome = i32Stack.pop(); + let optValue; + if (isSome === 0) { + optValue = null; + } else { const arrayLen = i32Stack.pop(); let arrayResult; if (arrayLen === -1) { @@ -263,9 +266,7 @@ export async function createInstantiator(options, swift) { } arrayResult.reverse(); } - optResult = arrayResult; - } else { - optResult = null; + optValue = arrayResult; } const arrayLen1 = i32Stack.pop(); let arrayResult1; @@ -279,18 +280,21 @@ export async function createInstantiator(options, swift) { } arrayResult1.reverse(); } - let ret = imports.optionalArrayThenArray(optResult, arrayResult1); + let ret = imports.optionalArrayThenArray(optValue, arrayResult1); return ret; } catch (error) { setException(error); return 0 } } - TestModule["bjs_borrowedStringAroundStackParams"] = function bjs_borrowedStringAroundStackParams(sBytes, sCount, a) { + TestModule["bjs_borrowedStringAroundStackParams"] = function bjs_borrowedStringAroundStackParams(sBytes, sCount) { try { const string = decodeString(sBytes, sCount); - let optResult; - if (a) { + const isSome = i32Stack.pop(); + let optValue; + if (isSome === 0) { + optValue = null; + } else { const arrayLen = i32Stack.pop(); let arrayResult; if (arrayLen === -1) { @@ -303,9 +307,7 @@ export async function createInstantiator(options, swift) { } arrayResult.reverse(); } - optResult = arrayResult; - } else { - optResult = null; + optValue = arrayResult; } const arrayLen1 = i32Stack.pop(); let arrayResult1; @@ -319,7 +321,7 @@ export async function createInstantiator(options, swift) { } arrayResult1.reverse(); } - let ret = imports.borrowedStringAroundStackParams(string, optResult, arrayResult1); + let ret = imports.borrowedStringAroundStackParams(string, optValue, arrayResult1); return ret; } catch (error) { setException(error); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 62c2de8c6..227fc38a9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -852,22 +852,23 @@ export async function createInstantiator(options, swift) { }; return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModuleSq5ThemeO_Sq5ThemeO); } - bjs["invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV"] = function(callbackId, param0) { + bjs["invoke_js_callback_TestModule_10TestModuleSq6AnimalV_Sq6AnimalV"] = function(callbackId) { try { const callback = swift.memory.getObject(callbackId); - let optResult; - if (param0) { - const struct = structHelpers.Animal.lift(); - optResult = struct; + const isSome = i32Stack.pop(); + let optValue; + if (isSome === 0) { + optValue = null; } else { - optResult = null; + const struct = structHelpers.Animal.lift(); + optValue = struct; } - let ret = callback(optResult); - const isSome = ret != null; - if (isSome) { + let ret = callback(optValue); + const isSome1 = ret != null; + if (isSome1) { structHelpers.Animal.lower(ret); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome1 ? 1 : 0); } catch (error) { setException(error); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index 4a2e18d6b..478202df5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -232,21 +232,22 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_roundTripOptional"] = function bjs_roundTripOptional(point) { + TestModule["bjs_roundTripOptional"] = function bjs_roundTripOptional() { try { - let optResult; - if (point) { - const struct = structHelpers.Point.lift(); - optResult = struct; + const isSome = i32Stack.pop(); + let optValue; + if (isSome === 0) { + optValue = null; } else { - optResult = null; + const struct = structHelpers.Point.lift(); + optValue = struct; } - let ret = imports.roundTripOptional(optResult); - const isSome = ret != null; - if (isSome) { + let ret = imports.roundTripOptional(optValue); + const isSome1 = ret != null; + if (isSome1) { structHelpers.Point.lower(ret); } - i32Stack.push(isSome ? 1 : 0); + i32Stack.push(isSome1 ? 1 : 0); } catch (error) { setException(error); } diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 4eeae4dac..ad55deb79 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -1945,14 +1945,8 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftStackType, Wrapped.Stac extension _BridgedAsOptional where Wrapped: _BridgedSwiftStackType, Wrapped.StackLiftResult == Wrapped, Wrapped: _BridgedSwiftTypeLoweredIntoVoidType { - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { - switch asOptional { - case .none: - return 0 - case .some(let array): - array.bridgeJSLowerReturn() - return 1 - } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() { + Wrapped.bridgeJSStackPushAsOptional(asOptional) } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { @@ -2369,24 +2363,6 @@ extension _BridgedAsOptional where Wrapped: _BridgedSwiftAssociatedValueEnum { } } -extension _BridgedAsOptional where Wrapped: _BridgedSwiftStruct { - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32) -> Self { - if isSome == 0 { - return Self(optional: nil) - } else { - return Self(optional: Wrapped.bridgeJSStackPop()) - } - } - - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - Wrapped.bridgeJSStackPushAsOptional(asOptional) - } - - @_spi(BridgeJS) public static func bridgeJSLiftParameter() -> Self { - Self.bridgeJSStackPop() - } -} - // MARK: - Array Support extension Array: _BridgedSwiftTypeLoweredIntoVoidType @@ -2462,41 +2438,6 @@ where Key == String, Value: _BridgedSwiftStackType, Value.StackLiftResult == Val } } -extension _BridgedAsOptional { - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 - where Wrapped == Dictionary, Value: _BridgedSwiftStackType, Value.StackLiftResult == Value { - switch asOptional { - case .none: - return 0 - case .some(let dict): - dict.bridgeJSStackPush() - return 1 - } - } - - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32) -> Self - where Wrapped == Dictionary, Value: _BridgedSwiftStackType, Value.StackLiftResult == Value { - if isSome == 0 { - return Self(optional: nil) - } - return Self(optional: Dictionary.bridgeJSStackPop()) - } - - @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> Self - where Wrapped == Dictionary, Value: _BridgedSwiftStackType, Value.StackLiftResult == Value { - let isSome = _swift_js_pop_i32() - if isSome == 0 { - return Self(optional: nil) - } - return Self(optional: Dictionary.bridgeJSStackPop()) - } - - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void - where Wrapped == Dictionary, Value: _BridgedSwiftStackType, Value.StackLiftResult == Value { - Wrapped.bridgeJSStackPushAsOptional(asOptional) - } -} - // MARK: Async Promise Awaiting /// Protocol for type-erasing `JSTypedClosure` in `_bjs_awaitPromise`. diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index 6c5fe3b05..8376c8636 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -14118,20 +14118,20 @@ func _$Promise_resolve_Sa11PublicPointV(_ promise: JSObject, _ value: [PublicPoi #if arch(wasm32) @_extern(wasm, module: "bjs", name: "promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV") -fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(_ promise: Int32, _ value: Int32) -> Void +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(_ promise: Int32) -> Void #else -fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(_ promise: Int32, _ value: Int32) -> Void { +fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(_ promise: Int32) -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV(_ promise: Int32, _ value: Int32) -> Void { - return promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(promise, value) +@inline(never) fileprivate func promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV(_ promise: Int32) -> Void { + return promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV_extern(promise) } func _$Promise_resolve_Sq11PublicPointV(_ promise: JSObject, _ value: Optional) throws(JSException) -> Void { - let valueIsSome = value.bridgeJSLowerParameter() + let _ = value.bridgeJSLowerParameter() let promiseValue = promise.bridgeJSLowerParameter() - promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV(promiseValue, valueIsSome) + promise_resolve_BridgeJSRuntimeTests_Sq11PublicPointV(promiseValue) if let error = _swift_js_take_exception() { throw error } } @@ -16727,20 +16727,20 @@ func _$jsRoundTripOptionalImportedPayloadSignal(_ value: Optional Int32 +fileprivate func bjs_jsJoinOptionalArrayThenArray_extern() -> Int32 #else -fileprivate func bjs_jsJoinOptionalArrayThenArray_extern(_ a: Int32) -> Int32 { +fileprivate func bjs_jsJoinOptionalArrayThenArray_extern() -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_jsJoinOptionalArrayThenArray(_ a: Int32) -> Int32 { - return bjs_jsJoinOptionalArrayThenArray_extern(a) +@inline(never) fileprivate func bjs_jsJoinOptionalArrayThenArray() -> Int32 { + return bjs_jsJoinOptionalArrayThenArray_extern() } func _$jsJoinOptionalArrayThenArray(_ a: Optional<[Int]>, _ b: [Int]) throws(JSException) -> String { let _ = b.bridgeJSLowerParameter() - let aIsSome = a.bridgeJSLowerParameter() - let ret = bjs_jsJoinOptionalArrayThenArray(aIsSome) + let _ = a.bridgeJSLowerParameter() + let ret = bjs_jsJoinOptionalArrayThenArray() if let error = _swift_js_take_exception() { throw error } @@ -16749,20 +16749,20 @@ func _$jsJoinOptionalArrayThenArray(_ a: Optional<[Int]>, _ b: [Int]) throws(JSE #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsJoinOptionalStructThenArray") -fileprivate func bjs_jsJoinOptionalStructThenArray_extern(_ a: Int32) -> Int32 +fileprivate func bjs_jsJoinOptionalStructThenArray_extern() -> Int32 #else -fileprivate func bjs_jsJoinOptionalStructThenArray_extern(_ a: Int32) -> Int32 { +fileprivate func bjs_jsJoinOptionalStructThenArray_extern() -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_jsJoinOptionalStructThenArray(_ a: Int32) -> Int32 { - return bjs_jsJoinOptionalStructThenArray_extern(a) +@inline(never) fileprivate func bjs_jsJoinOptionalStructThenArray() -> Int32 { + return bjs_jsJoinOptionalStructThenArray_extern() } func _$jsJoinOptionalStructThenArray(_ a: Optional, _ b: [Int]) throws(JSException) -> String { let _ = b.bridgeJSLowerParameter() - let aIsSome = a.bridgeJSLowerParameter() - let ret = bjs_jsJoinOptionalStructThenArray(aIsSome) + let _ = a.bridgeJSLowerParameter() + let ret = bjs_jsJoinOptionalStructThenArray() if let error = _swift_js_take_exception() { throw error } @@ -16793,21 +16793,21 @@ func _$jsJoinEnumThenArray(_ a: ImportedPayloadSignal, _ b: [Int]) throws(JSExce #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsJoinStringThenStackParams") -fileprivate func bjs_jsJoinStringThenStackParams_extern(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 +fileprivate func bjs_jsJoinStringThenStackParams_extern(_ sBytes: Int32, _ sLength: Int32) -> Int32 #else -fileprivate func bjs_jsJoinStringThenStackParams_extern(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 { +fileprivate func bjs_jsJoinStringThenStackParams_extern(_ sBytes: Int32, _ sLength: Int32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_jsJoinStringThenStackParams(_ sBytes: Int32, _ sLength: Int32, _ a: Int32) -> Int32 { - return bjs_jsJoinStringThenStackParams_extern(sBytes, sLength, a) +@inline(never) fileprivate func bjs_jsJoinStringThenStackParams(_ sBytes: Int32, _ sLength: Int32) -> Int32 { + return bjs_jsJoinStringThenStackParams_extern(sBytes, sLength) } func _$jsJoinStringThenStackParams(_ s: String, _ a: Optional<[Int]>, _ b: [Int]) throws(JSException) -> String { let ret0 = s.bridgeJSWithLoweredParameter { (sBytes, sLength) in let _ = b.bridgeJSLowerParameter() - let aIsSome = a.bridgeJSLowerParameter() - let ret = bjs_jsJoinStringThenStackParams(sBytes, sLength, aIsSome) + let _ = a.bridgeJSLowerParameter() + let ret = bjs_jsJoinStringThenStackParams(sBytes, sLength) return ret } let ret = ret0 @@ -16842,19 +16842,19 @@ func _$jsTranslatePoint(_ point: Point, _ dx: Int, _ dy: Int) throws(JSException #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_jsRoundTripOptionalPoint") -fileprivate func bjs_jsRoundTripOptionalPoint_extern(_ point: Int32) -> Void +fileprivate func bjs_jsRoundTripOptionalPoint_extern() -> Void #else -fileprivate func bjs_jsRoundTripOptionalPoint_extern(_ point: Int32) -> Void { +fileprivate func bjs_jsRoundTripOptionalPoint_extern() -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_jsRoundTripOptionalPoint(_ point: Int32) -> Void { - return bjs_jsRoundTripOptionalPoint_extern(point) +@inline(never) fileprivate func bjs_jsRoundTripOptionalPoint() -> Void { + return bjs_jsRoundTripOptionalPoint_extern() } func _$jsRoundTripOptionalPoint(_ point: Optional) throws(JSException) -> Optional { - let pointIsSome = point.bridgeJSLowerParameter() - bjs_jsRoundTripOptionalPoint(pointIsSome) + let _ = point.bridgeJSLowerParameter() + bjs_jsRoundTripOptionalPoint() if let error = _swift_js_take_exception() { throw error } @@ -17911,50 +17911,50 @@ fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringUndefined_s #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static") -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern(_ v: Int32) -> Void +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern() -> Void #else -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern(_ v: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern() -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static(_ v: Int32) -> Void { - return bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern(v) +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static() -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static_extern() } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static") -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static_extern(_ v: Int32) -> Void +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static_extern() -> Void #else -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static_extern(_ v: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static_extern() -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static(_ v: Int32) -> Void { - return bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static_extern(v) +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static() -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static_extern() } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static") -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern(_ v: Int32) -> Void +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern() -> Void #else -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern(_ v: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern() -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static(_ v: Int32) -> Void { - return bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern(v) +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static() -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static_extern() } #if arch(wasm32) @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static") -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static_extern(_ v: Int32) -> Void +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static_extern() -> Void #else -fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static_extern(_ v: Int32) -> Void { +fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static_extern() -> Void { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static(_ v: Int32) -> Void { - return bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static_extern(v) +@inline(never) fileprivate func bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static() -> Void { + return bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static_extern() } #if arch(wasm32) @@ -18020,8 +18020,8 @@ func _$OptionalSupportImports_jsRoundTripOptionalStringUndefined(_ name: JSUndef } func _$OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull(_ v: Optional<[JSValue]>) throws(JSException) -> Optional<[JSValue]> { - let vIsSome = v.bridgeJSLowerParameter() - bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static(vIsSome) + let _ = v.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull_static() if let error = _swift_js_take_exception() { throw error } @@ -18029,8 +18029,8 @@ func _$OptionalSupportImports_jsRoundTripOptionalJSValueArrayNull(_ v: Optional< } func _$OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined(_ v: JSUndefinedOr<[JSValue]>) throws(JSException) -> JSUndefinedOr<[JSValue]> { - let vIsSome = v.bridgeJSLowerParameter() - bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static(vIsSome) + let _ = v.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined_static() if let error = _swift_js_take_exception() { throw error } @@ -18038,8 +18038,8 @@ func _$OptionalSupportImports_jsRoundTripOptionalJSValueArrayUndefined(_ v: JSUn } func _$OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull(_ v: Optional<[String: String]>) throws(JSException) -> Optional<[String: String]> { - let vIsSome = v.bridgeJSLowerParameter() - bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static(vIsSome) + let _ = v.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull_static() if let error = _swift_js_take_exception() { throw error } @@ -18047,8 +18047,8 @@ func _$OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryNull(_ } func _$OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined(_ v: JSUndefinedOr<[String: String]>) throws(JSException) -> JSUndefinedOr<[String: String]> { - let vIsSome = v.bridgeJSLowerParameter() - bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static(vIsSome) + let _ = v.bridgeJSLowerParameter() + bjs_OptionalSupportImports_jsRoundTripOptionalStringToStringDictionaryUndefined_static() if let error = _swift_js_take_exception() { throw error }