From 9c8cb0b5d2308fd9b1c64446a556b72b24e3c71e Mon Sep 17 00:00:00 2001 From: William Taylor Date: Fri, 14 Aug 2026 15:13:22 +1000 Subject: [PATCH 1/2] 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 f37bfb822..2073563cc 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift @@ -525,12 +525,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) { @@ -569,7 +569,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 ) @@ -587,7 +587,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. @@ -627,7 +627,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 } @@ -766,27 +766,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 { @@ -1861,7 +1884,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" @@ -1921,25 +1944,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 { @@ -1958,7 +1979,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( @@ -2023,7 +2044,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" @@ -2209,7 +2230,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" @@ -2524,10 +2545,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 @@ -2544,7 +2564,6 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor { } } } - currentNode = parent.parent } return namespace.isEmpty ? nil : namespace @@ -2552,19 +2571,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 c70de88dc..e4608ae29 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 779553ddeab8761c133637c998b7adcbcd897da0 Mon Sep 17 00:00:00 2001 From: William Taylor Date: Fri, 14 Aug 2026 16:44:43 +1000 Subject: [PATCH 2/2] 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