From 2e36a76259d30a6fe4ae4f6be698741d333a20d1 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Fri, 14 Aug 2026 15:13:22 +1000 Subject: [PATCH 1/4] BridgeJS: Allow extensions to contain types --- .../BridgeJSCore/SwiftToSkeleton.swift | 97 ++-- .../BridgeJSCore/TypeDeclResolver.swift | 54 ++- .../BridgeJSCodegenTests.swift | 22 + .../MacroSwift/ExtensionNestedTypes.swift | 68 +++ .../MacroSwift/ExtensionScopeParity.swift | 25 + .../Multifile/CrossFileNestedTypeClass.swift | 11 + .../CrossFileNestedTypeExtension.swift | 6 + .../CrossFileNestedTypeExtension.json | 100 ++++ .../CrossFileNestedTypeExtension.swift | 74 +++ .../ExtensionNestedTypes.json | 370 ++++++++++++++ .../ExtensionNestedTypes.swift | 342 +++++++++++++ .../ExtensionScopeParity.json | 151 ++++++ .../ExtensionScopeParity.swift | 167 +++++++ .../ExtensionNestedTypes.d.ts | 82 ++++ .../BridgeJSLinkTests/ExtensionNestedTypes.js | 457 ++++++++++++++++++ .../ExtensionScopeParity.d.ts | 52 ++ .../BridgeJSLinkTests/ExtensionScopeParity.js | 354 ++++++++++++++ .../CrossFileNestedTypeClassAPIs.swift | 13 + .../CrossFileNestedTypeExtensionAPIs.swift | 8 + .../ExtensionNestedTypesAPIs.swift | 70 +++ .../Generated/BridgeJS.swift | 390 +++++++++++++++ .../Generated/JavaScript/BridgeJS.json | 422 ++++++++++++++++ Tests/prelude.mjs | 23 + 23 files changed, 3301 insertions(+), 57 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionNestedTypes.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionScopeParity.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeClass.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeExtension.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionNestedTypes.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionNestedTypes.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.js create mode 100644 Tests/BridgeJSRuntimeTests/CrossFileNestedTypeClassAPIs.swift create mode 100644 Tests/BridgeJSRuntimeTests/CrossFileNestedTypeExtensionAPIs.swift create mode 100644 Tests/BridgeJSRuntimeTests/ExtensionNestedTypesAPIs.swift diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index 937ec5c41..f119f5bff 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -536,12 +536,12 @@ public final class SwiftToSkeleton { if let typeDecl = typeDeclResolver.resolve(type) { if typeDecl.is(ProtocolDeclSyntax.self) { - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) + let swiftCallName = computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) return .swiftProtocol(swiftCallName) } if let enumDecl = typeDecl.as(EnumDeclSyntax.self) { - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: enumDecl, itemName: enumDecl.name.text) + let swiftCallName = computeSwiftCallName(for: enumDecl, itemName: enumDecl.name.text) if let jsAttribute = enumDecl.attributes.firstJSAttribute, let aliasTarget = extractAliasTarget(from: jsAttribute) { @@ -580,7 +580,7 @@ public final class SwiftToSkeleton { } if let structDecl = typeDecl.as(StructDeclSyntax.self) { - let swiftCallName = SwiftToSkeleton.computeSwiftCallName( + let swiftCallName = computeSwiftCallName( for: structDecl, itemName: structDecl.name.text ) @@ -598,7 +598,7 @@ public final class SwiftToSkeleton { guard typeDecl.is(ClassDeclSyntax.self) || typeDecl.is(ActorDeclSyntax.self) else { return nil } - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) + let swiftCallName = computeSwiftCallName(for: typeDecl, itemName: typeDecl.name.text) // A type annotated with @JSClass is a JavaScript object wrapper (imported), // even if it is declared as a Swift class. @@ -638,7 +638,7 @@ public final class SwiftToSkeleton { private func resolveExternal(for type: TypeSyntax, errors: inout [DiagnosticError]) -> BridgeType? { guard !externalModuleIndex.isEmpty, - var components = typeDeclResolver.qualifiedComponents(from: type) + var components = type.qualifiedComponents else { return nil } @@ -777,27 +777,50 @@ public final class SwiftToSkeleton { return nil } - /// Computes the full Swift call name by walking up the AST hierarchy to find all parent enums + /// This currently doesn’t work correctly for extensions on types defined in other modules, + /// which is fine for now since we don’t support extending @JS types from other modules. + /// This will need updating when we do. + fileprivate func enclosingDeclarations(of node: some SyntaxProtocol) -> [Syntax] { + var declarations: [Syntax] = [] + var visitedExtendedTypes: Set = [] + var currentNode: Syntax? = Syntax(node).parent + + while let parent = currentNode { + if let extensionDecl = parent.as(ExtensionDeclSyntax.self) { + if let extendedDecl = typeDeclResolver.resolve(extensionDecl.extendedType), + visitedExtendedTypes.insert(extendedDecl.id).inserted + { + declarations.append(Syntax(extendedDecl)) + currentNode = Syntax(extendedDecl).parent + } else { + currentNode = parent.parent + } + } else { + declarations.append(parent) + currentNode = parent.parent + } + } + return declarations + } + /// This generates the qualified name needed for Swift code generation (e.g., "Networking.API.HTTPServer") - fileprivate static func computeSwiftCallName(for node: some SyntaxProtocol, itemName: String) -> String { + fileprivate func computeSwiftCallName(for node: some SyntaxProtocol, itemName: String) -> String { var swiftPath: [String] = [] - var currentNode: Syntax? = node.parent - while let parent = currentNode { - if let enumDecl = parent.as(EnumDeclSyntax.self), + for declaration in enclosingDeclarations(of: node) { + if let enumDecl = declaration.as(EnumDeclSyntax.self), enumDecl.attributes.hasJSAttribute() { swiftPath.insert(enumDecl.name.text, at: 0) - } else if let structDecl = parent.as(StructDeclSyntax.self), + } else if let structDecl = declaration.as(StructDeclSyntax.self), structDecl.attributes.hasJSAttribute() { swiftPath.insert(structDecl.name.text, at: 0) - } else if let classDecl = parent.as(ClassDeclSyntax.self), + } else if let classDecl = declaration.as(ClassDeclSyntax.self), classDecl.attributes.hasJSAttribute() { swiftPath.insert(classDecl.name.text, at: 0) } - currentNode = parent.parent } if swiftPath.isEmpty { @@ -1883,7 +1906,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { resolvedNamespace: namespaceResult.namespace, parentTypeNamespace: computeParentTypeNamespace(for: node) ) - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: node, itemName: name) + let swiftCallName = parent.computeSwiftCallName(for: node, itemName: name) let explicitAccessControl = computeExplicitAtLeastInternalAccessControl( for: node, message: "Class visibility must be at least internal" @@ -1949,25 +1972,23 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } /// Walks extension members under the matching type’s state, returning whether the type was found. - /// - /// Note: The lookup scans dictionaries keyed by `makeKey(name:namespace:)`, matching only by - /// plain name. If two types share a name but differ by namespace, `.first(where:)` picks - /// whichever comes first. This is acceptable today since namespace collisions are unlikely, - /// but may need refinement if namespace-qualified extension resolution is added. func resolveExtension(_ ext: ExtensionDeclSyntax) -> Bool { - let name = ext.extendedType.trimmedDescription + guard let extendedDecl = parent.typeDeclResolver.resolve(ext.extendedType) else { + return false + } + let swiftCallName = parent.computeSwiftCallName(for: extendedDecl, itemName: extendedDecl.name.text) let state: State - if let entry = exportedClassByName.first(where: { $0.value.name == name }) { - state = .classBody(name: name, key: entry.key) - } else if let entry = exportedStructByName.first(where: { $0.value.name == name }) { - state = .structBody(name: name, key: entry.key) - } else if let entry = exportedEnumByName.first(where: { $0.value.name == name }) { - state = .enumBody(name: name, key: entry.key) - } else if exportedProtocolByName.values.contains(where: { $0.name == name }) { + if let entry = exportedClassByName.first(where: { $0.value.swiftCallName == swiftCallName }) { + state = .classBody(name: entry.value.name, key: entry.key) + } else if let entry = exportedStructByName.first(where: { $0.value.swiftCallName == swiftCallName }) { + state = .structBody(name: entry.value.name, key: entry.key) + } else if let entry = exportedEnumByName.first(where: { $0.value.swiftCallName == swiftCallName }) { + state = .enumBody(name: entry.value.name, key: entry.key) + } else if exportedProtocolByName.values.contains(where: { $0.name == swiftCallName }) { diagnose( node: ext.extendedType, message: "Protocol extensions are not supported by BridgeJS.", - hint: "You cannot extend `@JS` protocol '\(name)' with additional members" + hint: "You cannot extend `@JS` protocol '\(swiftCallName)' with additional members" ) return true } else { @@ -1986,7 +2007,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { jsAttribute: AttributeSyntax, aliasTarget: TypeSyntax ) { - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: node, itemName: node.name.text) + let swiftCallName = parent.computeSwiftCallName(for: node, itemName: node.name.text) if extractNamespace(from: jsAttribute) != nil { errors.append( DiagnosticError( @@ -2051,7 +2072,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { parentTypeNamespace: computeParentTypeNamespace(for: node) ) let emitStyle = extractEnumStyle(from: jsAttribute) ?? .const - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: node, itemName: name) + let swiftCallName = parent.computeSwiftCallName(for: node, itemName: name) let explicitAccessControl = computeExplicitAtLeastInternalAccessControl( for: node, message: "Enum visibility must be at least internal" @@ -2237,7 +2258,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { resolvedNamespace: namespaceResult.namespace, parentTypeNamespace: computeParentTypeNamespace(for: node) ) - let swiftCallName = SwiftToSkeleton.computeSwiftCallName(for: node, itemName: name) + let swiftCallName = parent.computeSwiftCallName(for: node, itemName: name) let explicitAccessControl = computeExplicitAtLeastInternalAccessControl( for: node, message: "Struct visibility must be at least internal" @@ -2552,10 +2573,9 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { /// Method allows for explicit namespace for top level enum, it will be used as base namespace and will concat enum name private func computeNamespace(for node: some SyntaxProtocol) -> [String]? { var namespace: [String] = [] - var currentNode: Syntax? = node.parent - while let parent = currentNode { - if let enumDecl = parent.as(EnumDeclSyntax.self), + for declaration in parent.enclosingDeclarations(of: node) { + if let enumDecl = declaration.as(EnumDeclSyntax.self), enumDecl.attributes.hasJSAttribute() { let isNamespaceEnum = !enumDecl.memberBlock.members.contains { member in @@ -2572,7 +2592,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } } - currentNode = parent.parent } return namespace.isEmpty ? nil : namespace @@ -2580,19 +2599,17 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { private func computeParentTypeNamespace(for node: some SyntaxProtocol) -> [String]? { var path: [String] = [] - var currentNode: Syntax? = node.parent - while let parent = currentNode { - if let structDecl = parent.as(StructDeclSyntax.self), + for declaration in parent.enclosingDeclarations(of: node) { + if let structDecl = declaration.as(StructDeclSyntax.self), structDecl.attributes.hasJSAttribute() { path.insert(structDecl.name.text, at: 0) - } else if let classDecl = parent.as(ClassDeclSyntax.self), + } else if let classDecl = declaration.as(ClassDeclSyntax.self), classDecl.attributes.hasJSAttribute() { path.insert(classDecl.name.text, at: 0) } - currentNode = parent.parent } return path.isEmpty ? nil : path diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift index ec04421aa..e5d77939b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/TypeDeclResolver.swift @@ -16,8 +16,7 @@ class TypeDeclResolver { private class TypeDeclCollector: SyntaxVisitor { let resolver: TypeDeclResolver - var scope: [TypeDecl] = [] - var rootTypeDecls: [TypeDecl] = [] + var scope: [String] = [] init(resolver: TypeDeclResolver) { self.resolver = resolver @@ -26,17 +25,14 @@ class TypeDeclResolver { func visitNominalDecl(_ node: TypeDecl) -> SyntaxVisitorContinueKind { let name = node.name.text - let qualifiedName = scope.map(\.name.text) + [name] + let qualifiedName = scope + [name] resolver.typeDeclByQualifiedName[qualifiedName] = node - scope.append(node) + scope.append(name) return .visitChildren } func visitPostNominalDecl() { - let type = scope.removeLast() - if scope.isEmpty { - rootTypeDecls.append(type) - } + scope.removeLast() } override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { @@ -72,10 +68,21 @@ class TypeDeclResolver { override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { let name = node.name.text - let qualifiedName = scope.map(\.name.text) + [name] + let qualifiedName = scope + [name] resolver.typeAliasByQualifiedName[qualifiedName] = node return .skipChildren } + + override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + guard let components = node.memberScopeComponents else { + return .skipChildren + } + scope.append(contentsOf: components) + return .visitChildren + } + override func visitPost(_ node: ExtensionDeclSyntax) { + scope.removeLast(node.memberScopeComponents?.count ?? 0) + } } /// Collects type declarations from a parsed Swift source file @@ -91,6 +98,10 @@ class TypeDeclResolver { while let parent = context.parent { if let parent = parent.asProtocol(NamedDeclSyntax.self), parent.isProtocol(DeclGroupSyntax.self) { innerToOuter.append(parent.name.text) + } else if let extensionDecl = parent.as(ExtensionDeclSyntax.self), + let components = extensionDecl.memberScopeComponents + { + innerToOuter.append(contentsOf: components.reversed()) } context = parent } @@ -106,7 +117,7 @@ class TypeDeclResolver { /// Search for the type declaration from the innermost scope to the outermost scope for i in (0...scope.count).reversed() { let qualifiedName = Array(scope[0.. QualifiedName? { - if let m = type.as(MemberTypeSyntax.self) { - guard let base = qualifiedComponents(from: TypeSyntax(m.baseType)) else { return nil } +} + +extension TypeSyntax { + var qualifiedComponents: TypeDeclResolver.QualifiedName? { + if let m = self.as(MemberTypeSyntax.self) { + guard let base = TypeSyntax(m.baseType).qualifiedComponents else { return nil } return base + [m.name.text] - } else if let id = type.as(IdentifierTypeSyntax.self) { + } else if let id = self.as(IdentifierTypeSyntax.self) { return [id.name.text] } else { return nil } } } + +extension ExtensionDeclSyntax { + var memberScopeComponents: TypeDeclResolver.QualifiedName? { + extendedType.qualifiedComponents + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index 6d2f3d453..baffc0c20 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -336,6 +336,28 @@ import Testing try snapshotCodegen(skeleton: skeleton, name: "CrossFileExtension") } + @Test + func codegenCrossFileNestedTypeExtension() throws { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + let classURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileNestedTypeClass.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: classURL, encoding: .utf8)), + inputFilePath: "CrossFileNestedTypeClass.swift" + ) + let extensionURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileNestedTypeExtension.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: extensionURL, encoding: .utf8)), + inputFilePath: "CrossFileNestedTypeExtension.swift" + ) + let skeleton = try swiftAPI.finalize() + try snapshotCodegen(skeleton: skeleton, name: "CrossFileNestedTypeExtension") + } + @Test func codegenSkipsEmptySkeletons() throws { let swiftAPI = SwiftToSkeleton( diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionNestedTypes.swift new file mode 100644 index 000000000..b3ef8ddaf --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionNestedTypes.swift @@ -0,0 +1,68 @@ +@JS class Library { + @JS var name: String + + @JS init(name: String) { + self.name = name + } + + @JS func describe() -> String { + name + } +} + +extension Library { + typealias Title = String + + @JS enum Genre: String { + case fiction + case reference + } + + @JS struct Shelf { + var label: String + + @JS init(label: String) { + self.label = label + } + + @JS static var capacity: Int { 32 } + } + + @JS func rename(_ title: Title) -> Title { + title + } + + @JS func shelf(label: String) -> Shelf { + Shelf(label: label) + } +} + +extension Library.Shelf { + @JS struct Divider { + var slot: Int + + @JS init(slot: Int) { + self.slot = slot + } + } + + @JS func describeShelf() -> String { + "Shelf: " + label + } +} + +@JS enum Message { + case update(Update) + case delete +} + +extension Message { + @JS enum Update { + case flip + case rotate + } +} + +@JS func roundTripMessage(_ message: Message) -> Message { + message +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionScopeParity.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionScopeParity.swift new file mode 100644 index 000000000..43a71c484 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionScopeParity.swift @@ -0,0 +1,25 @@ +@JS(namespace: "app") enum Toolbox { + @JS class Mallet { + @JS init() {} + } +} + +extension Toolbox { + @JS class Hammer { + @JS init() {} + } +} + +@JS enum Signal: String { + case ready +} + +extension Signal { + @JS struct Meta { + var note: String + + @JS init(note: String) { + self.note = note + } + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeClass.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeClass.swift new file mode 100644 index 000000000..7fa16b59f --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeClass.swift @@ -0,0 +1,11 @@ +@JS class Workspace { + let name: String + + @JS init(name: String) { + self.name = name + } + + @JS func describe() -> String { + name + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeExtension.swift new file mode 100644 index 000000000..1e99eae1e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileNestedTypeExtension.swift @@ -0,0 +1,6 @@ +extension Workspace { + @JS enum Kind: String { + case personal + case shared + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.json new file mode 100644 index 000000000..ad8a71bb7 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.json @@ -0,0 +1,100 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Workspace_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Workspace_describe", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describe", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Workspace", + "properties" : [ + + ], + "swiftCallName" : "Workspace" + } + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "personal" + }, + { + "associatedValues" : [ + + ], + "name" : "shared" + } + ], + "emitStyle" : "const", + "name" : "Kind", + "namespace" : [ + "Workspace" + ], + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Workspace.Kind", + "tsFullPath" : "Workspace.Kind" + } + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.swift new file mode 100644 index 000000000..7601f0f72 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileNestedTypeExtension.swift @@ -0,0 +1,74 @@ +extension Workspace.Kind: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +@_expose(wasm, "bjs_Workspace_init") +@_cdecl("bjs_Workspace_init") +public func _bjs_Workspace_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Workspace(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Workspace_describe") +@_cdecl("bjs_Workspace_describe") +public func _bjs_Workspace_describe(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Workspace.bridgeJSLiftParameter(_self).describe() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Workspace_deinit") +@_cdecl("bjs_Workspace_deinit") +public func _bjs_Workspace_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Workspace: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Workspace_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Workspace_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Workspace_wrap") +fileprivate func _bjs_Workspace_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Workspace_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Workspace_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Workspace_wrap_extern(pointer) +} + +extension Workspace.Kind: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Workspace.Kind.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Workspace.Kind.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.json new file mode 100644 index 000000000..e6cf2b271 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.json @@ -0,0 +1,370 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Library_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Library_describe", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describe", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Library_rename", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "rename", + "parameters" : [ + { + "label" : "_", + "name" : "title", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Library_shelf", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "shelf", + "parameters" : [ + { + "label" : "label", + "name" : "label", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Library.Shelf" + } + } + } + ], + "name" : "Library", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Library" + } + ], + "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "caseEnum" : { + "_0" : "Message.Update" + } + } + } + ], + "name" : "update" + }, + { + "associatedValues" : [ + + ], + "name" : "delete" + } + ], + "emitStyle" : "const", + "name" : "Message", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Message", + "tsFullPath" : "Message" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "fiction" + }, + { + "associatedValues" : [ + + ], + "name" : "reference" + } + ], + "emitStyle" : "const", + "name" : "Genre", + "namespace" : [ + "Library" + ], + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Library.Genre", + "tsFullPath" : "Library.Genre" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "flip" + }, + { + "associatedValues" : [ + + ], + "name" : "rotate" + } + ], + "emitStyle" : "const", + "name" : "Update", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Message.Update", + "tsFullPath" : "Update" + } + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_roundTripMessage", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripMessage", + "parameters" : [ + { + "label" : "_", + "name" : "message", + "type" : { + "associatedValueEnum" : { + "_0" : "Message" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "Message" + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + { + "constructor" : { + "abiName" : "bjs_Library_Shelf_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "label", + "name" : "label", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Library_Shelf_describeShelf", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describeShelf", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Shelf", + "namespace" : [ + "Library" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "label", + "namespace" : [ + "Library" + ], + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "capacity", + "staticContext" : { + "structName" : { + "_0" : "Library_Shelf" + } + }, + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "Library.Shelf" + }, + { + "constructor" : { + "abiName" : "bjs_Library_Shelf_Divider_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "slot", + "name" : "slot", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Divider", + "namespace" : [ + "Library", + "Shelf" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "slot", + "namespace" : [ + "Library", + "Shelf" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "Library.Shelf.Divider" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.swift new file mode 100644 index 000000000..d7efa630c --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionNestedTypes.swift @@ -0,0 +1,342 @@ +extension Message: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> Message { + switch caseId { + case 0: + return .update(Message.Update.bridgeJSStackPop()) + case 1: + return .delete + default: + fatalError("Unknown Message case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .update(let param0): + param0.bridgeJSStackPush() + return Int32(0) + case .delete: + return Int32(1) + } + } +} + +extension Library.Genre: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension Message.Update: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Message.Update { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Message.Update { + return Message.Update(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .flip + case 1: + self = .rotate + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .flip: + return 0 + case .rotate: + return 1 + } + } +} + +extension Library.Shelf: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Library.Shelf { + let label = String.bridgeJSStackPop() + return Library.Shelf(label: label) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.label.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Library_Shelf(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Library_Shelf())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Library_Shelf") +fileprivate func _bjs_struct_lower_Library_Shelf_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Library_Shelf_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Library_Shelf(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Library_Shelf_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Library_Shelf") +fileprivate func _bjs_struct_lift_Library_Shelf_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Library_Shelf_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Library_Shelf() -> Int32 { + return _bjs_struct_lift_Library_Shelf_extern() +} + +@_expose(wasm, "bjs_Library_Shelf_init") +@_cdecl("bjs_Library_Shelf_init") +public func _bjs_Library_Shelf_init(_ labelBytes: Int32, _ labelLength: Int32) -> Void { + #if arch(wasm32) + let ret = Library.Shelf(label: String.bridgeJSLiftParameter(labelBytes, labelLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_Shelf_static_capacity_get") +@_cdecl("bjs_Library_Shelf_static_capacity_get") +public func _bjs_Library_Shelf_static_capacity_get() -> Int32 { + #if arch(wasm32) + let ret = Library.Shelf.capacity + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_Shelf_describeShelf") +@_cdecl("bjs_Library_Shelf_describeShelf") +public func _bjs_Library_Shelf_describeShelf() -> Void { + #if arch(wasm32) + let ret = Library.Shelf.bridgeJSLiftParameter().describeShelf() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Library.Shelf.Divider: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Library.Shelf.Divider { + let slot = Int.bridgeJSStackPop() + return Library.Shelf.Divider(slot: slot) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.slot.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Library_Shelf_Divider(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Library_Shelf_Divider())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Library_Shelf_Divider") +fileprivate func _bjs_struct_lower_Library_Shelf_Divider_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Library_Shelf_Divider_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Library_Shelf_Divider(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Library_Shelf_Divider_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Library_Shelf_Divider") +fileprivate func _bjs_struct_lift_Library_Shelf_Divider_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Library_Shelf_Divider_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Library_Shelf_Divider() -> Int32 { + return _bjs_struct_lift_Library_Shelf_Divider_extern() +} + +@_expose(wasm, "bjs_Library_Shelf_Divider_init") +@_cdecl("bjs_Library_Shelf_Divider_init") +public func _bjs_Library_Shelf_Divider_init(_ slot: Int32) -> Void { + #if arch(wasm32) + let ret = Library.Shelf.Divider(slot: Int.bridgeJSLiftParameter(slot)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_roundTripMessage") +@_cdecl("bjs_roundTripMessage") +public func _bjs_roundTripMessage(_ message: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripMessage(_: Message.bridgeJSLiftParameter(message)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_init") +@_cdecl("bjs_Library_init") +public func _bjs_Library_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Library(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_describe") +@_cdecl("bjs_Library_describe") +public func _bjs_Library_describe(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).describe() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_rename") +@_cdecl("bjs_Library_rename") +public func _bjs_Library_rename(_ _self: UnsafeMutableRawPointer, _ titleBytes: Int32, _ titleLength: Int32) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).rename(_: String.bridgeJSLiftParameter(titleBytes, titleLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_shelf") +@_cdecl("bjs_Library_shelf") +public func _bjs_Library_shelf(_ _self: UnsafeMutableRawPointer, _ labelBytes: Int32, _ labelLength: Int32) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).shelf(label: String.bridgeJSLiftParameter(labelBytes, labelLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_name_get") +@_cdecl("bjs_Library_name_get") +public func _bjs_Library_name_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).name + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_name_set") +@_cdecl("bjs_Library_name_set") +public func _bjs_Library_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + Library.bridgeJSLiftParameter(_self).name = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_deinit") +@_cdecl("bjs_Library_deinit") +public func _bjs_Library_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Library: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Library_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Library_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Library_wrap") +fileprivate func _bjs_Library_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Library_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Library_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Library_wrap_extern(pointer) +} + +extension Library.Shelf: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Shelf.bridgeJSMakeTypeHandle() +} + +extension Library.Shelf.Divider: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Shelf.Divider.bridgeJSMakeTypeHandle() +} + +extension Message: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Message.bridgeJSMakeTypeHandle() +} + +extension Library.Genre: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Genre.bridgeJSMakeTypeHandle() +} + +extension Message.Update: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Message.Update.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Library.Shelf.bridgeJSTypeID, + Library.Shelf.Divider.bridgeJSTypeID, + Message.bridgeJSTypeID, + Library.Genre.bridgeJSTypeID, + Message.Update.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.json new file mode 100644 index 000000000..2e25e938e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.json @@ -0,0 +1,151 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_app_Toolbox_Mallet_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + + ], + "name" : "Mallet", + "namespace" : [ + "app", + "Toolbox" + ], + "properties" : [ + + ], + "swiftCallName" : "Toolbox.Mallet" + }, + { + "constructor" : { + "abiName" : "bjs_app_Toolbox_Hammer_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + + ], + "name" : "Hammer", + "namespace" : [ + "app", + "Toolbox" + ], + "properties" : [ + + ], + "swiftCallName" : "Toolbox.Hammer" + } + ], + "enums" : [ + { + "cases" : [ + + ], + "emitStyle" : "const", + "name" : "Toolbox", + "namespace" : [ + "app" + ], + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Toolbox", + "tsFullPath" : "app.Toolbox" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "ready" + } + ], + "emitStyle" : "const", + "name" : "Signal", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Signal", + "tsFullPath" : "Signal" + } + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "constructor" : { + "abiName" : "bjs_Meta_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "note", + "name" : "note", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Meta", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "note", + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Signal.Meta" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.swift new file mode 100644 index 000000000..7fe6db4d2 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionScopeParity.swift @@ -0,0 +1,167 @@ +extension Signal: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension Signal.Meta: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Signal.Meta { + let note = String.bridgeJSStackPop() + return Signal.Meta(note: note) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.note.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Meta(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Meta())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Meta") +fileprivate func _bjs_struct_lower_Meta_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Meta_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Meta(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Meta_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Meta") +fileprivate func _bjs_struct_lift_Meta_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Meta_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Meta() -> Int32 { + return _bjs_struct_lift_Meta_extern() +} + +@_expose(wasm, "bjs_Meta_init") +@_cdecl("bjs_Meta_init") +public func _bjs_Meta_init(_ noteBytes: Int32, _ noteLength: Int32) -> Void { + #if arch(wasm32) + let ret = Signal.Meta(note: String.bridgeJSLiftParameter(noteBytes, noteLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_app_Toolbox_Mallet_init") +@_cdecl("bjs_app_Toolbox_Mallet_init") +public func _bjs_app_Toolbox_Mallet_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Toolbox.Mallet() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_app_Toolbox_Mallet_deinit") +@_cdecl("bjs_app_Toolbox_Mallet_deinit") +public func _bjs_app_Toolbox_Mallet_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Toolbox.Mallet: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_app_Toolbox_Mallet_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_app_Toolbox_Mallet_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_app_Toolbox_Mallet_wrap") +fileprivate func _bjs_app_Toolbox_Mallet_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_app_Toolbox_Mallet_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_app_Toolbox_Mallet_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_app_Toolbox_Mallet_wrap_extern(pointer) +} + +@_expose(wasm, "bjs_app_Toolbox_Hammer_init") +@_cdecl("bjs_app_Toolbox_Hammer_init") +public func _bjs_app_Toolbox_Hammer_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Toolbox.Hammer() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_app_Toolbox_Hammer_deinit") +@_cdecl("bjs_app_Toolbox_Hammer_deinit") +public func _bjs_app_Toolbox_Hammer_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Toolbox.Hammer: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_app_Toolbox_Hammer_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_app_Toolbox_Hammer_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_app_Toolbox_Hammer_wrap") +fileprivate func _bjs_app_Toolbox_Hammer_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_app_Toolbox_Hammer_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_app_Toolbox_Hammer_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_app_Toolbox_Hammer_wrap_extern(pointer) +} + +extension Signal.Meta: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Signal.Meta.bridgeJSMakeTypeHandle() +} + +extension Signal: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Signal.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Signal.Meta.bridgeJSTypeID, + Signal.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionNestedTypes.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionNestedTypes.d.ts new file mode 100644 index 000000000..df59ccefd --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionNestedTypes.d.ts @@ -0,0 +1,82 @@ +// 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 MessageValues: { + readonly Tag: { + readonly Update: 0; + readonly Delete: 1; + }; +}; + +export type MessageTag = + { tag: typeof MessageValues.Tag.Update; param0: UpdateTag } | { tag: typeof MessageValues.Tag.Delete } + +export const UpdateValues: { + readonly Flip: 0; + readonly Rotate: 1; +}; +export type UpdateTag = typeof UpdateValues[keyof typeof UpdateValues]; + +export type MessageObject = typeof MessageValues; + +export type GenreObject = typeof Library.GenreValues; + +export type UpdateObject = typeof UpdateValues; + +export namespace Library { + const GenreValues: { + readonly Fiction: "fiction"; + readonly Reference: "reference"; + }; + type GenreTag = typeof GenreValues[keyof typeof GenreValues]; + export interface Shelf { + label: string; + describeShelf(): string; + } + export namespace Shelf { + export interface Divider { + slot: number; + } + } +} +/// Represents a Swift heap object like a class instance or an actor instance. +export interface SwiftHeapObject { + /// Release the heap object. + /// + /// Note: Calling this method will release the heap object and it will no longer be accessible. + release(): void; +} +export interface Library extends SwiftHeapObject { + describe(): string; + rename(title: string): string; + shelf(label: string): Library.Shelf; + name: string; +} +export type Exports = { + roundTripMessage(message: MessageTag): MessageTag; + Message: MessageObject + Update: UpdateObject + Library: { + new(name: string): Library; + Genre: GenreObject + Shelf: { + init(label: string): Library.Shelf; + readonly capacity: number; + Divider: { + init(slot: number): Library.Shelf.Divider; + }, + }, + }, +} +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/ExtensionNestedTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionNestedTypes.js new file mode 100644 index 000000000..d031ff64b --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionNestedTypes.js @@ -0,0 +1,457 @@ +// 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 MessageValues = { + Tag: { + Update: 0, + Delete: 1, + }, +}; +export const GenreValues = { + Fiction: "fiction", + Reference: "reference", +}; + +export const UpdateValues = { + Flip: 0, + Rotate: 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_createStructHelpers_M10TestModuleT7LibraryT5Shelf = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.label); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + const instance1 = { label: string }; + instance1.describeShelf = function() { + structHelpers.M10TestModuleT7LibraryT5Shelf.lower(this); + const ret = instance.exports.bjs_Library_Shelf_describeShelf(); + const ret1 = tmpRetString; + tmpRetString = undefined; + return ret1; + }.bind(instance1); + return instance1; + } + }); + const __bjs_createStructHelpers_M10TestModuleT7LibraryT5ShelfT7Divider = () => ({ + lower: (value) => { + i32Stack.push((value.slot | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return { slot: int }; + } + }); + const __bjs_createEnumHelpers_M10TestModuleT7Message = () => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case MessageValues.Tag.Update: { + i32Stack.push((value.param0 | 0)); + return MessageValues.Tag.Update; + } + case MessageValues.Tag.Delete: { + return MessageValues.Tag.Delete; + } + default: throw new Error("Unknown MessageValues tag: " + String(enumTag)); + } + }, + lift: (tag) => { + tag = tag | 0; + switch (tag) { + case MessageValues.Tag.Update: { + const caseId = i32Stack.pop(); + return { tag: MessageValues.Tag.Update, param0: caseId }; + } + case MessageValues.Tag.Delete: return { tag: MessageValues.Tag.Delete }; + default: throw new Error("Unknown MessageValues tag returned from Swift: " + String(tag)); + } + } + }); + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr >>> 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_Library_Shelf"] = function(objectId) { + structHelpers.M10TestModuleT7LibraryT5Shelf.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Library_Shelf"] = function() { + const value = structHelpers.M10TestModuleT7LibraryT5Shelf.lift(); + return swift.memory.retain(value); + } + bjs["swift_js_struct_lower_Library_Shelf_Divider"] = function(objectId) { + structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Library_Shelf_Divider"] = function() { + const value = structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lift(); + return swift.memory.retain(value); + } + bjs["bjs_core_register_type_handles"] = function() {}; + bjs["bjs_TestModule_register_type_handles"] = function() {}; + 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_Library_wrap"] = function(pointer) { + const obj = _exports['Library'].__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 Library extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Library_deinit, Library.prototype, null); + } + + constructor(name) { + const nameBytes = textEncoder.encode(name); + const nameId = swift.memory.retain(nameBytes); + const ret = instance.exports.bjs_Library_init(nameId, nameBytes.length); + return Library.__construct(ret); + } + describe() { + instance.exports.bjs_Library_describe(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + rename(title) { + const titleBytes = textEncoder.encode(title); + const titleId = swift.memory.retain(titleBytes); + instance.exports.bjs_Library_rename(this.pointer, titleId, titleBytes.length); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + shelf(label) { + const labelBytes = textEncoder.encode(label); + const labelId = swift.memory.retain(labelBytes); + instance.exports.bjs_Library_shelf(this.pointer, labelId, labelBytes.length); + const structValue = structHelpers.M10TestModuleT7LibraryT5Shelf.lift(); + return structValue; + } + get name() { + instance.exports.bjs_Library_name_get(this.pointer); + const ret = tmpRetString; + tmpRetString = undefined; + return ret; + } + set name(value) { + const valueBytes = textEncoder.encode(value); + const valueId = swift.memory.retain(valueBytes); + instance.exports.bjs_Library_name_set(this.pointer, valueId, valueBytes.length); + } + } + const __bjs_helpers_M10TestModuleT7LibraryT5Shelf = __bjs_createStructHelpers_M10TestModuleT7LibraryT5Shelf(); + structHelpers.M10TestModuleT7LibraryT5Shelf = __bjs_helpers_M10TestModuleT7LibraryT5Shelf; + + const __bjs_helpers_M10TestModuleT7LibraryT5ShelfT7Divider = __bjs_createStructHelpers_M10TestModuleT7LibraryT5ShelfT7Divider(); + structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider = __bjs_helpers_M10TestModuleT7LibraryT5ShelfT7Divider; + + const __bjs_helpers_M10TestModuleT7Message = __bjs_createEnumHelpers_M10TestModuleT7Message(); + enumHelpers.M10TestModuleT7Message = __bjs_helpers_M10TestModuleT7Message; + + const exports = { + roundTripMessage: function bjs_roundTripMessage(message) { + const messageCaseId = enumHelpers.M10TestModuleT7Message.lower(message); + instance.exports.bjs_roundTripMessage(messageCaseId); + const ret = enumHelpers.M10TestModuleT7Message.lift(i32Stack.pop()); + return ret; + }, + Message: MessageValues, + Update: UpdateValues, + Library: Object.assign(Library, { + Genre: GenreValues, + Shelf: { + init: function(label) { + const labelBytes = textEncoder.encode(label); + const labelId = swift.memory.retain(labelBytes); + instance.exports.bjs_Library_Shelf_init(labelId, labelBytes.length); + const structValue = structHelpers.M10TestModuleT7LibraryT5Shelf.lift(); + return structValue; + }, + get capacity() { + const ret = instance.exports.bjs_Library_Shelf_static_capacity_get(); + return ret; + }, + Divider: { + init: function(slot) { + instance.exports.bjs_Library_Shelf_Divider_init(slot); + const structValue = structHelpers.M10TestModuleT7LibraryT5ShelfT7Divider.lift(); + return structValue; + }, + }, + }, + }), + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts new file mode 100644 index 000000000..74569a6db --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts @@ -0,0 +1,52 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export const SignalValues: { + readonly Ready: "ready"; +}; +export type SignalTag = typeof SignalValues[keyof typeof SignalValues]; + +export interface Meta { + note: string; +} +export type SignalObject = typeof SignalValues; + +/// 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 Mallet extends SwiftHeapObject { +} +export interface Hammer extends SwiftHeapObject { +} +export type Exports = { + Signal: SignalObject + Meta: { + init(note: string): Signal.Meta; + }, + app: { + Toolbox: { + Hammer: { + new(): Hammer; + }, + Mallet: { + new(): Mallet; + }, + }, + }, +} +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/ExtensionScopeParity.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.js new file mode 100644 index 000000000..6b8ae44b1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.js @@ -0,0 +1,354 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export const SignalValues = { + Ready: "ready", +}; + +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_createStructHelpers_M10TestModuleT6SignalT4Meta = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.note); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return { note: string }; + } + }); + + 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_Meta"] = function(objectId) { + structHelpers.M10TestModuleT6SignalT4Meta.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Meta"] = function() { + const value = structHelpers.M10TestModuleT6SignalT4Meta.lift(); + return swift.memory.retain(value); + } + bjs["bjs_core_register_type_handles"] = function() {}; + bjs["bjs_TestModule_register_type_handles"] = function() {}; + 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_app_Toolbox_Hammer_wrap"] = function(pointer) { + const obj = _exports.app.Toolbox.Hammer.__construct(pointer); + return swift.memory.retain(obj); + }; + importObject["TestModule"]["bjs_app_Toolbox_Mallet_wrap"] = function(pointer) { + const obj = _exports.app.Toolbox.Mallet.__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 Mallet extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_app_Toolbox_Mallet_deinit, Mallet.prototype, null); + } + + constructor() { + const ret = instance.exports.bjs_app_Toolbox_Mallet_init(); + return Mallet.__construct(ret); + } + } + class Hammer extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_app_Toolbox_Hammer_deinit, Hammer.prototype, null); + } + + constructor() { + const ret = instance.exports.bjs_app_Toolbox_Hammer_init(); + return Hammer.__construct(ret); + } + } + const __bjs_helpers_M10TestModuleT6SignalT4Meta = __bjs_createStructHelpers_M10TestModuleT6SignalT4Meta(); + structHelpers.M10TestModuleT6SignalT4Meta = __bjs_helpers_M10TestModuleT6SignalT4Meta; + + const exports = { + Signal: SignalValues, + Meta: { + init: function(note) { + const noteBytes = textEncoder.encode(note); + const noteId = swift.memory.retain(noteBytes); + instance.exports.bjs_Meta_init(noteId, noteBytes.length); + const structValue = structHelpers.M10TestModuleT6SignalT4Meta.lift(); + return structValue; + }, + }, + app: { + Toolbox: { + Hammer, + Mallet, + }, + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/CrossFileNestedTypeClassAPIs.swift b/Tests/BridgeJSRuntimeTests/CrossFileNestedTypeClassAPIs.swift new file mode 100644 index 000000000..8663f1fe5 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/CrossFileNestedTypeClassAPIs.swift @@ -0,0 +1,13 @@ +import JavaScriptKit + +@JS class Workspace { + let name: String + + @JS init(name: String) { + self.name = name + } + + @JS func describe() -> String { + name + } +} diff --git a/Tests/BridgeJSRuntimeTests/CrossFileNestedTypeExtensionAPIs.swift b/Tests/BridgeJSRuntimeTests/CrossFileNestedTypeExtensionAPIs.swift new file mode 100644 index 000000000..c50446ee2 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/CrossFileNestedTypeExtensionAPIs.swift @@ -0,0 +1,8 @@ +import JavaScriptKit + +extension Workspace { + @JS enum Kind: String { + case personal + case shared + } +} diff --git a/Tests/BridgeJSRuntimeTests/ExtensionNestedTypesAPIs.swift b/Tests/BridgeJSRuntimeTests/ExtensionNestedTypesAPIs.swift new file mode 100644 index 000000000..b09807ac7 --- /dev/null +++ b/Tests/BridgeJSRuntimeTests/ExtensionNestedTypesAPIs.swift @@ -0,0 +1,70 @@ +import JavaScriptKit + +@JS class Library { + @JS var name: String + + @JS init(name: String) { + self.name = name + } + + @JS func describe() -> String { + name + } +} + +extension Library { + typealias Title = String + + @JS enum Genre: String { + case fiction + case reference + } + + @JS struct Shelf { + var label: String + + @JS init(label: String) { + self.label = label + } + + @JS static var capacity: Int { 32 } + } + + @JS func rename(_ title: Title) -> Title { + title + } + + @JS func shelf(label: String) -> Shelf { + Shelf(label: label) + } +} + +extension Library.Shelf { + @JS struct Divider { + var slot: Int + + @JS init(slot: Int) { + self.slot = slot + } + } + + @JS func describeShelf() -> String { + "Shelf: " + label + } +} + +@JS enum Message { + case update(Update) + case delete +} + +extension Message { + @JS enum Update { + case flip + case rotate + } +} + +@JS func roundTripMessage(_ message: Message) -> Message { + message +} diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift index e453e3534..f16bce9f2 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift @@ -4878,6 +4878,9 @@ extension AsyncImportedPayloadResult: _BridgedSwiftAssociatedValueEnum { } } +extension Workspace.Kind: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + @_expose(wasm, "bjs_DefaultArgumentExports_static_testStringDefault") @_cdecl("bjs_DefaultArgumentExports_static_testStringDefault") public func _bjs_DefaultArgumentExports_static_testStringDefault(_ messageBytes: Int32, _ messageLength: Int32) -> Void { @@ -5924,6 +5927,67 @@ public func _bjs_NestedStructGroupB_static_roundtripMetadata() -> Void { extension NestedTypeHost.Variant: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { } +extension Message: _BridgedSwiftAssociatedValueEnum { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPopPayload(_ caseId: Int32) -> Message { + switch caseId { + case 0: + return .update(Message.Update.bridgeJSStackPop()) + case 1: + return .delete + default: + fatalError("Unknown Message case ID: \(caseId)") + } + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPushPayload() -> Int32 { + switch self { + case .update(let param0): + param0.bridgeJSStackPush() + return Int32(0) + case .delete: + return Int32(1) + } + } +} + +extension Library.Genre: _BridgedSwiftEnumNoPayload, _BridgedSwiftRawValueEnum { +} + +extension Message.Update: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Message.Update { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Message.Update { + return Message.Update(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + @_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .flip + case 1: + self = .rotate + default: + return nil + } + } + + @_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 { + switch self { + case .flip: + return 0 + case .rotate: + return 1 + } + } +} + extension LightColor: _BridgedSwiftCaseEnum { @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { return bridgeJSRawValue @@ -6848,6 +6912,142 @@ public func _bjs_NestedTypeHost_Label_static_untitled() -> Void { #endif } +extension Library.Shelf: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Library.Shelf { + let label = String.bridgeJSStackPop() + return Library.Shelf(label: label) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.label.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Library_Shelf(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Library_Shelf())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Library_Shelf") +fileprivate func _bjs_struct_lower_Library_Shelf_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Library_Shelf_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Library_Shelf(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Library_Shelf_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Library_Shelf") +fileprivate func _bjs_struct_lift_Library_Shelf_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Library_Shelf_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Library_Shelf() -> Int32 { + return _bjs_struct_lift_Library_Shelf_extern() +} + +@_expose(wasm, "bjs_Library_Shelf_init") +@_cdecl("bjs_Library_Shelf_init") +public func _bjs_Library_Shelf_init(_ labelBytes: Int32, _ labelLength: Int32) -> Void { + #if arch(wasm32) + let ret = Library.Shelf(label: String.bridgeJSLiftParameter(labelBytes, labelLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_Shelf_static_capacity_get") +@_cdecl("bjs_Library_Shelf_static_capacity_get") +public func _bjs_Library_Shelf_static_capacity_get() -> Int32 { + #if arch(wasm32) + let ret = Library.Shelf.capacity + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_Shelf_describeShelf") +@_cdecl("bjs_Library_Shelf_describeShelf") +public func _bjs_Library_Shelf_describeShelf() -> Void { + #if arch(wasm32) + let ret = Library.Shelf.bridgeJSLiftParameter().describeShelf() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Library.Shelf.Divider: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Library.Shelf.Divider { + let slot = Int.bridgeJSStackPop() + return Library.Shelf.Divider(slot: slot) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.slot.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Library_Shelf_Divider(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Library_Shelf_Divider())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Library_Shelf_Divider") +fileprivate func _bjs_struct_lower_Library_Shelf_Divider_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Library_Shelf_Divider_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Library_Shelf_Divider(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Library_Shelf_Divider_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Library_Shelf_Divider") +fileprivate func _bjs_struct_lift_Library_Shelf_Divider_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Library_Shelf_Divider_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Library_Shelf_Divider() -> Int32 { + return _bjs_struct_lift_Library_Shelf_Divider_extern() +} + +@_expose(wasm, "bjs_Library_Shelf_Divider_init") +@_cdecl("bjs_Library_Shelf_Divider_init") +public func _bjs_Library_Shelf_Divider_init(_ slot: Int32) -> Void { + #if arch(wasm32) + let ret = Library.Shelf.Divider(slot: Int.bridgeJSLiftParameter(slot)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + extension GenericRTPoint: _BridgedSwiftStruct { @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> GenericRTPoint { let y = Int.bridgeJSStackPop() @@ -9990,6 +10190,17 @@ public func _bjs_makeAdder(_ base: Int32) -> Int32 { #endif } +@_expose(wasm, "bjs_roundTripMessage") +@_cdecl("bjs_roundTripMessage") +public func _bjs_roundTripMessage(_ message: Int32) -> Void { + #if arch(wasm32) + let ret = roundTripMessage(_: Message.bridgeJSLiftParameter(message)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_renamedEcho") @_cdecl("bjs_renamedEcho") public func _bjs_renamedEcho(_ valueBytes: Int32, _ valueLength: Int32) -> Void { @@ -10759,6 +10970,59 @@ fileprivate func _bjs_ClosureSupportExports_wrap_extern(_ pointer: UnsafeMutable return _bjs_ClosureSupportExports_wrap_extern(pointer) } +@_expose(wasm, "bjs_Workspace_init") +@_cdecl("bjs_Workspace_init") +public func _bjs_Workspace_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Workspace(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Workspace_describe") +@_cdecl("bjs_Workspace_describe") +public func _bjs_Workspace_describe(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Workspace.bridgeJSLiftParameter(_self).describe() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Workspace_deinit") +@_cdecl("bjs_Workspace_deinit") +public func _bjs_Workspace_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Workspace: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Workspace_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Workspace_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Workspace_wrap") +fileprivate func _bjs_Workspace_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Workspace_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Workspace_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Workspace_wrap_extern(pointer) +} + @_expose(wasm, "bjs_DefaultArgumentConstructorDefaults_init") @_cdecl("bjs_DefaultArgumentConstructorDefaults_init") public func _bjs_DefaultArgumentConstructorDefaults_init(_ nameBytes: Int32, _ nameLength: Int32, _ count: Int32, _ enabled: Int32, _ status: Int32, _ tagIsSome: Int32, _ tagBytes: Int32, _ tagLength: Int32) -> UnsafeMutableRawPointer { @@ -13371,6 +13635,102 @@ fileprivate func _bjs_NestedTypeHost_wrap_extern(_ pointer: UnsafeMutableRawPoin return _bjs_NestedTypeHost_wrap_extern(pointer) } +@_expose(wasm, "bjs_Library_init") +@_cdecl("bjs_Library_init") +public func _bjs_Library_init(_ nameBytes: Int32, _ nameLength: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Library(name: String.bridgeJSLiftParameter(nameBytes, nameLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_describe") +@_cdecl("bjs_Library_describe") +public func _bjs_Library_describe(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).describe() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_rename") +@_cdecl("bjs_Library_rename") +public func _bjs_Library_rename(_ _self: UnsafeMutableRawPointer, _ titleBytes: Int32, _ titleLength: Int32) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).rename(_: String.bridgeJSLiftParameter(titleBytes, titleLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_shelf") +@_cdecl("bjs_Library_shelf") +public func _bjs_Library_shelf(_ _self: UnsafeMutableRawPointer, _ labelBytes: Int32, _ labelLength: Int32) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).shelf(label: String.bridgeJSLiftParameter(labelBytes, labelLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_name_get") +@_cdecl("bjs_Library_name_get") +public func _bjs_Library_name_get(_ _self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = Library.bridgeJSLiftParameter(_self).name + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_name_set") +@_cdecl("bjs_Library_name_set") +public func _bjs_Library_name_set(_ _self: UnsafeMutableRawPointer, _ valueBytes: Int32, _ valueLength: Int32) -> Void { + #if arch(wasm32) + Library.bridgeJSLiftParameter(_self).name = String.bridgeJSLiftParameter(valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Library_deinit") +@_cdecl("bjs_Library_deinit") +public func _bjs_Library_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Library: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Library_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Library_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Library_wrap") +fileprivate func _bjs_Library_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Library_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Library_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Library_wrap_extern(pointer) +} + @_expose(wasm, "bjs_ImportGenericBox_init") @_cdecl("bjs_ImportGenericBox_init") public func _bjs_ImportGenericBox_init(_ value: Int32) -> UnsafeMutableRawPointer { @@ -13863,6 +14223,14 @@ extension NestedTypeHost.Label: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedTypeHost.Label.bridgeJSMakeTypeHandle() } +extension Library.Shelf: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Shelf.bridgeJSMakeTypeHandle() +} + +extension Library.Shelf.Divider: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Shelf.Divider.bridgeJSMakeTypeHandle() +} + extension GenericRTPoint: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = GenericRTPoint.bridgeJSMakeTypeHandle() } @@ -13987,6 +14355,10 @@ extension AsyncImportedPayloadResult: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = AsyncImportedPayloadResult.bridgeJSMakeTypeHandle() } +extension Workspace.Kind: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Workspace.Kind.bridgeJSMakeTypeHandle() +} + extension Direction: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = Direction.bridgeJSMakeTypeHandle() } @@ -14083,6 +14455,18 @@ extension NestedTypeHost.Variant: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = NestedTypeHost.Variant.bridgeJSMakeTypeHandle() } +extension Message: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Message.bridgeJSMakeTypeHandle() +} + +extension Library.Genre: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Library.Genre.bridgeJSMakeTypeHandle() +} + +extension Message.Update: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Message.Update.bridgeJSMakeTypeHandle() +} + extension LightColor: BridgedSwiftGenericBridgeable { @_spi(BridgeJS) public static let bridgeJSTypeHandle = LightColor.bridgeJSMakeTypeHandle() } @@ -19051,6 +19435,8 @@ public func _bjs_BridgeJSRuntimeTests_register_type_handles() { NestedStructGroupA.Metadata.bridgeJSTypeID, NestedStructGroupB.Metadata.bridgeJSTypeID, NestedTypeHost.Label.bridgeJSTypeID, + Library.Shelf.bridgeJSTypeID, + Library.Shelf.Divider.bridgeJSTypeID, GenericRTPoint.bridgeJSTypeID, GenericRTNamespace.Metadata.bridgeJSTypeID, Point.bridgeJSTypeID, @@ -19082,6 +19468,7 @@ public func _bjs_BridgeJSRuntimeTests_register_type_handles() { Shape.bridgeJSTypeID, InnerTag.bridgeJSTypeID, AsyncImportedPayloadResult.bridgeJSTypeID, + Workspace.Kind.bridgeJSTypeID, Direction.bridgeJSTypeID, Status.bridgeJSTypeID, Theme.bridgeJSTypeID, @@ -19106,6 +19493,9 @@ public func _bjs_BridgeJSRuntimeTests_register_type_handles() { StaticCalculator.bridgeJSTypeID, StaticPropertyEnum.bridgeJSTypeID, NestedTypeHost.Variant.bridgeJSTypeID, + Message.bridgeJSTypeID, + Library.Genre.bridgeJSTypeID, + Message.Update.bridgeJSTypeID, LightColor.bridgeJSTypeID, ImportedPayloadSignal.bridgeJSTypeID, GenericRTColor.bridgeJSTypeID, diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json index 8622b1cc9..c1a3e26cc 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json @@ -831,6 +831,51 @@ ], "swiftCallName" : "ClosureSupportExports" }, + { + "constructor" : { + "abiName" : "bjs_Workspace_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Workspace_describe", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describe", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Workspace", + "properties" : [ + + ], + "swiftCallName" : "Workspace" + }, { "constructor" : { "abiName" : "bjs_DefaultArgumentConstructorDefaults_init", @@ -4844,6 +4889,110 @@ ], "swiftCallName" : "NestedTypeHost" }, + { + "constructor" : { + "abiName" : "bjs_Library_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "name", + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Library_describe", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describe", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Library_rename", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "rename", + "parameters" : [ + { + "label" : "_", + "name" : "title", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Library_shelf", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "shelf", + "parameters" : [ + { + "label" : "label", + "name" : "label", + "type" : { + "string" : { + + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Library.Shelf" + } + } + } + ], + "name" : "Library", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Library" + }, { "constructor" : { "abiName" : "bjs_ImportGenericBox_init", @@ -7508,6 +7657,36 @@ "swiftCallName" : "AsyncImportedPayloadResult", "tsFullPath" : "AsyncImportedPayloadResult" }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "personal" + }, + { + "associatedValues" : [ + + ], + "name" : "shared" + } + ], + "emitStyle" : "const", + "name" : "Kind", + "namespace" : [ + "Workspace" + ], + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Workspace.Kind", + "tsFullPath" : "Workspace.Kind" + }, { "cases" : [ @@ -10329,6 +10508,94 @@ "swiftCallName" : "NestedTypeHost.Variant", "tsFullPath" : "NestedTypeHost.Variant" }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "caseEnum" : { + "_0" : "Message.Update" + } + } + } + ], + "name" : "update" + }, + { + "associatedValues" : [ + + ], + "name" : "delete" + } + ], + "emitStyle" : "const", + "name" : "Message", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Message", + "tsFullPath" : "Message" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "fiction" + }, + { + "associatedValues" : [ + + ], + "name" : "reference" + } + ], + "emitStyle" : "const", + "name" : "Genre", + "namespace" : [ + "Library" + ], + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Library.Genre", + "tsFullPath" : "Library.Genre" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "flip" + }, + { + "associatedValues" : [ + + ], + "name" : "rotate" + } + ], + "emitStyle" : "const", + "name" : "Update", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Message.Update", + "tsFullPath" : "Update" + }, { "cases" : [ { @@ -17145,6 +17412,31 @@ } } }, + { + "abiName" : "bjs_roundTripMessage", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "roundTripMessage", + "parameters" : [ + { + "label" : "_", + "name" : "message", + "type" : { + "associatedValueEnum" : { + "_0" : "Message" + } + } + } + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "Message" + } + } + }, { "abiName" : "bjs_renamedEcho", "effects" : { @@ -18679,6 +18971,136 @@ ], "swiftCallName" : "NestedTypeHost.Label" }, + { + "constructor" : { + "abiName" : "bjs_Library_Shelf_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "label", + "name" : "label", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Library_Shelf_describeShelf", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describeShelf", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Shelf", + "namespace" : [ + "Library" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "label", + "namespace" : [ + "Library" + ], + "type" : { + "string" : { + + } + } + }, + { + "isReadonly" : true, + "isStatic" : true, + "name" : "capacity", + "staticContext" : { + "structName" : { + "_0" : "Library_Shelf" + } + }, + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "Library.Shelf" + }, + { + "constructor" : { + "abiName" : "bjs_Library_Shelf_Divider_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "slot", + "name" : "slot", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Divider", + "namespace" : [ + "Library", + "Shelf" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "slot", + "namespace" : [ + "Library", + "Shelf" + ], + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "Library.Shelf.Divider" + }, { "methods" : [ diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index b7e21e821..78271e1ba 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -743,6 +743,29 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) { assert.equal(exports.NestedTypeHost.Label.untitled().text, "untitled"); nestedHost.release(); + const library = new exports.Library("Central"); + assert.equal(library.describe(), "Central"); + assert.equal(library.rename("Annex"), "Annex"); + assert.equal(exports.Library.Genre.Fiction, "fiction"); + assert.equal(exports.Library.Genre.Reference, "reference"); + const shelf = exports.Library.Shelf.init("History"); + assert.equal(shelf.label, "History"); + assert.equal(exports.Library.Shelf.capacity, 32); + assert.equal(library.shelf("Science").label, "Science"); + assert.equal(shelf.describeShelf(), "Shelf: History"); + assert.equal(exports.Library.Shelf.Divider.init(5).slot, 5); + const updateMessage = { tag: exports.Message.Tag.Update, param0: exports.Update.Flip }; + assert.deepEqual(exports.roundTripMessage(updateMessage), updateMessage); + const deleteMessage = { tag: exports.Message.Tag.Delete }; + assert.deepEqual(exports.roundTripMessage(deleteMessage), deleteMessage); + library.release(); + + const workspace = new exports.Workspace("Docs"); + assert.equal(workspace.describe(), "Docs"); + assert.equal(exports.Workspace.Kind.Personal, "personal"); + assert.equal(exports.Workspace.Kind.Shared, "shared"); + workspace.release(); + const s1 = { tag: exports.APIResult.Tag.Success, param0: "Cześć 🙋‍♂️" }; const f1 = { tag: exports.APIResult.Tag.Failure, param0: 42 }; const i1 = { tag: APIResultValues.Tag.Info }; From 0b453a5c895658213e83e3621c313020307b08fb Mon Sep 17 00:00:00 2001 From: William Taylor Date: Fri, 14 Aug 2026 16:44:43 +1000 Subject: [PATCH 2/4] BridgeJS: Fix nested type references in generated TS --- .../Sources/BridgeJSLink/BridgeJSLink.swift | 36 ++- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 8 + .../MacroSwift/NamespacedClassSignature.swift | 9 + .../NamespacedClassSignature.json | 80 +++++ .../NamespacedClassSignature.swift | 52 +++ .../ExtensionScopeParity.d.ts | 2 +- .../NamespacedClassSignature.d.ts | 32 ++ .../NamespacedClassSignature.js | 304 ++++++++++++++++++ 8 files changed, 511 insertions(+), 12 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 8b46af1b4..b796c35e7 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1704,6 +1704,24 @@ public struct BridgeJSLink { } } return type.tsType + case .swiftStruct(let name): + for skeleton in exportedSkeletons { + for structDef in skeleton.structs { + if structDef.name == name || structDef.swiftCallName == name { + return structDef.tsFullPath + } + } + } + return type.tsType + case .swiftHeapObject(let name): + for skeleton in exportedSkeletons { + for klass in skeleton.classes { + if klass.name == name || klass.swiftCallName == name { + return klass.name + } + } + } + return type.tsType case .alias(_, let underlying): return resolveTypeScriptType(underlying, exportedSkeletons: exportedSkeletons) case .nullable(let wrapped, let kind): @@ -2903,7 +2921,7 @@ extension BridgeJSLink { let namespaceEnumPaths = skeleton.enums .filter { $0.enumType == .namespace } .filter { !$0.staticProperties.isEmpty || !$0.staticMethods.isEmpty } - .map { ($0.namespace ?? []) + [$0.name] } + .map(\.tsPathComponents) return itemNamespaces + namespaceEnumPaths } @@ -2961,15 +2979,13 @@ extension BridgeJSLink { } for enumDef in skeleton.enums where enumDef.enumType == .namespace { for function in enumDef.staticMethods { - let fullNamespace = (enumDef.namespace ?? []) + [enumDef.name] - let namespacePath = fullNamespace.joined(separator: ".") + let namespacePath = enumDef.tsFullPath printer.write( "globalThis.\(namespacePath).\(function.resolvedJSName) = exports.\(namespacePath).\(function.resolvedJSName);" ) } for property in enumDef.staticProperties { - let fullNamespace = (enumDef.namespace ?? []) + [enumDef.name] - let namespacePath = fullNamespace.joined(separator: ".") + let namespacePath = enumDef.tsFullPath let exportsPath = "exports.\(namespacePath)" printer.write( @@ -3082,7 +3098,7 @@ extension BridgeJSLink { for klass in skeleton.classes { var currentNode = rootNode - for part in (klass.namespace ?? []) + [klass.name] { + for part in klass.tsPathComponents { currentNode = currentNode.addChild(part) } currentNode.content.declaration = .classType(klass) @@ -3090,7 +3106,7 @@ extension BridgeJSLink { for structDef in skeleton.structs { var currentNode = rootNode - for part in (structDef.namespace ?? []) + [structDef.name] { + for part in structDef.tsPathComponents { currentNode = currentNode.addChild(part) } currentNode.content.declaration = .structType(structDef) @@ -3106,17 +3122,15 @@ extension BridgeJSLink { for enumDef in skeleton.enums where enumDef.enumType == .namespace { for property in enumDef.staticProperties { - let fullNamespace = (enumDef.namespace ?? []) + [enumDef.name] var currentNode = rootNode - for part in fullNamespace { + for part in enumDef.tsPathComponents { currentNode = currentNode.addChild(part) } currentNode.content.staticProperties.append(property) } for function in enumDef.staticMethods { - let fullNamespace = (enumDef.namespace ?? []) + [enumDef.name] var currentNode = rootNode - for part in fullNamespace { + for part in enumDef.tsPathComponents { currentNode = currentNode.addChild(part) } currentNode.content.functions.append(function) diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index ed7dee420..79d6b4b07 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -14,6 +14,14 @@ extension NamespacedExportedType { } return name } + + public var tsPathComponents: [String] { + (namespace ?? []) + [name] + } + + public var tsFullPath: String { + tsPathComponents.joined(separator: ".") + } } // MARK: - ABI Name Generation diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift new file mode 100644 index 000000000..4e684ac11 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift @@ -0,0 +1,9 @@ +@JS enum Workshop { + @JS class Bench { + @JS init() {} + } +} + +@JS func makeBench() -> Workshop.Bench { + Workshop.Bench() +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json new file mode 100644 index 000000000..a6aaddafe --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json @@ -0,0 +1,80 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Workshop_Bench_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + + ], + "name" : "Bench", + "namespace" : [ + "Workshop" + ], + "properties" : [ + + ], + "swiftCallName" : "Workshop.Bench" + } + ], + "enums" : [ + { + "cases" : [ + + ], + "emitStyle" : "const", + "name" : "Workshop", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Workshop", + "tsFullPath" : "Workshop" + } + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_makeBench", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "makeBench", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Workshop.Bench" + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift new file mode 100644 index 000000000..0bb5652f1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift @@ -0,0 +1,52 @@ +@_expose(wasm, "bjs_makeBench") +@_cdecl("bjs_makeBench") +public func _bjs_makeBench() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = makeBench() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Workshop_Bench_init") +@_cdecl("bjs_Workshop_Bench_init") +public func _bjs_Workshop_Bench_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Workshop.Bench() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Workshop_Bench_deinit") +@_cdecl("bjs_Workshop_Bench_deinit") +public func _bjs_Workshop_Bench_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Workshop.Bench: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Workshop_Bench_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Workshop_Bench_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Workshop_Bench_wrap") +fileprivate func _bjs_Workshop_Bench_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Workshop_Bench_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Workshop_Bench_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Workshop_Bench_wrap_extern(pointer) +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts index 74569a6db..9097d0270 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionScopeParity.d.ts @@ -28,7 +28,7 @@ export interface Hammer extends SwiftHeapObject { export type Exports = { Signal: SignalObject Meta: { - init(note: string): Signal.Meta; + init(note: string): Meta; }, app: { Toolbox: { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts new file mode 100644 index 000000000..35e010247 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts @@ -0,0 +1,32 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +/// Represents a Swift heap object like a class instance or an actor instance. +export interface SwiftHeapObject { + /// Release the heap object. + /// + /// Note: Calling this method will release the heap object and it will no longer be accessible. + release(): void; +} +export interface Bench extends SwiftHeapObject { +} +export type Exports = { + makeBench(): Bench; + Workshop: { + Bench: { + new(): Bench; + }, + }, +} +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/NamespacedClassSignature.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js new file mode 100644 index 000000000..33ca4c706 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js @@ -0,0 +1,304 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + + return { + /** + * @param {WebAssembly.Imports} importObject + */ + addImports: (importObject, importsContext) => { + bjs = {}; + importObject["bjs"] = bjs; + bjs["swift_js_return_string"] = function(ptr, len) { + tmpRetString = decodeString(ptr, len); + } + bjs["swift_js_init_memory"] = function(sourceId, bytesPtr) { + const source = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const bytes = new Uint8Array(memory.buffer, bytesPtr >>> 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["bjs_core_register_type_handles"] = function() {}; + 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_Workshop_Bench_wrap"] = function(pointer) { + const obj = _exports.Workshop.Bench.__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 Bench extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Workshop_Bench_deinit, Bench.prototype, null); + } + + constructor() { + const ret = instance.exports.bjs_Workshop_Bench_init(); + return Bench.__construct(ret); + } + } + const exports = { + makeBench: function bjs_makeBench() { + const ret = instance.exports.bjs_makeBench(); + return Bench.__construct(ret); + }, + Workshop: { + Bench, + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file From ae935a974a47ca277ca29584595e03e56f87f1ef Mon Sep 17 00:00:00 2001 From: William Taylor Date: Mon, 17 Aug 2026 12:58:43 +1000 Subject: [PATCH 3/4] Fix types in extensions bugs --- .../BridgeJSCore/SwiftToSkeleton.swift | 61 +++- .../Sources/BridgeJSLink/BridgeJSLink.swift | 29 +- .../BridgeJSCodegenTests.swift | 24 ++ .../ExtensionOrderIndependence.swift | 19 + .../CrossFileExtensionOrderMember.swift | 5 + .../CrossFileExtensionOrderType.swift | 13 + .../MacroSwift/NamespacedClassSignature.swift | 4 + .../MacroSwift/NestedTypeNameCollision.swift | 25 ++ .../CrossFileExtensionOrderIndependence.json | 106 ++++++ .../CrossFileExtensionOrderIndependence.swift | 128 +++++++ .../ExtensionOrderIndependence.json | 106 ++++++ .../ExtensionOrderIndependence.swift | 128 +++++++ .../NamespacedClassSignature.json | 53 +++ .../NamespacedClassSignature.swift | 74 ++++ .../NestedTypeNameCollision.json | 177 +++++++++ .../NestedTypeNameCollision.swift | 159 ++++++++ .../ExtensionOrderIndependence.d.ts | 38 ++ .../ExtensionOrderIndependence.js | 339 ++++++++++++++++++ .../NamespacedClassSignature.d.ts | 1 + .../NamespacedClassSignature.js | 57 +++ .../NestedTypeNameCollision.d.ts | 35 ++ .../NestedTypeNameCollision.js | 299 +++++++++++++++ 22 files changed, 1851 insertions(+), 29 deletions(-) create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionOrderIndependence.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderMember.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderType.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedTypeNameCollision.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.json create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.swift create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionOrderIndependence.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionOrderIndependence.js create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedTypeNameCollision.d.ts create mode 100644 Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedTypeNameCollision.js diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift index f119f5bff..fb9cee01c 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -139,6 +139,39 @@ public final class SwiftToSkeleton { sourceFiles.append((sourceFile, inputFilePath)) } + private func resolveDeferredExtensions(_ exportCollectors: [ExportSwiftAPICollector]) { + var pendingExtensions = exportCollectors.flatMap { collector in + collector.deferredExtensions.map { (owner: collector, declaration: $0) } + } + var previousCount: Int + // An extended type might be defined in another extension, so keep resolving until no more progress is made. + repeat { + previousCount = pendingExtensions.count + var nextPendingExtensions: [(owner: ExportSwiftAPICollector, declaration: ExtensionDeclSyntax)] = [] + for pending in pendingExtensions { + if !resolveExtension(pending.declaration, in: exportCollectors) { + nextPendingExtensions.append(pending) + } + } + pendingExtensions = nextPendingExtensions + } while pendingExtensions.count < previousCount + for pending in pendingExtensions { + pending.owner.diagnoseUnresolvedExtension(pending.declaration) + } + } + + private func resolveExtension( + _ declaration: ExtensionDeclSyntax, + in exportCollectors: [ExportSwiftAPICollector] + ) -> Bool { + for collector in exportCollectors { + if collector.resolveExtension(declaration) { + return true + } + } + return false + } + public func finalize() throws -> BridgeJSSkeleton { var perSourceErrors: [(inputFilePath: String, errors: [DiagnosticError])] = [] var importedFiles: [ImportedFileSkeleton] = [] @@ -244,9 +277,7 @@ public final class SwiftToSkeleton { } // Resolve extensions against all collectors. This needs to happen at this point so we can resolve both same file and cross file extensions. - for source in exportCollectors { - source.resolveDeferredExtensions(against: exportCollectors) - } + resolveDeferredExtensions(exportCollectors) // We have to collect diagnostics after all deferred extensions are resolved, since they could generate some. for ((_, inputFilePath), exportCollector) in zip(sourceFiles, exportCollectors) { @@ -1946,23 +1977,15 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { return .skipChildren } - func resolveDeferredExtensions(against collectors: [ExportSwiftAPICollector]) { - for ext in deferredExtensions { - var resolved = false - for collector in collectors { - if collector.resolveExtension(ext) { - resolved = true - break - } - } - if !resolved, containsJSAnnotatedDeclaration(ext.memberBlock.members) { - diagnose( - node: ext.extendedType, - message: "Unsupported type '\(ext.extendedType.trimmedDescription)'.", - hint: "You can only extend `@JS` annotated types defined in the same module" - ) - } + func diagnoseUnresolvedExtension(_ ext: ExtensionDeclSyntax) { + guard containsJSAnnotatedDeclaration(ext.memberBlock.members) else { + return } + diagnose( + node: ext.extendedType, + message: "Unsupported type '\(ext.extendedType.trimmedDescription)'.", + hint: "You can only extend `@JS` annotated types defined in the same module" + ) } private func containsJSAnnotatedDeclaration(_ members: MemberBlockItemListSyntax) -> Bool { diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index b796c35e7..0e5bdc221 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1689,7 +1689,7 @@ public struct BridgeJSLink { // Look up the enum to get its tsFullPath for skeleton in exportedSkeletons { for enumDef in skeleton.enums { - if enumDef.name == name || enumDef.swiftCallName == name { + if enumDef.swiftCallName == name { // Use the stored tsFullPath which has the full namespace switch type { case .namespaceEnum: @@ -1707,7 +1707,7 @@ public struct BridgeJSLink { case .swiftStruct(let name): for skeleton in exportedSkeletons { for structDef in skeleton.structs { - if structDef.name == name || structDef.swiftCallName == name { + if structDef.swiftCallName == name { return structDef.tsFullPath } } @@ -1716,12 +1716,14 @@ public struct BridgeJSLink { case .swiftHeapObject(let name): for skeleton in exportedSkeletons { for klass in skeleton.classes { - if klass.name == name || klass.swiftCallName == name { + if klass.swiftCallName == name { return klass.name } } } return type.tsType + case .closure(let signature, _): + return signature.renderTSFunctionType { resolveTypeScriptType($0, exportedSkeletons: exportedSkeletons) } case .alias(_, let underlying): return resolveTypeScriptType(underlying, exportedSkeletons: exportedSkeletons) case .nullable(let wrapped, let kind): @@ -3761,7 +3763,8 @@ extension BridgeJSLink { let abiName = getter.abiName(context: nil) let funcLines = thunkBuilder.renderFunction(name: abiName) if getter.from == nil { - importObjectBuilder.appendDts(["readonly \(renderTSPropertyName(jsName)): \(getter.type.tsType);"]) + importObjectBuilder.appendDts(["readonly \(renderTSPropertyName(jsName)): \(getter.type.tsType);"] + ) } importObjectBuilder.assignToImportObject(name: abiName, function: funcLines) } @@ -4230,6 +4233,17 @@ struct BridgeJSLinkError: Error { let message: String } +extension ClosureSignature { + fileprivate func renderTSFunctionType(renderType: (BridgeType) -> String) -> String { + let renderedParameters = parameters.enumerated().map { index, parameter in + "arg\(index): \(renderType(parameter))" + }.joined(separator: ", ") + let renderedReturnType = renderType(returnType) + let returnTypeWithEffect = isAsync ? "Promise<\(renderedReturnType)>" : renderedReturnType + return "(\(renderedParameters)) => \(returnTypeWithEffect)" + } +} + extension BridgeType { var tsType: String { switch self { @@ -4271,12 +4285,7 @@ extension BridgeType { case .swiftProtocol(let name): return name case .closure(let signature, _): - let paramTypes = signature.parameters.enumerated().map { index, param in - "arg\(index): \(param.tsType)" - }.joined(separator: ", ") - let returnTS = - signature.isAsync ? "Promise<\(signature.returnType.tsType)>" : signature.returnType.tsType - return "(\(paramTypes)) => \(returnTS)" + return signature.renderTSFunctionType { $0.tsType } case .array(let elementType): let inner = elementType.tsType if inner.contains("|") || inner.contains("=>") { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift index baffc0c20..11347dc40 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/BridgeJSCodegenTests.swift @@ -358,6 +358,30 @@ import Testing try snapshotCodegen(skeleton: skeleton, name: "CrossFileNestedTypeExtension") } + @Test + func codegenCrossFileExtensionOrderIndependence() throws { + let swiftAPI = SwiftToSkeleton( + progress: .silent, + moduleName: "TestModule", + exposeToGlobal: false, + externalModuleIndex: .empty + ) + let memberURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtensionOrderMember.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: memberURL, encoding: .utf8)), + inputFilePath: "CrossFileExtensionOrderMember.swift" + ) + let typeURL = Self.multifileInputsDirectory.appendingPathComponent("CrossFileExtensionOrderType.swift") + swiftAPI.addSourceFile( + Parser.parse(source: try String(contentsOf: typeURL, encoding: .utf8)), + inputFilePath: "CrossFileExtensionOrderType.swift" + ) + let skeleton = try swiftAPI.finalize() + let record = skeleton.exported?.structs.first { $0.swiftCallName == "Archive.Record" } + #expect(record?.methods.map(\.name) == ["describeRecord"]) + try snapshotCodegen(skeleton: skeleton, name: "CrossFileExtensionOrderIndependence") + } + @Test func codegenSkipsEmptySkeletons() throws { let swiftAPI = SwiftToSkeleton( diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionOrderIndependence.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionOrderIndependence.swift new file mode 100644 index 000000000..143a60233 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/ExtensionOrderIndependence.swift @@ -0,0 +1,19 @@ +@JS class Depot { + @JS init() {} +} + +extension Depot.Crate { + @JS func describeCrate() -> String { + "Crate: " + label + } +} + +extension Depot { + @JS struct Crate { + var label: String + + @JS init(label: String) { + self.label = label + } + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderMember.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderMember.swift new file mode 100644 index 000000000..277e9d40f --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderMember.swift @@ -0,0 +1,5 @@ +extension Archive.Record { + @JS func describeRecord() -> String { + "Record: " + label + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderType.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderType.swift new file mode 100644 index 000000000..641e25559 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Multifile/CrossFileExtensionOrderType.swift @@ -0,0 +1,13 @@ +@JS class Archive { + @JS init() {} +} + +extension Archive { + @JS struct Record { + var label: String + + @JS init(label: String) { + self.label = label + } + } +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift index 4e684ac11..67841f250 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NamespacedClassSignature.swift @@ -7,3 +7,7 @@ @JS func makeBench() -> Workshop.Bench { Workshop.Bench() } + +@JS func refitBench(_ bench: Workshop.Bench, _ transform: (Workshop.Bench) -> Workshop.Bench) -> Workshop.Bench { + transform(bench) +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedTypeNameCollision.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedTypeNameCollision.swift new file mode 100644 index 000000000..231e8d7b6 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/NestedTypeNameCollision.swift @@ -0,0 +1,25 @@ +@JS enum Catalog { + @JS struct Entry { + var title: String + + @JS init(title: String) { + self.title = title + } + } +} + +@JS struct Entry { + var identifier: Int + + @JS init(identifier: Int) { + self.identifier = identifier + } +} + +@JS func takeEntry(_ entry: Entry) -> Entry { + entry +} + +@JS func takeCatalogEntry(_ entry: Catalog.Entry) -> Catalog.Entry { + entry +} diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.json new file mode 100644 index 000000000..ef20e9a28 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.json @@ -0,0 +1,106 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Archive_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + + ], + "name" : "Archive", + "properties" : [ + + ], + "swiftCallName" : "Archive" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "constructor" : { + "abiName" : "bjs_Archive_Record_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "label", + "name" : "label", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Archive_Record_describeRecord", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describeRecord", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Record", + "namespace" : [ + "Archive" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "label", + "namespace" : [ + "Archive" + ], + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Archive.Record" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.swift new file mode 100644 index 000000000..c8df6b29e --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/CrossFileExtensionOrderIndependence.swift @@ -0,0 +1,128 @@ +extension Archive.Record: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Archive.Record { + let label = String.bridgeJSStackPop() + return Archive.Record(label: label) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.label.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Archive_Record(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Archive_Record())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Archive_Record") +fileprivate func _bjs_struct_lower_Archive_Record_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Archive_Record_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Archive_Record(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Archive_Record_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Archive_Record") +fileprivate func _bjs_struct_lift_Archive_Record_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Archive_Record_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Archive_Record() -> Int32 { + return _bjs_struct_lift_Archive_Record_extern() +} + +@_expose(wasm, "bjs_Archive_Record_init") +@_cdecl("bjs_Archive_Record_init") +public func _bjs_Archive_Record_init(_ labelBytes: Int32, _ labelLength: Int32) -> Void { + #if arch(wasm32) + let ret = Archive.Record(label: String.bridgeJSLiftParameter(labelBytes, labelLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Archive_Record_describeRecord") +@_cdecl("bjs_Archive_Record_describeRecord") +public func _bjs_Archive_Record_describeRecord() -> Void { + #if arch(wasm32) + let ret = Archive.Record.bridgeJSLiftParameter().describeRecord() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Archive_init") +@_cdecl("bjs_Archive_init") +public func _bjs_Archive_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Archive() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Archive_deinit") +@_cdecl("bjs_Archive_deinit") +public func _bjs_Archive_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Archive: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Archive_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Archive_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Archive_wrap") +fileprivate func _bjs_Archive_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Archive_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Archive_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Archive_wrap_extern(pointer) +} + +extension Archive.Record: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Archive.Record.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Archive.Record.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.json new file mode 100644 index 000000000..9096006ae --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.json @@ -0,0 +1,106 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Depot_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + + ] + }, + "methods" : [ + + ], + "name" : "Depot", + "properties" : [ + + ], + "swiftCallName" : "Depot" + } + ], + "enums" : [ + + ], + "exposeToGlobal" : false, + "functions" : [ + + ], + "protocols" : [ + + ], + "structs" : [ + { + "constructor" : { + "abiName" : "bjs_Depot_Crate_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "label", + "name" : "label", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Depot_Crate_describeCrate", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "describeCrate", + "parameters" : [ + + ], + "returnType" : { + "string" : { + + } + } + } + ], + "name" : "Crate", + "namespace" : [ + "Depot" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "label", + "namespace" : [ + "Depot" + ], + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Depot.Crate" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.swift new file mode 100644 index 000000000..cc8091bbe --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/ExtensionOrderIndependence.swift @@ -0,0 +1,128 @@ +extension Depot.Crate: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Depot.Crate { + let label = String.bridgeJSStackPop() + return Depot.Crate(label: label) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.label.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Depot_Crate(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Depot_Crate())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Depot_Crate") +fileprivate func _bjs_struct_lower_Depot_Crate_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Depot_Crate_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Depot_Crate(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Depot_Crate_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Depot_Crate") +fileprivate func _bjs_struct_lift_Depot_Crate_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Depot_Crate_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Depot_Crate() -> Int32 { + return _bjs_struct_lift_Depot_Crate_extern() +} + +@_expose(wasm, "bjs_Depot_Crate_init") +@_cdecl("bjs_Depot_Crate_init") +public func _bjs_Depot_Crate_init(_ labelBytes: Int32, _ labelLength: Int32) -> Void { + #if arch(wasm32) + let ret = Depot.Crate(label: String.bridgeJSLiftParameter(labelBytes, labelLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Depot_Crate_describeCrate") +@_cdecl("bjs_Depot_Crate_describeCrate") +public func _bjs_Depot_Crate_describeCrate() -> Void { + #if arch(wasm32) + let ret = Depot.Crate.bridgeJSLiftParameter().describeCrate() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Depot_init") +@_cdecl("bjs_Depot_init") +public func _bjs_Depot_init() -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Depot() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Depot_deinit") +@_cdecl("bjs_Depot_deinit") +public func _bjs_Depot_deinit(_ pointer: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Unmanaged.fromOpaque(pointer).release() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Depot: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable { + var jsValue: JSValue { + return .object(JSObject(id: UInt32(bitPattern: _bjs_Depot_wrap(Unmanaged.passRetained(self).toOpaque())))) + } + consuming func bridgeJSLowerAsProtocolReturn() -> Int32 { + _bjs_Depot_wrap(Unmanaged.passRetained(self).toOpaque()) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "TestModule", name: "bjs_Depot_wrap") +fileprivate func _bjs_Depot_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 +#else +fileprivate func _bjs_Depot_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_Depot_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 { + return _bjs_Depot_wrap_extern(pointer) +} + +extension Depot.Crate: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Depot.Crate.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Depot.Crate.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json index a6aaddafe..e4568f101 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json @@ -64,6 +64,59 @@ "_0" : "Workshop.Bench" } } + }, + { + "abiName" : "bjs_refitBench", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "refitBench", + "parameters" : [ + { + "label" : "_", + "name" : "bench", + "type" : { + "swiftHeapObject" : { + "_0" : "Workshop.Bench" + } + } + }, + { + "label" : "_", + "name" : "transform", + "type" : { + "closure" : { + "_0" : { + "isAsync" : false, + "isThrows" : false, + "mangleName" : "10TestModule14Workshop.BenchC_14Workshop.BenchC", + "moduleName" : "TestModule", + "parameters" : [ + { + "swiftHeapObject" : { + "_0" : "Workshop.Bench" + } + } + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Workshop.Bench" + } + }, + "sendingParameters" : false + }, + "useJSTypedClosure" : false + } + } + } + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Workshop.Bench" + } + } } ], "protocols" : [ diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift index 0bb5652f1..511d0f75c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift @@ -1,3 +1,66 @@ +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") +fileprivate func invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer +#else +fileprivate func invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + return invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(callback, param0) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") +fileprivate func make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +#else +fileprivate func make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(boxPtr, file, line) +} + +private enum _BJS_Closure_10TestModule14Workshop.BenchC_14Workshop.BenchC { + static func bridgeJSLift(_ callbackId: Int32) -> (Workshop.Bench) -> Workshop.Bench { + let callback = JSObject.bridgeJSLiftParameter(callbackId) + return { [callback] param0 in + #if arch(wasm32) + let param0Pointer = param0.bridgeJSLowerParameter() + let callbackValue = callback.bridgeJSLowerParameter() + let ret = invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(callbackValue, param0Pointer) + return Workshop.Bench.bridgeJSLiftReturn(ret) + #else + fatalError("Only available on WebAssembly") + #endif + } + } +} + +extension JSTypedClosure where Signature == (Workshop.Bench) -> Workshop.Bench { + init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Workshop.Bench) -> Workshop.Bench) { + self.init( + makeClosure: make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC, + body: body, + fileID: fileID, + line: line + ) + } +} + +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") +@_cdecl("invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") +public func _invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(_ boxPtr: UnsafeMutableRawPointer, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let closure = Unmanaged<_BridgeJSTypedClosureBox<(Workshop.Bench) -> Workshop.Bench>>.fromOpaque(boxPtr).takeUnretainedValue().closure + let result = closure(Workshop.Bench.bridgeJSLiftParameter(param0)) + return result.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_makeBench") @_cdecl("bjs_makeBench") public func _bjs_makeBench() -> UnsafeMutableRawPointer { @@ -9,6 +72,17 @@ public func _bjs_makeBench() -> UnsafeMutableRawPointer { #endif } +@_expose(wasm, "bjs_refitBench") +@_cdecl("bjs_refitBench") +public func _bjs_refitBench(_ bench: UnsafeMutableRawPointer, _ transform: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = refitBench(_: Workshop.Bench.bridgeJSLiftParameter(bench), _: _BJS_Closure_10TestModule14Workshop.BenchC_14Workshop.BenchC.bridgeJSLift(transform)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_Workshop_Bench_init") @_cdecl("bjs_Workshop_Bench_init") public func _bjs_Workshop_Bench_init() -> UnsafeMutableRawPointer { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.json new file mode 100644 index 000000000..8683e11b1 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.json @@ -0,0 +1,177 @@ +{ + "exported" : { + "aliases" : [ + + ], + "classes" : [ + + ], + "enums" : [ + { + "cases" : [ + + ], + "emitStyle" : "const", + "name" : "Catalog", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Catalog", + "tsFullPath" : "Catalog" + } + ], + "exposeToGlobal" : false, + "functions" : [ + { + "abiName" : "bjs_takeEntry", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "takeEntry", + "parameters" : [ + { + "label" : "_", + "name" : "entry", + "type" : { + "swiftStruct" : { + "_0" : "Entry" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Entry" + } + } + }, + { + "abiName" : "bjs_takeCatalogEntry", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "takeCatalogEntry", + "parameters" : [ + { + "label" : "_", + "name" : "entry", + "type" : { + "swiftStruct" : { + "_0" : "Catalog.Entry" + } + } + } + ], + "returnType" : { + "swiftStruct" : { + "_0" : "Catalog.Entry" + } + } + } + ], + "protocols" : [ + + ], + "structs" : [ + { + "constructor" : { + "abiName" : "bjs_Catalog_Entry_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "title", + "name" : "title", + "type" : { + "string" : { + + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Entry", + "namespace" : [ + "Catalog" + ], + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "title", + "namespace" : [ + "Catalog" + ], + "type" : { + "string" : { + + } + } + } + ], + "swiftCallName" : "Catalog.Entry" + }, + { + "constructor" : { + "abiName" : "bjs_Entry_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "identifier", + "name" : "identifier", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ] + }, + "methods" : [ + + ], + "name" : "Entry", + "properties" : [ + { + "isReadonly" : true, + "isStatic" : false, + "name" : "identifier", + "type" : { + "integer" : { + "_0" : { + "isSigned" : true, + "width" : "word" + } + } + } + } + ], + "swiftCallName" : "Entry" + } + ] + }, + "moduleName" : "TestModule", + "usedExternalModules" : [ + + ] +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.swift new file mode 100644 index 000000000..266f37f09 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NestedTypeNameCollision.swift @@ -0,0 +1,159 @@ +extension Catalog.Entry: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Catalog.Entry { + let title = String.bridgeJSStackPop() + return Catalog.Entry(title: title) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.title.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Catalog_Entry(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Catalog_Entry())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Catalog_Entry") +fileprivate func _bjs_struct_lower_Catalog_Entry_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Catalog_Entry_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Catalog_Entry(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Catalog_Entry_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Catalog_Entry") +fileprivate func _bjs_struct_lift_Catalog_Entry_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Catalog_Entry_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Catalog_Entry() -> Int32 { + return _bjs_struct_lift_Catalog_Entry_extern() +} + +@_expose(wasm, "bjs_Catalog_Entry_init") +@_cdecl("bjs_Catalog_Entry_init") +public func _bjs_Catalog_Entry_init(_ titleBytes: Int32, _ titleLength: Int32) -> Void { + #if arch(wasm32) + let ret = Catalog.Entry(title: String.bridgeJSLiftParameter(titleBytes, titleLength)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Entry: _BridgedSwiftStruct { + @_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> Entry { + let identifier = Int.bridgeJSStackPop() + return Entry(identifier: identifier) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() { + self.identifier.bridgeJSStackPush() + } + + init(unsafelyCopying jsObject: JSObject) { + _bjs_struct_lower_Entry(jsObject.bridgeJSLowerParameter()) + self = Self.bridgeJSStackPop() + } + + func toJSObject() -> JSObject { + let __bjs_self = self + __bjs_self.bridgeJSStackPush() + return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_Entry())) + } +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_Entry") +fileprivate func _bjs_struct_lower_Entry_extern(_ objectId: Int32) -> Void +#else +fileprivate func _bjs_struct_lower_Entry_extern(_ objectId: Int32) -> Void { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lower_Entry(_ objectId: Int32) -> Void { + return _bjs_struct_lower_Entry_extern(objectId) +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_Entry") +fileprivate func _bjs_struct_lift_Entry_extern() -> Int32 +#else +fileprivate func _bjs_struct_lift_Entry_extern() -> Int32 { + fatalError("Only available on WebAssembly") +} +#endif +@inline(never) fileprivate func _bjs_struct_lift_Entry() -> Int32 { + return _bjs_struct_lift_Entry_extern() +} + +@_expose(wasm, "bjs_Entry_init") +@_cdecl("bjs_Entry_init") +public func _bjs_Entry_init(_ identifier: Int32) -> Void { + #if arch(wasm32) + let ret = Entry(identifier: Int.bridgeJSLiftParameter(identifier)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_takeEntry") +@_cdecl("bjs_takeEntry") +public func _bjs_takeEntry() -> Void { + #if arch(wasm32) + let ret = takeEntry(_: Entry.bridgeJSLiftParameter()) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_takeCatalogEntry") +@_cdecl("bjs_takeCatalogEntry") +public func _bjs_takeCatalogEntry() -> Void { + #if arch(wasm32) + let ret = takeCatalogEntry(_: Catalog.Entry.bridgeJSLiftParameter()) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +extension Catalog.Entry: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Catalog.Entry.bridgeJSMakeTypeHandle() +} + +extension Entry: BridgedSwiftGenericBridgeable { + @_spi(BridgeJS) public static let bridgeJSTypeHandle = Entry.bridgeJSMakeTypeHandle() +} + +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles") +fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer?, _ count: Int32) + +@_expose(wasm, "bjs_TestModule_register_type_handles") +public func _bjs_TestModule_register_type_handles() { + let typeIds: [Int32] = [ + Catalog.Entry.bridgeJSTypeID, + Entry.bridgeJSTypeID, + ] + typeIds.withUnsafeBufferPointer { buffer in + _bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count)) + } +} +#endif \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionOrderIndependence.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionOrderIndependence.d.ts new file mode 100644 index 000000000..2b16f6a6d --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionOrderIndependence.d.ts @@ -0,0 +1,38 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export namespace Depot { + export interface Crate { + label: string; + describeCrate(): 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 Depot extends SwiftHeapObject { +} +export type Exports = { + Depot: { + new(): Depot; + Crate: { + init(label: string): Depot.Crate; + }, + }, +} +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/ExtensionOrderIndependence.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionOrderIndependence.js new file mode 100644 index 000000000..6cc339d24 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ExtensionOrderIndependence.js @@ -0,0 +1,339 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const __bjs_createStructHelpers_M10TestModuleT5DepotT5Crate = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.label); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + const instance1 = { label: string }; + instance1.describeCrate = function() { + structHelpers.M10TestModuleT5DepotT5Crate.lower(this); + const ret = instance.exports.bjs_Depot_Crate_describeCrate(); + const ret1 = tmpRetString; + tmpRetString = undefined; + return ret1; + }.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_Depot_Crate"] = function(objectId) { + structHelpers.M10TestModuleT5DepotT5Crate.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Depot_Crate"] = function() { + const value = structHelpers.M10TestModuleT5DepotT5Crate.lift(); + return swift.memory.retain(value); + } + bjs["bjs_core_register_type_handles"] = function() {}; + bjs["bjs_TestModule_register_type_handles"] = function() {}; + 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_Depot_wrap"] = function(pointer) { + const obj = _exports['Depot'].__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 Depot extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Depot_deinit, Depot.prototype, null); + } + + constructor() { + const ret = instance.exports.bjs_Depot_init(); + return Depot.__construct(ret); + } + } + const __bjs_helpers_M10TestModuleT5DepotT5Crate = __bjs_createStructHelpers_M10TestModuleT5DepotT5Crate(); + structHelpers.M10TestModuleT5DepotT5Crate = __bjs_helpers_M10TestModuleT5DepotT5Crate; + + const exports = { + Depot: Object.assign(Depot, { + Crate: { + init: function(label) { + const labelBytes = textEncoder.encode(label); + const labelId = swift.memory.retain(labelBytes); + instance.exports.bjs_Depot_Crate_init(labelId, labelBytes.length); + const structValue = structHelpers.M10TestModuleT5DepotT5Crate.lift(); + return structValue; + }, + }, + }), + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts index 35e010247..7c7c4ce3a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.d.ts @@ -15,6 +15,7 @@ export interface Bench extends SwiftHeapObject { } export type Exports = { makeBench(): Bench; + refitBench(bench: Bench, transform: (arg0: Bench) => Bench): Bench; Workshop: { Bench: { new(): Bench; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js index 33ca4c706..e963771c4 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js @@ -31,6 +31,31 @@ export async function createInstantiator(options, swift) { let _exports = null; let bjs = null; + const swiftClosureRegistry = (typeof FinalizationRegistry === "undefined") ? { register: () => {}, unregister: () => {} } : new FinalizationRegistry((state) => { + if (state.unregistered) { return; } + instance?.exports?.bjs_release_swift_closure(state.pointer); + }); + const makeClosure = (pointer, file, line, func) => { + const state = { pointer, file, line, unregistered: false }; + const real = (...args) => { + if (state.unregistered) { + const bytes = new Uint8Array(memory.buffer, state.file >>> 0); + let length = 0; + while (bytes[length] !== 0) { length += 1; } + const fileID = decodeString(state.file, length); + throw new Error(`Attempted to call a released JSTypedClosure created at ${fileID}:${state.line}`); + } + return func(...args); + }; + real.__unregister = () => { + if (state.unregistered) { return; } + state.unregistered = true; + swiftClosureRegistry.unregister(state); + }; + swiftClosureRegistry.register(real, state, state); + return swift.memory.retain(real); + }; + return { /** @@ -204,6 +229,33 @@ export async function createInstantiator(options, swift) { return pointer || 0; } bjs["swift_js_closure_unregister"] = function(funcRef) {} + bjs["swift_js_closure_unregister"] = function(funcRef) { + const func = swift.memory.getObject(funcRef); + func.__unregister(); + } + bjs["invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC"] = function(callbackId, param0) { + try { + const callback = swift.memory.getObject(callbackId); + let ret = callback(_exports.Workshop.Bench.__construct(param0)); + return ret.pointer; + } catch (error) { + setException(error); + return 0 + } + } + bjs["make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC = function(param0) { + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(boxPtr, param0.pointer); + if (tmpRetException) { + const error = swift.memory.getObject(tmpRetException); + swift.memory.release(tmpRetException); + tmpRetException = undefined; + throw error; + } + return _exports.Workshop.Bench.__construct(ret); + }; + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC); + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -293,6 +345,11 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_makeBench(); return Bench.__construct(ret); }, + refitBench: function bjs_refitBench(bench, transform) { + const callbackId = swift.memory.retain(transform); + const ret = instance.exports.bjs_refitBench(bench.pointer, callbackId); + return Bench.__construct(ret); + }, Workshop: { Bench, }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedTypeNameCollision.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedTypeNameCollision.d.ts new file mode 100644 index 000000000..13c22ea11 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedTypeNameCollision.d.ts @@ -0,0 +1,35 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export interface Entry { + identifier: number; +} +export namespace Catalog { + export interface Entry { + title: string; + } +} +export type Exports = { + takeEntry(entry: Entry): Entry; + takeCatalogEntry(entry: Catalog.Entry): Catalog.Entry; + Catalog: { + Entry: { + init(title: string): Catalog.Entry; + }, + }, + Entry: { + init(identifier: number): Entry; + }, +} +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/NestedTypeNameCollision.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedTypeNameCollision.js new file mode 100644 index 000000000..1f4400ce9 --- /dev/null +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedTypeNameCollision.js @@ -0,0 +1,299 @@ +// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit, +// DO NOT EDIT. +// +// To update this file, just rebuild your project or run +// `swift package bridge-js`. + +export async function createInstantiator(options, swift) { + let instance; + let memory; + let setException; + let decodeString; + const textDecoder = new TextDecoder("utf-8"); + const textEncoder = new TextEncoder("utf-8"); + let tmpRetString; + let tmpRetBytes; + let tmpRetException; + let tmpRetOptionalBool; + let tmpRetOptionalInt; + let tmpRetOptionalFloat; + let tmpRetOptionalDouble; + let tmpRetOptionalHeapObject; + let strStack = []; + let i32Stack = []; + let i64Stack = []; + let f32Stack = []; + let f64Stack = []; + let ptrStack = []; + let taStack = []; + const enumHelpers = {}; + const structHelpers = {}; + + let _exports = null; + let bjs = null; + const __bjs_createStructHelpers_M10TestModuleT7CatalogT5Entry = () => ({ + lower: (value) => { + const bytes = textEncoder.encode(value.title); + const id = swift.memory.retain(bytes); + i32Stack.push(bytes.length); + i32Stack.push(id); + }, + lift: () => { + const string = strStack.pop(); + return { title: string }; + } + }); + const __bjs_createStructHelpers_M10TestModuleT5Entry = () => ({ + lower: (value) => { + i32Stack.push((value.identifier | 0)); + }, + lift: () => { + const int = i32Stack.pop(); + return { identifier: int }; + } + }); + + 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_Catalog_Entry"] = function(objectId) { + structHelpers.M10TestModuleT7CatalogT5Entry.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Catalog_Entry"] = function() { + const value = structHelpers.M10TestModuleT7CatalogT5Entry.lift(); + return swift.memory.retain(value); + } + bjs["swift_js_struct_lower_Entry"] = function(objectId) { + structHelpers.M10TestModuleT5Entry.lower(swift.memory.getObject(objectId)); + } + bjs["swift_js_struct_lift_Entry"] = function() { + const value = structHelpers.M10TestModuleT5Entry.lift(); + return swift.memory.retain(value); + } + bjs["bjs_core_register_type_handles"] = function() {}; + bjs["bjs_TestModule_register_type_handles"] = function() {}; + 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) {} + }, + 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 __bjs_helpers_M10TestModuleT7CatalogT5Entry = __bjs_createStructHelpers_M10TestModuleT7CatalogT5Entry(); + structHelpers.M10TestModuleT7CatalogT5Entry = __bjs_helpers_M10TestModuleT7CatalogT5Entry; + + const __bjs_helpers_M10TestModuleT5Entry = __bjs_createStructHelpers_M10TestModuleT5Entry(); + structHelpers.M10TestModuleT5Entry = __bjs_helpers_M10TestModuleT5Entry; + + const exports = { + takeEntry: function bjs_takeEntry(entry) { + structHelpers.M10TestModuleT5Entry.lower(entry); + instance.exports.bjs_takeEntry(); + const structValue = structHelpers.M10TestModuleT5Entry.lift(); + return structValue; + }, + takeCatalogEntry: function bjs_takeCatalogEntry(entry) { + structHelpers.M10TestModuleT7CatalogT5Entry.lower(entry); + instance.exports.bjs_takeCatalogEntry(); + const structValue = structHelpers.M10TestModuleT7CatalogT5Entry.lift(); + return structValue; + }, + Catalog: { + Entry: { + init: function(title) { + const titleBytes = textEncoder.encode(title); + const titleId = swift.memory.retain(titleBytes); + instance.exports.bjs_Catalog_Entry_init(titleId, titleBytes.length); + const structValue = structHelpers.M10TestModuleT7CatalogT5Entry.lift(); + return structValue; + }, + }, + }, + Entry: { + init: function(identifier) { + instance.exports.bjs_Entry_init(identifier); + const structValue = structHelpers.M10TestModuleT5Entry.lift(); + return structValue; + }, + }, + }; + _exports = exports; + return exports; + }, + } +} \ No newline at end of file From 59a62746895f6a2d5e4c68ff2e9d4c486415a73f Mon Sep 17 00:00:00 2001 From: William Taylor Date: Mon, 17 Aug 2026 16:03:35 +1000 Subject: [PATCH 4/4] =?UTF-8?q?BridgeJS:=20Don=E2=80=99t=20put=20dots=20in?= =?UTF-8?q?=20mangled=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 18 ++++++---- .../NamespacedClassSignature.json | 2 +- .../NamespacedClassSignature.swift | 34 +++++++++---------- .../NamespacedClassSignature.js | 10 +++--- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 79d6b4b07..8aaa6d5cd 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -1987,11 +1987,11 @@ extension BridgeType { case .void: return "y" case .jsObject(let name): let typeName = name ?? "JSObject" - return "\(typeName.count)\(typeName)C" + return "\(Self.mangleQualifiedName(typeName))C" case .jsValue: return "7JSValueV" case .swiftHeapObject(let name): - return "\(name.count)\(name)C" + return "\(Self.mangleQualifiedName(name))C" case .unsafePointer(let ptr): func sanitize(_ s: String) -> String { s.filter { $0.isNumber || $0.isLetter } @@ -2016,11 +2016,11 @@ extension BridgeType { .rawValueEnum(let name, _), .associatedValueEnum(let name), .namespaceEnum(let name): - return "\(name.count)\(name)O" + return "\(Self.mangleQualifiedName(name))O" case .swiftProtocol(let name): - return "\(name.count)\(name)P" + return "\(Self.mangleQualifiedName(name))P" case .swiftStruct(let name): - return "\(name.count)\(name)V" + return "\(Self.mangleQualifiedName(name))V" case .closure(let signature, let useJSTypedClosure): let params = signature.parameters.isEmpty @@ -2037,12 +2037,18 @@ extension BridgeType { case .alias(let name, _): // `name` is the namespace-qualified swiftCallName (unique), so the underlying // representation isn't mangled in - aliases bridge via their JS type's ABI. - return "Al\(name.count)\(name)" + return "Al\(Self.mangleQualifiedName(name))" case .generic(let name): return "\(name.count)\(name)T" } } + /// Transforms a namespace-qualified name into a valid identifier by removing + /// each dot and prefixing each component with length (e.g. `Workshop.Bench` -> `8Workshop5Bench`). + private static func mangleQualifiedName(_ name: String) -> String { + name.split(separator: ".").map { "\($0.count)\($0)" }.joined() + } + /// Determines if an optional type requires side-channel communication for protocol property returns /// /// Side channels are needed when the wrapped type cannot be directly returned via WASM, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json index e4568f101..e6ea49859 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.json @@ -91,7 +91,7 @@ "_0" : { "isAsync" : false, "isThrows" : false, - "mangleName" : "10TestModule14Workshop.BenchC_14Workshop.BenchC", + "mangleName" : "10TestModule8Workshop5BenchC_8Workshop5BenchC", "moduleName" : "TestModule", "parameters" : [ { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift index 511d0f75c..bff3007b7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/NamespacedClassSignature.swift @@ -1,35 +1,35 @@ #if arch(wasm32) -@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") -fileprivate func invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer +@_extern(wasm, module: "bjs", name: "invoke_js_callback_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC") +fileprivate func invoke_js_callback_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC_extern(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer #else -fileprivate func invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { +fileprivate func invoke_js_callback_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC_extern(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { - return invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(callback, param0) +@inline(never) fileprivate func invoke_js_callback_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC(_ callback: Int32, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + return invoke_js_callback_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC_extern(callback, param0) } #if arch(wasm32) -@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") -fileprivate func make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 +@_extern(wasm, module: "bjs", name: "make_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC") +fileprivate func make_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 #else -fileprivate func make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { +fileprivate func make_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC_extern(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { fatalError("Only available on WebAssembly") } #endif -@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { - return make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC_extern(boxPtr, file, line) +@inline(never) fileprivate func make_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC(_ boxPtr: UnsafeMutableRawPointer, _ file: UnsafePointer, _ line: UInt32) -> Int32 { + return make_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC_extern(boxPtr, file, line) } -private enum _BJS_Closure_10TestModule14Workshop.BenchC_14Workshop.BenchC { +private enum _BJS_Closure_10TestModule8Workshop5BenchC_8Workshop5BenchC { static func bridgeJSLift(_ callbackId: Int32) -> (Workshop.Bench) -> Workshop.Bench { let callback = JSObject.bridgeJSLiftParameter(callbackId) return { [callback] param0 in #if arch(wasm32) let param0Pointer = param0.bridgeJSLowerParameter() let callbackValue = callback.bridgeJSLowerParameter() - let ret = invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(callbackValue, param0Pointer) + let ret = invoke_js_callback_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC(callbackValue, param0Pointer) return Workshop.Bench.bridgeJSLiftReturn(ret) #else fatalError("Only available on WebAssembly") @@ -41,7 +41,7 @@ private enum _BJS_Closure_10TestModule14Workshop.BenchC_14Workshop.BenchC { extension JSTypedClosure where Signature == (Workshop.Bench) -> Workshop.Bench { init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping (Workshop.Bench) -> Workshop.Bench) { self.init( - makeClosure: make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC, + makeClosure: make_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC, body: body, fileID: fileID, line: line @@ -49,9 +49,9 @@ extension JSTypedClosure where Signature == (Workshop.Bench) -> Workshop.Bench { } } -@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") -@_cdecl("invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC") -public func _invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(_ boxPtr: UnsafeMutableRawPointer, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { +@_expose(wasm, "invoke_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC") +@_cdecl("invoke_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC") +public func _invoke_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC(_ boxPtr: UnsafeMutableRawPointer, _ param0: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { #if arch(wasm32) let closure = Unmanaged<_BridgeJSTypedClosureBox<(Workshop.Bench) -> Workshop.Bench>>.fromOpaque(boxPtr).takeUnretainedValue().closure let result = closure(Workshop.Bench.bridgeJSLiftParameter(param0)) @@ -76,7 +76,7 @@ public func _bjs_makeBench() -> UnsafeMutableRawPointer { @_cdecl("bjs_refitBench") public func _bjs_refitBench(_ bench: UnsafeMutableRawPointer, _ transform: Int32) -> UnsafeMutableRawPointer { #if arch(wasm32) - let ret = refitBench(_: Workshop.Bench.bridgeJSLiftParameter(bench), _: _BJS_Closure_10TestModule14Workshop.BenchC_14Workshop.BenchC.bridgeJSLift(transform)) + let ret = refitBench(_: Workshop.Bench.bridgeJSLiftParameter(bench), _: _BJS_Closure_10TestModule8Workshop5BenchC_8Workshop5BenchC.bridgeJSLift(transform)) return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js index e963771c4..082d85f65 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NamespacedClassSignature.js @@ -233,7 +233,7 @@ export async function createInstantiator(options, swift) { const func = swift.memory.getObject(funcRef); func.__unregister(); } - bjs["invoke_js_callback_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC"] = function(callbackId, param0) { + bjs["invoke_js_callback_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC"] = function(callbackId, param0) { try { const callback = swift.memory.getObject(callbackId); let ret = callback(_exports.Workshop.Bench.__construct(param0)); @@ -243,9 +243,9 @@ export async function createInstantiator(options, swift) { return 0 } } - bjs["make_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC"] = function(boxPtr, file, line) { - const lower_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC = function(param0) { - const ret = instance.exports.invoke_swift_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC(boxPtr, param0.pointer); + bjs["make_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC"] = function(boxPtr, file, line) { + const lower_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC = function(param0) { + const ret = instance.exports.invoke_swift_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC(boxPtr, param0.pointer); if (tmpRetException) { const error = swift.memory.getObject(tmpRetException); swift.memory.release(tmpRetException); @@ -254,7 +254,7 @@ export async function createInstantiator(options, swift) { } return _exports.Workshop.Bench.__construct(ret); }; - return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule14Workshop.BenchC_14Workshop.BenchC); + return makeClosure(boxPtr, file, line, lower_closure_TestModule_10TestModule8Workshop5BenchC_8Workshop5BenchC); } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) {