Skip to content

Commit 46182e2

Browse files
authored
Merge pull request #717 from PassiveLogic/kr/fix-class-static-method-ts
BridgeJS: Emit static methods and properties on namespaced class entries
2 parents 0d6544f + 57c1fd8 commit 46182e2

File tree

15 files changed

+248
-24
lines changed

15 files changed

+248
-24
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,11 @@ public class ExportSwift {
433433
switch self {
434434
case .enumStatic(let enumDef):
435435
return property.callName(prefix: enumDef.swiftCallName)
436-
case .classStatic, .classInstance:
436+
case .classStatic(let klass):
437+
// property.callName() would use staticContext (the ABI name) as prefix;
438+
// use swiftCallName directly so the emitted expression is valid Swift.
439+
return "\(klass.swiftCallName).\(property.name)"
440+
case .classInstance:
437441
return property.callName()
438442
case .structStatic(let structDef):
439443
return property.callName(prefix: structDef.swiftCallName)

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ public struct BridgeJSLink {
130130
var classLines: [String] = []
131131
var dtsExportLines: [String] = []
132132
var dtsClassLines: [String] = []
133+
var namespacedClassDtsExportEntries: [String: [String]] = [:]
133134
var topLevelTypeLines: [String] = []
134135
var topLevelDtsTypeLines: [String] = []
135136
var importObjectBuilders: [ImportObjectBuilder] = []
@@ -161,13 +162,14 @@ public struct BridgeJSLink {
161162
for klass in skeleton.classes {
162163
let (jsType, dtsType, dtsExportEntry) = try renderExportedClass(klass)
163164
data.classLines.append(contentsOf: jsType)
165+
data.dtsClassLines.append(contentsOf: dtsType)
164166

165167
if klass.namespace == nil {
166168
data.exportsLines.append("\(klass.name),")
167169
data.dtsExportLines.append(contentsOf: dtsExportEntry)
170+
} else {
171+
data.namespacedClassDtsExportEntries[klass.name] = dtsExportEntry
168172
}
169-
170-
data.dtsClassLines.append(contentsOf: dtsType)
171173
}
172174

173175
// Process enums - collect top-level definitions and export entries
@@ -884,32 +886,21 @@ public struct BridgeJSLink {
884886
printer.write(lines: generateImportedTypeDefinitions())
885887

886888
// Exports type
889+
let hierarchicalExportLines = namespaceBuilder.buildHierarchicalExportsType(
890+
exportedSkeletons: exportedSkeletons,
891+
renderClassEntry: { klass in
892+
data.namespacedClassDtsExportEntries[klass.name] ?? []
893+
},
894+
renderFunctionSignature: { function in
895+
"\(function.name)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));"
896+
}
897+
)
887898
printer.write("export type Exports = {")
888899
printer.indent {
889900
// Add non-namespaced items
890901
printer.write(lines: data.dtsExportLines)
891-
892902
// Add hierarchical namespaced items
893-
let hierarchicalLines = namespaceBuilder.buildHierarchicalExportsType(
894-
exportedSkeletons: exportedSkeletons,
895-
renderClassEntry: { klass in
896-
let printer = CodeFragmentPrinter()
897-
printer.write("\(klass.name): {")
898-
printer.indent {
899-
if let constructor = klass.constructor {
900-
printer.write(
901-
"new\(self.renderTSSignature(parameters: constructor.parameters, returnType: .swiftHeapObject(klass.name), effects: constructor.effects));"
902-
)
903-
}
904-
}
905-
printer.write("}")
906-
return printer.lines
907-
},
908-
renderFunctionSignature: { function in
909-
"\(function.name)\(self.renderTSSignature(parameters: function.parameters, returnType: function.returnType, effects: function.effects));"
910-
}
911-
)
912-
printer.write(lines: hierarchicalLines)
903+
printer.write(lines: hierarchicalExportLines)
913904
}
914905
printer.write("}")
915906

Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/MacroSwift/Namespaces.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@
1616
func changeName(name: String) {
1717
self.name = name
1818
}
19+
20+
// Static methods and properties on a namespaced class must land on the
21+
// class's namespace entry (alongside `new`), not on the instance
22+
// interface and not silently dropped. Regression test for the
23+
// `@JS(namespace:)` + `@JS static func` bug where the hierarchical
24+
// exports builder only emitted the constructor.
25+
@JS static func makeDefault() -> Greeter {
26+
return Greeter(name: "World")
27+
}
28+
29+
@JS static var defaultGreeting: String { "Hello, world!" }
1930
}
2031

2132
@JS(namespace: "Utils.Converters") class Converter {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,28 @@
3838

3939
}
4040
}
41+
},
42+
{
43+
"abiName" : "bjs___Swift_Foundation_Greeter_static_makeDefault",
44+
"effects" : {
45+
"isAsync" : false,
46+
"isStatic" : true,
47+
"isThrows" : false
48+
},
49+
"name" : "makeDefault",
50+
"parameters" : [
51+
52+
],
53+
"returnType" : {
54+
"swiftHeapObject" : {
55+
"_0" : "Greeter"
56+
}
57+
},
58+
"staticContext" : {
59+
"className" : {
60+
"_0" : "__Swift_Foundation_Greeter"
61+
}
62+
}
4163
}
4264
],
4365
"name" : "Greeter",
@@ -46,7 +68,21 @@
4668
"Foundation"
4769
],
4870
"properties" : [
71+
{
72+
"isReadonly" : true,
73+
"isStatic" : true,
74+
"name" : "defaultGreeting",
75+
"staticContext" : {
76+
"className" : {
77+
"_0" : "__Swift_Foundation_Greeter"
78+
}
79+
},
80+
"type" : {
81+
"string" : {
4982

83+
}
84+
}
85+
}
5086
],
5187
"swiftCallName" : "Greeter"
5288
},

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.Global.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,28 @@ public func _bjs___Swift_Foundation_Greeter_greet(_ _self: UnsafeMutableRawPoint
4242
#endif
4343
}
4444

