Skip to content

Commit 871815e

Browse files
committed
BridgeJS: Fix name collision for same-named nested structs
1 parent 5e96639 commit 871815e

7 files changed

Lines changed: 286 additions & 28 deletions

File tree

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,9 @@ public struct BridgeJSLink {
232232
var structExportEntries: [(js: [String], dts: [String])] = []
233233
for structDefinition in skeleton.structs {
234234
let (jsStruct, dtsType, dtsExportEntry) = try renderExportedStruct(structDefinition)
235-
data.topLevelDtsTypeLines.append(contentsOf: dtsType)
235+
if structDefinition.namespace == nil {
236+
data.topLevelDtsTypeLines.append(contentsOf: dtsType)
237+
}
236238

237239
if structDefinition.namespace == nil && (!jsStruct.isEmpty || !dtsExportEntry.isEmpty) {
238240
structExportEntries.append((js: jsStruct, dts: dtsExportEntry))
@@ -492,15 +494,15 @@ public struct BridgeJSLink {
492494
printer.write("bjs[\"swift_js_struct_lower_\(structDef.abiName)\"] = function(objectId) {")
493495
printer.indent {
494496
printer.write(
495-
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));"
497+
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(\(JSGlueVariableScope.reservedSwift).memory.getObject(objectId));"
496498
)
497499
}
498500
printer.write("}")
499501

500502
printer.write("bjs[\"swift_js_struct_lift_\(structDef.abiName)\"] = function() {")
501503
printer.indent {
502504
printer.write(
503-
"const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lift();"
505+
"const value = \(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lift();"
504506
)
505507
printer.write("return \(JSGlueVariableScope.reservedSwift).memory.retain(value);")
506508
}
@@ -1005,7 +1007,7 @@ public struct BridgeJSLink {
10051007
let structScope = JSGlueVariableScope(intrinsicRegistry: intrinsicRegistry)
10061008
let fragment = IntrinsicJSFragment.structHelper(structDefinition: structDef, allStructs: allStructs)
10071009
_ = try fragment.printCode(
1008-
[structDef.name],
1010+
[structDef.abiName],
10091011
IntrinsicJSFragment.PrintCodeContext(
10101012
scope: structScope,
10111013
printer: structPrinter,
@@ -1159,10 +1161,10 @@ public struct BridgeJSLink {
11591161
for skeleton in skeletons.compactMap(\.exported) {
11601162
for structDef in skeleton.structs {
11611163
printer.write(
1162-
"const \(structDef.name)Helpers = __bjs_create\(structDef.name)Helpers();"
1164+
"const \(structDef.abiName)Helpers = __bjs_create\(structDef.abiName)Helpers();"
11631165
)
11641166
printer.write(
1165-
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name) = \(structDef.name)Helpers;"
1167+
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName) = \(structDef.abiName)Helpers;"
11661168
)
11671169
printer.nextLine()
11681170
}
@@ -1497,7 +1499,7 @@ public struct BridgeJSLink {
14971499
func renderExportedStruct(
14981500
_ structDefinition: ExportedStruct
14991501
) throws -> (js: [String], dtsType: [String], dtsExportEntry: [String]) {
1500-
let structName = structDefinition.name
1502+
let structName = structDefinition.abiName
15011503
let hasConstructor = structDefinition.constructor != nil
15021504
let staticMethods = structDefinition.methods.filter { $0.effects.isStatic }
15031505
let staticProperties = structDefinition.properties.filter { $0.isStatic }
@@ -2616,6 +2618,7 @@ extension BridgeJSLink {
26162618
var functions: [ExportedFunction] = []
26172619
var classes: [ExportedClass] = []
26182620
var enums: [ExportedEnum] = []
2621+
var structs: [ExportedStruct] = []
26192622
var staticProperties: [ExportedProperty] = []
26202623
var functionJsLines: [(name: String, lines: [String])] = []
26212624
var functionDtsLines: [(name: String, lines: [String])] = []
@@ -2672,6 +2675,14 @@ extension BridgeJSLink {
26722675
currentNode.content.enums.append(enumDef)
26732676
}
26742677

2678+
for structDef in skeleton.structs where structDef.namespace != nil {
2679+
var currentNode = rootNode
2680+
for part in structDef.namespace! {
2681+
currentNode = currentNode.addChild(part)
2682+
}
2683+
currentNode.content.structs.append(structDef)
2684+
}
2685+
26752686
for enumDef in skeleton.enums where enumDef.enumType == .namespace {
26762687
for property in enumDef.staticProperties {
26772688
let fullNamespace = (enumDef.namespace ?? []) + [enumDef.name]
@@ -2983,8 +2994,8 @@ extension BridgeJSLink {
29832994
renderTSSignatureCallback: @escaping ([Parameter], BridgeType, Effects) -> String
29842995
) {
29852996
func hasContent(node: NamespaceNode) -> Bool {
2986-
// Enums are always included
2987-
if !node.content.enums.isEmpty {
2997+
// Enums and structs are always included
2998+
if !node.content.enums.isEmpty || !node.content.structs.isEmpty {
29882999
return true
29893000
}
29903001

@@ -3164,6 +3175,23 @@ extension BridgeJSLink {
31643175
}
31653176
}
31663177

3178+
// Generate struct interface definitions
3179+
let sortedStructs = childNode.content.structs.sorted { $0.name < $1.name }
3180+
for structDef in sortedStructs {
3181+
let instanceProps = structDef.properties.filter { !$0.isStatic }
3182+
printer.write("export interface \(structDef.name) {")
3183+
printer.indent {
3184+
for property in instanceProps {
3185+
let tsType = BridgeJSLink.resolveTypeScriptType(
3186+
property.type,
3187+
exportedSkeletons: exportedSkeletons
3188+
)
3189+
printer.write("\(property.name): \(tsType);")
3190+
}
3191+
}
3192+
printer.write("}")
3193+
}
3194+
31673195
// Only include functions and properties when exposeToGlobal is true
31683196
if exposeToGlobal {
31693197
let sortedFunctions = childNode.content.functions.sorted { $0.name < $1.name }
@@ -3610,7 +3638,7 @@ extension BridgeType {
36103638
case .associatedValueEnum(let name):
36113639
return "\(name)Tag"
36123640
case .swiftStruct(let name):
3613-
return name.components(separatedBy: ".").last ?? name
3641+
return name
36143642
case .namespaceEnum(let name):
36153643
return name
36163644
case .swiftProtocol(let name):

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ struct IntrinsicJSFragment: Sendable {
944944
fullName: String,
945945
kind: JSOptionalKind
946946
) -> IntrinsicJSFragment {
947-
let base = fullName.components(separatedBy: ".").last ?? fullName
947+
let base = fullName.replacingOccurrences(of: ".", with: "_")
948948
let absenceLiteral = kind.absenceLiteral
949949
return IntrinsicJSFragment(
950950
parameters: [],
@@ -1300,7 +1300,7 @@ struct IntrinsicJSFragment: Sendable {
13001300
let base = fullName.components(separatedBy: ".").last ?? fullName
13011301
return .associatedEnumLowerParameter(enumBase: base)
13021302
case .swiftStruct(let fullName):
1303-
let base = fullName.components(separatedBy: ".").last ?? fullName
1303+
let base = fullName.replacingOccurrences(of: ".", with: "_")
13041304
return swiftStructLowerParameter(structBase: base)
13051305
case .closure:
13061306
return IntrinsicJSFragment(
@@ -1360,7 +1360,7 @@ struct IntrinsicJSFragment: Sendable {
13601360
let base = fullName.components(separatedBy: ".").last ?? fullName
13611361
return .associatedEnumLiftReturn(enumBase: base)
13621362
case .swiftStruct(let fullName):
1363-
let base = fullName.components(separatedBy: ".").last ?? fullName
1363+
let base = fullName.replacingOccurrences(of: ".", with: "_")
13641364
return swiftStructLiftReturn(structBase: base)
13651365
case .closure:
13661366
return IntrinsicJSFragment(
@@ -1446,7 +1446,7 @@ struct IntrinsicJSFragment: Sendable {
14461446
case .importTS:
14471447
return .jsObjectLiftRetainedObjectId
14481448
case .exportSwift:
1449-
let base = fullName.components(separatedBy: ".").last ?? fullName
1449+
let base = fullName.replacingOccurrences(of: ".", with: "_")
14501450
return IntrinsicJSFragment(
14511451
parameters: [],
14521452
printCode: { arguments, context in
@@ -1805,7 +1805,7 @@ struct IntrinsicJSFragment: Sendable {
18051805
}
18061806

18071807
static func swiftStructLowerReturn(fullName: String) -> IntrinsicJSFragment {
1808-
swiftStructLower(structBase: fullName.components(separatedBy: ".").last ?? fullName)
1808+
swiftStructLower(structBase: fullName.replacingOccurrences(of: ".", with: "_"))
18091809
}
18101810

18111811
static func swiftStructLowerParameter(structBase: String) -> IntrinsicJSFragment {
@@ -2008,7 +2008,7 @@ struct IntrinsicJSFragment: Sendable {
20082008
}
20092009
)
20102010
case .swiftStruct(let fullName):
2011-
let structBase = fullName.components(separatedBy: ".").last ?? fullName
2011+
let structBase = fullName.replacingOccurrences(of: ".", with: "_")
20122012
return IntrinsicJSFragment(
20132013
parameters: [],
20142014
printCode: { arguments, context in
@@ -2130,7 +2130,7 @@ struct IntrinsicJSFragment: Sendable {
21302130
}
21312131
)
21322132
case .swiftStruct(let fullName):
2133-
let structBase = fullName.components(separatedBy: ".").last ?? fullName
2133+
let structBase = fullName.replacingOccurrences(of: ".", with: "_")
21342134
return IntrinsicJSFragment(
21352135
parameters: ["value"],
21362136
printCode: { arguments, context in
@@ -2426,7 +2426,7 @@ struct IntrinsicJSFragment: Sendable {
24262426
)
24272427
try printer.indent {
24282428
printer.write(
2429-
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.name).lower(this);"
2429+
"\(JSGlueVariableScope.reservedStructHelpers).\(structDef.abiName).lower(this);"
24302430
)
24312431

24322432
var paramForwardings: [String] = []
@@ -2502,7 +2502,7 @@ struct IntrinsicJSFragment: Sendable {
25022502
let printer = context.printer
25032503
let value = arguments[0]
25042504
printer.write(
2505-
"\(JSGlueVariableScope.reservedStructHelpers).\(nestedName).lower(\(value));"
2505+
"\(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lower(\(value));"
25062506
)
25072507
return []
25082508
}
@@ -2540,7 +2540,7 @@ struct IntrinsicJSFragment: Sendable {
25402540
let (scope, printer) = (context.scope, context.printer)
25412541
let structVar = scope.variable("struct")
25422542
printer.write(
2543-
"const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedName).lift();"
2543+
"const \(structVar) = \(JSGlueVariableScope.reservedStructHelpers).\(nestedName.replacingOccurrences(of: ".", with: "_")).lift();"
25442544
)
25452545
return [structVar]
25462546
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,14 @@
88
var score: Double
99
}
1010
}
11+
12+
@JS class Player {
13+
@JS func getTag() -> String {
14+
return "player"
15+
}
16+
17+
@JS struct Stats {
18+
var level: Int
19+
var rating: String
20+
}
21+
}

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,32 @@
2626

2727
],
2828
"swiftCallName" : "User"
29+
},
30+
{
31+
"methods" : [
32+
{
33+
"abiName" : "bjs_Player_getTag",
34+
"effects" : {
35+
"isAsync" : false,
36+
"isStatic" : false,
37+
"isThrows" : false
38+
},
39+
"name" : "getTag",
40+
"parameters" : [
41+
42+
],
43+
"returnType" : {
44+
"string" : {
45+
46+
}
47+
}
48+
}
49+
],
50+
"name" : "Player",
51+
"properties" : [
52+
53+
],
54+
"swiftCallName" : "Player"
2955
}
3056
],
3157
"enums" : [
@@ -79,6 +105,47 @@
79105
}
80106
],
81107
"swiftCallName" : "User.Stats"
108+
},
109+
{
110+
"methods" : [
111+
112+
],
113+
"name" : "Stats",
114+
"namespace" : [
115+
"Player"
116+
],
117+
"properties" : [
118+
{
119+
"isReadonly" : true,
120+
"isStatic" : false,
121+
"name" : "level",
122+
"namespace" : [
123+
"Player"
124+
],
125+
"type" : {
126+
"integer" : {
127+
"_0" : {
128+
"isSigned" : true,
129+
"width" : "word"
130+
}
131+
}
132+
}
133+
},
134+
{
135+
"isReadonly" : true,
136+
"isStatic" : false,
137+
"name" : "rating",
138+
"namespace" : [
139+
"Player"
140+
],
141+
"type" : {
142+
"string" : {
143+
144+
}
145+
}
146+
}
147+
],
148+
"swiftCallName" : "Player.Stats"
82149
}
83150
]
84151
},

0 commit comments

Comments
 (0)