Skip to content

Commit 1711b35

Browse files
committed
BridgeJS: Test custom exported type names
1 parent 511e46a commit 1711b35

12 files changed

Lines changed: 977 additions & 48 deletions

File tree

Plugins/BridgeJS/Tests/BridgeJSToolTests/DiagnosticsTests.swift

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -696,42 +696,6 @@ import Testing
696696
}
697697
}
698698

699-
@Test
700-
func jsNameOnClassDiagnostic() throws {
701-
let source = """
702-
@JS("Renamed") class Box { @JS init() {} }
703-
"""
704-
let diagnostics = try #require(moduleDiagnostics(source: source))
705-
#expect(diagnostics.description.contains("A separate name for JavaScript is not supported here"))
706-
}
707-
708-
@Test
709-
func jsNameOnStructDiagnostic() throws {
710-
let source = """
711-
@JS("Renamed") struct Box { var x: Int }
712-
"""
713-
let diagnostics = try #require(moduleDiagnostics(source: source))
714-
#expect(diagnostics.description.contains("A separate name for JavaScript is not supported here"))
715-
}
716-
717-
@Test
718-
func jsNameOnEnumDiagnostic() throws {
719-
let source = """
720-
@JS("Renamed") enum Box { case a }
721-
"""
722-
let diagnostics = try #require(moduleDiagnostics(source: source))
723-
#expect(diagnostics.description.contains("A separate name for JavaScript is not supported here"))
724-
}
725-
726-
@Test
727-
func jsNameOnProtocolDiagnostic() throws {
728-
let source = """
729-
@JS("Renamed") protocol Box { func run() }
730-
"""
731-
let diagnostics = try #require(moduleDiagnostics(source: source))
732-
#expect(diagnostics.description.contains("A separate name for JavaScript is not supported here"))
733-
}
734-
735699
@Test
736700
func jsNameOnInitializerDiagnostic() throws {
737701
let source = """
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import Foundation
2+
import SwiftParser
3+
import Testing
4+
5+
@testable import BridgeJSCore
6+
@testable import BridgeJSSkeleton
7+
8+
@Suite struct ExportedTypeNameTests {
9+
private func parse(_ source: String) throws -> ExportedSkeleton {
10+
let generator = SwiftToSkeleton(
11+
progress: .silent,
12+
moduleName: "TestModule",
13+
exposeToGlobal: false,
14+
externalModuleIndex: .empty
15+
)
16+
generator.addSourceFile(Parser.parse(source: source), inputFilePath: "Types.swift")
17+
return try #require(generator.finalize().exported)
18+
}
19+
20+
@Test
21+
func renamedTypesKeepSwiftIdentities() throws {
22+
let exported = try parse(
23+
"""
24+
@JS func box() -> SwiftBox
25+
@JS func record() -> SwiftRecord
26+
@JS func choice() -> SwiftChoice
27+
@JS func delegate(_ value: SwiftDelegate)
28+
@JS("PublicBox") class SwiftBox { @JS init() {} }
29+
@JS("PublicRecord") struct SwiftRecord { var value: Int }
30+
@JS("PublicChoice") enum SwiftChoice { case first }
31+
@JS("PublicDelegate") protocol SwiftDelegate { func run() }
32+
"""
33+
)
34+
#expect(exported.classes.first?.resolvedJSName == "PublicBox")
35+
#expect(exported.structs.first?.resolvedJSName == "PublicRecord")
36+
#expect(exported.enums.first?.resolvedJSName == "PublicChoice")
37+
#expect(exported.protocols.first?.resolvedJSName == "PublicDelegate")
38+
#expect(exported.functions[0].returnType == .swiftHeapObject("SwiftBox"))
39+
#expect(exported.functions[1].returnType == .swiftStruct("SwiftRecord"))
40+
#expect(exported.functions[2].returnType == .caseEnum("SwiftChoice"))
41+
#expect(exported.functions[3].parameters.first?.type == .swiftProtocol("SwiftDelegate"))
42+
}
43+
44+
@Test
45+
func renamedParentsKeepSwiftThunkABI() throws {
46+
let source = """
47+
@JS(namespace: "API") enum InternalAPI {
48+
@JS class Item { @JS init() {} }
49+
}
50+
"""
51+
let original = try parse(source)
52+
let renamed = try parse(
53+
source.replacingOccurrences(of: "@JS(namespace:", with: "@JS(\"PublicAPI\", namespace:")
54+
)
55+
let originalThunks = try ExportSwift(progress: .silent, moduleName: "TestModule", skeleton: original).finalize()
56+
let renamedThunks = try ExportSwift(progress: .silent, moduleName: "TestModule", skeleton: renamed).finalize()
57+
#expect(renamedThunks == originalThunks)
58+
#expect(renamed.classes.first?.tsFullPath == "API.PublicAPI.Item")
59+
}
60+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@JS("PublicBox") final class SwiftBox {
2+
@JS init()
3+
@JS func copy() -> SwiftBox
4+
}
5+
6+
@JS("PublicChoice") enum SwiftChoice {
7+
case first
8+
case second
9+
}
10+
11+
@JS func renamedChoice(_ value: SwiftChoice) -> SwiftChoice
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
{
2+
"exported" : {
3+
"aliases" : [
4+
5+
],
6+
"classes" : [
7+
{
8+
"constructor" : {
9+
"abiName" : "bjs_SwiftBox_init",
10+
"effects" : {
11+
"isAsync" : false,
12+
"isStatic" : false,
13+
"isThrows" : false
14+
},
15+
"parameters" : [
16+
17+
]
18+
},
19+
"isFinal" : true,
20+
"jsName" : "PublicBox",
21+
"methods" : [
22+
{
23+
"abiName" : "bjs_SwiftBox_copy",
24+
"effects" : {
25+
"isAsync" : false,
26+
"isStatic" : false,
27+
"isThrows" : false
28+
},
29+
"name" : "copy",
30+
"parameters" : [
31+
32+
],
33+
"returnType" : {
34+
"swiftHeapObject" : {
35+
"_0" : "SwiftBox"
36+
}
37+
}
38+
}
39+
],
40+
"name" : "SwiftBox",
41+
"properties" : [
42+
43+
],
44+
"swiftCallName" : "SwiftBox"
45+
}
46+
],
47+
"enums" : [
48+
{
49+
"cases" : [
50+
{
51+
"associatedValues" : [
52+
53+
],
54+
"name" : "first"
55+
},
56+
{
57+
"associatedValues" : [
58+
59+
],
60+
"name" : "second"
61+
}
62+
],
63+
"emitStyle" : "const",
64+
"jsName" : "PublicChoice",
65+
"name" : "SwiftChoice",
66+
"staticMethods" : [
67+
68+
],
69+
"staticProperties" : [
70+
71+
],
72+
"swiftCallName" : "SwiftChoice",
73+
"tsFullPath" : "PublicChoice"
74+
}
75+
],
76+
"exposeToGlobal" : false,
77+
"functions" : [
78+
{
79+
"abiName" : "bjs_renamedChoice",
80+
"effects" : {
81+
"isAsync" : false,
82+
"isStatic" : false,
83+
"isThrows" : false
84+
},
85+
"name" : "renamedChoice",
86+
"parameters" : [
87+
{
88+
"label" : "_",
89+
"name" : "value",
90+
"type" : {
91+
"caseEnum" : {
92+
"_0" : "SwiftChoice"
93+
}
94+
}
95+
}
96+
],
97+
"returnType" : {
98+
"caseEnum" : {
99+
"_0" : "SwiftChoice"
100+
}
101+
}
102+
}
103+
],
104+
"protocols" : [
105+
106+
],
107+
"structs" : [
108+
109+
]
110+
},
111+
"moduleName" : "TestModule",
112+
"usedExternalModules" : [
113+
114+
]
115+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
extension SwiftChoice: _BridgedSwiftCaseEnum {
2+
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 {
3+
return bridgeJSRawValue
4+
}
5+
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> SwiftChoice {
6+
return bridgeJSLiftParameter(value)
7+
}
8+
@_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> SwiftChoice {
9+
return SwiftChoice(bridgeJSRawValue: value)!
10+
}
11+
@_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 {
12+
return bridgeJSLowerParameter()
13+
}
14+
15+
@_spi(BridgeJS) @usableFromInline init?(bridgeJSRawValue: Int32) {
16+
switch bridgeJSRawValue {
17+
case 0:
18+
self = .first
19+
case 1:
20+
self = .second
21+
default:
22+
return nil
23+
}
24+
}
25+
26+
@_spi(BridgeJS) @usableFromInline var bridgeJSRawValue: Int32 {
27+
switch self {
28+
case .first:
29+
return 0
30+
case .second:
31+
return 1
32+
}
33+
}
34+
}
35+
36+
@_expose(wasm, "bjs_renamedChoice")
37+
@_cdecl("bjs_renamedChoice")
38+
public func _bjs_renamedChoice(_ value: Int32) -> Int32 {
39+
#if arch(wasm32)
40+
let value = SwiftChoice.bridgeJSLiftParameter(value)
41+
let ret = renamedChoice(_: value)
42+
return ret.bridgeJSLowerReturn()
43+
#else
44+
fatalError("Only available on WebAssembly")
45+
#endif
46+
}
47+
48+
@_expose(wasm, "bjs_SwiftBox_init")
49+
@_cdecl("bjs_SwiftBox_init")
50+
public func _bjs_SwiftBox_init() -> UnsafeMutableRawPointer {
51+
#if arch(wasm32)
52+
let ret = SwiftBox()
53+
return ret.bridgeJSLowerReturn()
54+
#else
55+
fatalError("Only available on WebAssembly")
56+
#endif
57+
}
58+
59+
@_expose(wasm, "bjs_SwiftBox_copy")
60+
@_cdecl("bjs_SwiftBox_copy")
61+
public func _bjs_SwiftBox_copy(_ _self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer {
62+
#if arch(wasm32)
63+
let _self = SwiftBox.bridgeJSLiftParameter(_self)
64+
let ret = _self.copy()
65+
return ret.bridgeJSLowerReturn()
66+
#else
67+
fatalError("Only available on WebAssembly")
68+
#endif
69+
}
70+
71+
@_expose(wasm, "bjs_SwiftBox_deinit")
72+
@_cdecl("bjs_SwiftBox_deinit")
73+
public func _bjs_SwiftBox_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
74+
#if arch(wasm32)
75+
Unmanaged<SwiftBox>.fromOpaque(pointer).release()
76+
#else
77+
fatalError("Only available on WebAssembly")
78+
#endif
79+
}
80+
81+
extension SwiftBox: ConvertibleToJSValue, _BridgedSwiftHeapObject, _BridgedSwiftProtocolExportable {
82+
var jsValue: JSValue {
83+
return .object(JSObject(id: UInt32(bitPattern: _bjs_SwiftBox_wrap(Unmanaged.passRetained(self).toOpaque()))))
84+
}
85+
consuming func bridgeJSLowerAsProtocolReturn() -> Int32 {
86+
_bjs_SwiftBox_wrap(Unmanaged.passRetained(self).toOpaque())
87+
}
88+
}
89+
90+
#if arch(wasm32)
91+
@_extern(wasm, module: "TestModule", name: "bjs_SwiftBox_wrap")
92+
fileprivate func _bjs_SwiftBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32
93+
#else
94+
fileprivate func _bjs_SwiftBox_wrap_extern(_ pointer: UnsafeMutableRawPointer) -> Int32 {
95+
fatalError("Only available on WebAssembly")
96+
}
97+
#endif
98+
@inline(never) fileprivate func _bjs_SwiftBox_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 {
99+
return _bjs_SwiftBox_wrap_extern(pointer)
100+
}
101+
102+
extension SwiftBox: BridgedSwiftGenericBridgeable {
103+
@_spi(BridgeJS) public static let bridgeJSTypeHandle = SwiftBox.bridgeJSMakeTypeHandle()
104+
}
105+
106+
extension SwiftChoice: BridgedSwiftGenericBridgeable {
107+
@_spi(BridgeJS) public static let bridgeJSTypeHandle = SwiftChoice.bridgeJSMakeTypeHandle()
108+
}
109+
110+
#if arch(wasm32)
111+
@_extern(wasm, module: "bjs", name: "bjs_TestModule_register_type_handles")
112+
fileprivate func _bjs_TestModule_register_type_handles_extern(_ base: UnsafePointer<Int32>?, _ count: Int32)
113+
114+
@_expose(wasm, "bjs_TestModule_register_type_handles")
115+
public func _bjs_TestModule_register_type_handles() {
116+
let typeIds: [Int32] = [
117+
SwiftBox.bridgeJSTypeID,
118+
SwiftChoice.bridgeJSTypeID,
119+
]
120+
typeIds.withUnsafeBufferPointer { buffer in
121+
_bjs_TestModule_register_type_handles_extern(buffer.baseAddress, Int32(buffer.count))
122+
}
123+
}
124+
#endif

0 commit comments

Comments
 (0)