45+
@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_makeDefault")
46+
@_cdecl("bjs___Swift_Foundation_Greeter_static_makeDefault")
47+
public func _bjs___Swift_Foundation_Greeter_static_makeDefault() -> UnsafeMutableRawPointer {
48+
#if arch(wasm32)
49+
let ret = Greeter.makeDefault()
50+
return ret.bridgeJSLowerReturn()
51+
#else
52+
fatalError("Only available on WebAssembly")
53+
#endif
54+
}
55+
56+
@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_defaultGreeting_get")
57+
@_cdecl("bjs___Swift_Foundation_Greeter_static_defaultGreeting_get")
58+
public func _bjs___Swift_Foundation_Greeter_static_defaultGreeting_get() -> Void {
59+
#if arch(wasm32)
60+
let ret = Greeter.defaultGreeting
61+
return ret.bridgeJSLowerReturn()
62+
#else
63+
fatalError("Only available on WebAssembly")
64+
#endif
65+
}
66+
4567
@_expose(wasm, "bjs___Swift_Foundation_Greeter_deinit")
4668
@_cdecl("bjs___Swift_Foundation_Greeter_deinit")
4769
public func _bjs___Swift_Foundation_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,28 @@
3838

3939
}
4040
}
41+
},
42+
{
43+
"abiName" : "bjs___Swift_Foundation_Greeter_static_makeDefault",
44+
"effects" : {
45+
"isAsync" : false,
46+
"isStatic" : true,
47+
"isThrows" : false
48+
},
49+
"name" : "makeDefault",
50+
"parameters" : [
51+
52+
],
53+
"returnType" : {
54+
"swiftHeapObject" : {
55+
"_0" : "Greeter"
56+
}
57+
},
58+
"staticContext" : {
59+
"className" : {
60+
"_0" : "__Swift_Foundation_Greeter"
61+
}
62+
}
4163
}
4264
],
4365
"name" : "Greeter",
@@ -46,7 +68,21 @@
4668
"Foundation"
4769
],
4870
"properties" : [
71+
{
72+
"isReadonly" : true,
73+
"isStatic" : true,
74+
"name" : "defaultGreeting",
75+
"staticContext" : {
76+
"className" : {
77+
"_0" : "__Swift_Foundation_Greeter"
78+
}
79+
},
80+
"type" : {
81+
"string" : {
4982

83+
}
84+
}
85+
}
5086
],
5187
"swiftCallName" : "Greeter"
5288
},

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSCodegenTests/Namespaces.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,28 @@ public func _bjs___Swift_Foundation_Greeter_greet(_ _self: UnsafeMutableRawPoint
4242
#endif
4343
}
4444

45+
@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_makeDefault")
46+
@_cdecl("bjs___Swift_Foundation_Greeter_static_makeDefault")
47+
public func _bjs___Swift_Foundation_Greeter_static_makeDefault() -> UnsafeMutableRawPointer {
48+
#if arch(wasm32)
49+
let ret = Greeter.makeDefault()
50+
return ret.bridgeJSLowerReturn()
51+
#else
52+
fatalError("Only available on WebAssembly")
53+
#endif
54+
}
55+
56+
@_expose(wasm, "bjs___Swift_Foundation_Greeter_static_defaultGreeting_get")
57+
@_cdecl("bjs___Swift_Foundation_Greeter_static_defaultGreeting_get")
58+
public func _bjs___Swift_Foundation_Greeter_static_defaultGreeting_get() -> Void {
59+
#if arch(wasm32)
60+
let ret = Greeter.defaultGreeting
61+
return ret.bridgeJSLowerReturn()
62+
#else
63+
fatalError("Only available on WebAssembly")
64+
#endif
65+
}
66+
4567
@_expose(wasm, "bjs___Swift_Foundation_Greeter_deinit")
4668
@_cdecl("bjs___Swift_Foundation_Greeter_deinit")
4769
public func _bjs___Swift_Foundation_Greeter_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ declare global {
3434
class Greeter {
3535
constructor(name: string);
3636
greet(): string;
37+
makeDefault(): Greeter;
3738
release(): void;
3839
}
3940
class UUID {
@@ -87,6 +88,8 @@ export type Exports = {
8788
Foundation: {
8889
Greeter: {
8990
new(name: string): Greeter;
91+
makeDefault(): Greeter;
92+
readonly defaultGreeting: string;
9093
}
9194
UUID: {
9295
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,16 @@ export async function createInstantiator(options, swift) {
268268
tmpRetString = undefined;
269269
return ret;
270270
}
271+
static makeDefault() {
272+
const ret = instance.exports.bjs___Swift_Foundation_Greeter_static_makeDefault();
273+
return Greeter.__construct(ret);
274+
}
275+
static get defaultGreeting() {
276+
instance.exports.bjs___Swift_Foundation_Greeter_static_defaultGreeting_get();
277+
const ret = tmpRetString;
278+
tmpRetString = undefined;
279+
return ret;
280+
}
271281
}
272282
class Converter extends SwiftHeapObject {
273283
static __construct(ptr) {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export type Exports = {
4747
Foundation: {
4848
Greeter: {
4949
new(name: string): Greeter;
50+
makeDefault(): Greeter;
51+
readonly defaultGreeting: string;
5052
}
5153
UUID: {
5254
}

0 commit comments

Comments
 (0)