Skip to content

Commit 494ed16

Browse files
committed
BridgeJS: Include namespace prefix in ABI names for namespace-nested classes and structs
1 parent e902160 commit 494ed16

30 files changed

+858
-518
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,9 @@ public class ExportSwift {
389389
case .enumStatic(let enumDef):
390390
return enumDef.name
391391
case .classStatic(let klass), .classInstance(let klass):
392-
return klass.name
392+
return klass.abiName
393393
case .structStatic(let structDef):
394-
return structDef.name
394+
return structDef.abiName
395395
}
396396
}
397397

@@ -653,7 +653,7 @@ public class ExportSwift {
653653

654654
do {
655655
let funcDecl = SwiftCodePattern.buildExposedFunctionDecl(
656-
abiName: "bjs_\(klass.name)_deinit",
656+
abiName: "bjs_\(klass.abiName)_deinit",
657657
signature: SwiftSignatureBuilder.buildABIFunctionSignature(
658658
abiParameters: [("pointer", .pointer)],
659659
returnType: nil
@@ -686,8 +686,8 @@ public class ExportSwift {
686686
/// fileprivate func _bjs_Greeter_wrap(_: UnsafeMutableRawPointer) -> Int32
687687
/// ```
688688
func renderConvertibleToJSValueExtension(klass: ExportedClass) -> [DeclSyntax] {
689-
let wrapFunctionName = "_bjs_\(klass.name)_wrap"
690-
let externFunctionName = "bjs_\(klass.name)_wrap"
689+
let wrapFunctionName = "_bjs_\(klass.abiName)_wrap"
690+
let externFunctionName = "bjs_\(klass.abiName)_wrap"
691691

692692
// If the class has an explicit access control, we need to add it to the extension declaration.
693693
let accessControl = klass.explicitAccessControl.map { "\($0) " } ?? ""
@@ -1087,10 +1087,10 @@ struct StructCodegen {
10871087
func renderStructHelpers(_ structDef: ExportedStruct) -> [DeclSyntax] {
10881088
let typeName = structDef.swiftCallName
10891089

1090-
let lowerExternName = "swift_js_struct_lower_\(structDef.name)"
1091-
let liftExternName = "swift_js_struct_lift_\(structDef.name)"
1092-
let lowerFunctionName = "_bjs_struct_lower_\(structDef.name)"
1093-
let liftFunctionName = "_bjs_struct_lift_\(structDef.name)"
1090+
let lowerExternName = "swift_js_struct_lower_\(structDef.abiName)"
1091+
let liftExternName = "swift_js_struct_lift_\(structDef.abiName)"
1092+
let lowerFunctionName = "_bjs_struct_lower_\(structDef.abiName)"
1093+
let liftFunctionName = "_bjs_struct_lift_\(structDef.abiName)"
10941094

10951095
let printer = CodeFragmentPrinter()
10961096
printer.write("extension \(typeName): _BridgedSwiftStruct {")

Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,9 +1060,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
10601060
switch state {
10611061
case .topLevel:
10621062
staticContext = nil
1063-
case .classBody(let className, _):
1063+
case .classBody(_, let classKey):
10641064
if isStatic {
1065-
staticContext = .className(className)
1065+
let classAbiName = exportedClassByName[classKey]?.abiName ?? "unknown"
1066+
staticContext = .className(classAbiName)
10661067
} else {
10671068
staticContext = nil
10681069
}
@@ -1077,20 +1078,21 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
10771078
staticContext = isNamespaceEnum ? .namespaceEnum(swiftCallName) : .enumName(enumName)
10781079
case .protocolBody(_, _):
10791080
return nil
1080-
case .structBody(let structName, _):
1081+
case .structBody(_, let structKey):
10811082
if isStatic {
1082-
staticContext = .structName(structName)
1083+
let structAbiName = exportedStructByName[structKey]?.abiName ?? "unknown"
1084+
staticContext = .structName(structAbiName)
10831085
} else {
10841086
staticContext = nil
10851087
}
10861088
}
10871089

10881090
let classNameForABI: String?
10891091
switch state {
1090-
case .classBody(let className, _):
1091-
classNameForABI = className
1092-
case .structBody(let structName, _):
1093-
classNameForABI = structName
1092+
case .classBody(_, let classKey):
1093+
classNameForABI = exportedClassByName[classKey]?.abiName
1094+
case .structBody(_, let structKey):
1095+
classNameForABI = exportedStructByName[structKey]?.abiName
10941096
default:
10951097
classNameForABI = nil
10961098
}
@@ -1179,7 +1181,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
11791181
guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren }
11801182

11811183
switch state {
1182-
case .classBody(let className, let classKey):
1184+
case .classBody(_, let classKey):
11831185
if extractNamespace(from: jsAttribute) != nil {
11841186
diagnose(
11851187
node: jsAttribute,
@@ -1194,14 +1196,15 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
11941196
return .skipChildren
11951197
}
11961198

1199+
let classAbiName = exportedClassByName[classKey]?.abiName ?? "unknown"
11971200
let constructor = ExportedConstructor(
1198-
abiName: "bjs_\(className)_init",
1201+
abiName: "bjs_\(classAbiName)_init",
11991202
parameters: parameters,
12001203
effects: effects
12011204
)
12021205
exportedClassByName[classKey]?.constructor = constructor
12031206

1204-
case .structBody(let structName, let structKey):
1207+
case .structBody(_, let structKey):
12051208
if extractNamespace(from: jsAttribute) != nil {
12061209
diagnose(
12071210
node: jsAttribute,
@@ -1216,8 +1219,9 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
12161219
return .skipChildren
12171220
}
12181221

1222+
let structAbiName = exportedStructByName[structKey]?.abiName ?? "unknown"
12191223
let constructor = ExportedConstructor(
1220-
abiName: "bjs_\(structName)_init",
1224+
abiName: "bjs_\(structAbiName)_init",
12211225
parameters: parameters,
12221226
effects: effects
12231227
)
@@ -1263,8 +1267,13 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
12631267
let staticContext: StaticContext?
12641268

12651269
switch state {
1266-
case .classBody(let className, _):
1267-
staticContext = isStatic ? .className(className) : nil
1270+
case .classBody(_, let classKey):
1271+
if isStatic {
1272+
let classAbiName = exportedClassByName[classKey]?.abiName ?? "unknown"
1273+
staticContext = .className(classAbiName)
1274+
} else {
1275+
staticContext = nil
1276+
}
12681277
case .enumBody(let enumName, let enumKey):
12691278
if !isStatic {
12701279
diagnose(node: node, message: "Only static properties are supported in enums")
@@ -1280,9 +1289,10 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
12801289
return .skipChildren
12811290
case .protocolBody(let protocolName, let protocolKey):
12821291
return visitProtocolProperty(node: node, protocolName: protocolName, protocolKey: protocolKey)
1283-
case .structBody(let structName, _):
1292+
case .structBody(_, let structKey):
12841293
if isStatic {
1285-
staticContext = .structName(structName)
1294+
let structAbiName = exportedStructByName[structKey]?.abiName ?? "unknown"
1295+
staticContext = .structName(structAbiName)
12861296
} else {
12871297
diagnose(node: node, message: "@JS var must be static in structs (instance fields don't need @JS)")
12881298
return .skipChildren

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -447,15 +447,15 @@ public struct BridgeJSLink {
447447
printer.write("}")
448448
if !allStructs.isEmpty {
449449
for structDef in allStructs {
450-
printer.write("bjs[\"swift_js_struct_lower_\(structDef.name)\"] = function(objectId) {")
450+
printer.write("bjs[\"swift_js_struct_lower_\(structDef.abiName)\"] = function(objectId) {")
451451
printer.indent {
452452
printer.write(
453453
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));"
454454
)
455455
}
456456
printer.write("}")
457457

458-
printer.write("bjs[\"swift_js_struct_lift_\(structDef.name)\"] = function() {")
458+
printer.write("bjs[\"swift_js_struct_lift_\(structDef.abiName)\"] = function() {")
459459
printer.indent {
460460
printer.write(
461461
"const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lift();"
@@ -1155,7 +1155,7 @@ public struct BridgeJSLink {
11551155
wrapperLines.append("}")
11561156

11571157
for klass in classes.sorted(by: { $0.name < $1.name }) {
1158-
let wrapperFunctionName = "bjs_\(klass.name)_wrap"
1158+
let wrapperFunctionName = "bjs_\(klass.abiName)_wrap"
11591159
let namespacePath = (klass.namespace ?? []).map { ".\($0)" }.joined()
11601160
let exportsPath =
11611161
namespacePath.isEmpty ? "_exports['\(klass.name)']" : "_exports\(namespacePath).\(klass.name)"
@@ -1967,7 +1967,7 @@ extension BridgeJSLink {
19671967
jsPrinter.write("static __construct(ptr) {")
19681968
jsPrinter.indent {
19691969
jsPrinter.write(
1970-
"return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_\(klass.name)_deinit, \(klass.name).prototype);"
1970+
"return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_\(klass.abiName)_deinit, \(klass.name).prototype);"
19711971
)
19721972
}
19731973
jsPrinter.write("}")
@@ -2069,7 +2069,7 @@ extension BridgeJSLink {
20692069
for property in klass.properties {
20702070
try renderClassProperty(
20712071
property: property,
2072-
className: klass.name,
2072+
className: klass.abiName,
20732073
isStatic: property.isStatic,
20742074
jsPrinter: jsPrinter,
20752075
dtsPrinter: property.isStatic ? dtsExportEntryPrinter : dtsTypePrinter

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
// This file is shared between BridgeTool and BridgeJSLink
22

3+
// MARK: - Namespaced Type Protocol
4+
5+
public protocol NamespacedExportedType {
6+
var name: String { get }
7+
var namespace: [String]? { get }
8+
}
9+
10+
extension NamespacedExportedType {
11+
public var abiName: String {
12+
if let namespace = namespace, !namespace.isEmpty {
13+
return (namespace + [name]).joined(separator: "_")
14+
}
15+
return name
16+
}
17+
}
18+
319
// MARK: - ABI Name Generation
420

521
/// Utility for generating consistent ABI names across all exported and imported types
@@ -412,7 +428,7 @@ public struct StructField: Codable, Equatable, Sendable {
412428
}
413429
}
414430

415-
public struct ExportedStruct: Codable, Equatable, Sendable {
431+
public struct ExportedStruct: Codable, Equatable, Sendable, NamespacedExportedType {
416432
public let name: String
417433
public let swiftCallName: String
418434
public let explicitAccessControl: String?
@@ -490,7 +506,7 @@ public enum EnumEmitStyle: String, Codable, Sendable {
490506
case tsEnum
491507
}
492508

493-
public struct ExportedEnum: Codable, Equatable, Sendable {
509+
public struct ExportedEnum: Codable, Equatable, Sendable, NamespacedExportedType {
494510
public static let valuesSuffix = "Values"
495511
public static let objectSuffix = "Object"
496512

@@ -619,7 +635,7 @@ public struct ExportedFunction: Codable, Equatable, Sendable {
619635
}
620636
}
621637

622-
public struct ExportedClass: Codable {
638+
public struct ExportedClass: Codable, NamespacedExportedType {
623639
public var name: String
624640
public var swiftCallName: String
625641
public var explicitAccessControl: String?

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ enum Internal {
5757
}
5858
}
5959

60+
@JS enum Formatting {
61+
@JS class Converter {
62+
@JS init() {}
63+
64+
@JS func format(value: Int) -> String {
65+
return "formatted_\(value)"
66+
}
67+
}
68+
}
69+
6070
@JS(namespace: "Services.Graph")
6171
enum GraphOperations {
6272
@JS static func createGraph(rootId: Int) -> Int {

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

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"classes" : [
44
{
55
"constructor" : {
6-
"abiName" : "bjs_Converter_init",
6+
"abiName" : "bjs_Utils_Converter_init",
77
"effects" : {
88
"isAsync" : false,
99
"isStatic" : false,
@@ -15,7 +15,7 @@
1515
},
1616
"methods" : [
1717
{
18-
"abiName" : "bjs_Converter_toString",
18+
"abiName" : "bjs_Utils_Converter_toString",
1919
"effects" : {
2020
"isAsync" : false,
2121
"isStatic" : false,
@@ -66,7 +66,7 @@
6666
},
6767
{
6868
"constructor" : {
69-
"abiName" : "bjs_HTTPServer_init",
69+
"abiName" : "bjs_Networking_API_HTTPServer_init",
7070
"effects" : {
7171
"isAsync" : false,
7272
"isStatic" : false,
@@ -78,7 +78,7 @@
7878
},
7979
"methods" : [
8080
{
81-
"abiName" : "bjs_HTTPServer_call",
81+
"abiName" : "bjs_Networking_API_HTTPServer_call",
8282
"effects" : {
8383
"isAsync" : false,
8484
"isStatic" : false,
@@ -119,7 +119,7 @@
119119
},
120120
{
121121
"constructor" : {
122-
"abiName" : "bjs_TestServer_init",
122+
"abiName" : "bjs_Networking_APIV2_Internal_TestServer_init",
123123
"effects" : {
124124
"isAsync" : false,
125125
"isStatic" : false,
@@ -131,7 +131,7 @@
131131
},
132132
"methods" : [
133133
{
134-
"abiName" : "bjs_TestServer_call",
134+
"abiName" : "bjs_Networking_APIV2_Internal_TestServer_call",
135135
"effects" : {
136136
"isAsync" : false,
137137
"isStatic" : false,
@@ -171,6 +171,57 @@
171171

172172
],
173173
"swiftCallName" : "Internal.TestServer"
174+
},
175+
{
176+
"constructor" : {
177+
"abiName" : "bjs_Formatting_Converter_init",
178+
"effects" : {
179+
"isAsync" : false,
180+
"isStatic" : false,
181+
"isThrows" : false
182+
},
183+
"parameters" : [
184+
185+
]
186+
},
187+
"methods" : [
188+
{
189+
"abiName" : "bjs_Formatting_Converter_format",
190+
"effects" : {
191+
"isAsync" : false,
192+
"isStatic" : false,
193+
"isThrows" : false
194+
},
195+
"name" : "format",
196+
"namespace" : [
197+
"Formatting"
198+
],
199+
"parameters" : [
200+
{
201+
"label" : "value",
202+
"name" : "value",
203+
"type" : {
204+
"int" : {
205+
206+
}
207+
}
208+
}
209+
],
210+
"returnType" : {
211+
"string" : {
212+
213+
}
214+
}
215+
}
216+
],
217+
"name" : "Converter",
218+
"namespace" : [
219+
"Formatting"
220+
],
221+
"properties" : [
222+
223+
],
224+
"swiftCallName" : "Formatting.Converter"
174225
}
175226
],
176227
"enums" : [
@@ -417,6 +468,21 @@
417468
{
418469
"cases" : [
419470

471+
],
472+
"emitStyle" : "const",
473+
"name" : "Formatting",
474+
"staticMethods" : [
475+
476+
],
477+
"staticProperties" : [
478+
479+
],
480+
"swiftCallName" : "Formatting",
481+
"tsFullPath" : "Formatting"
482+
},
483+
{
484+
"cases" : [
485+
420486
],
421487
"emitStyle" : "const",
422488
"name" : "GraphOperations",

0 commit comments

Comments
 (0)