@@ -62,6 +62,7 @@ struct BridgeJSLink {
62
62
var classLines : [ String ] = [ ]
63
63
var dtsExportLines : [ String ] = [ ]
64
64
var dtsClassLines : [ String ] = [ ]
65
+ var namespacedFunctions : [ ExportedFunction ] = [ ]
65
66
66
67
if exportedSkeletons. contains ( where: { $0. classes. count > 0 } ) {
67
68
classLines. append (
@@ -87,9 +88,15 @@ struct BridgeJSLink {
87
88
88
89
for function in skeleton. functions {
89
90
var ( js, dts) = renderExportedFunction ( function: function)
91
+
92
+ if function. namespace != nil {
93
+ namespacedFunctions. append ( function)
94
+ }
95
+
90
96
js [ 0 ] = " \( function. name) : " + js[ 0 ]
91
97
js [ js. count - 1 ] += " , "
92
98
exportsLines. append ( contentsOf: js)
99
+
93
100
dtsExportLines. append ( contentsOf: dts)
94
101
}
95
102
}
@@ -108,6 +115,33 @@ struct BridgeJSLink {
108
115
importObjectBuilders. append ( importObjectBuilder)
109
116
}
110
117
118
+ let hasNamespacedFunctions = !namespacedFunctions. isEmpty
119
+
120
+ let exportsSection : String
121
+ if hasNamespacedFunctions {
122
+ let setupLines = renderGlobalNamespace ( namespacedFunctions: namespacedFunctions)
123
+ let namespaceSetupCode = setupLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " )
124
+ exportsSection = """
125
+ \( classLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " ) )
126
+ const exports = {
127
+ \( exportsLines. map { $0. indent ( count: 16 ) } . joined ( separator: " \n " ) )
128
+ };
129
+
130
+ \( namespaceSetupCode)
131
+
132
+ return exports;
133
+ },
134
+ """
135
+ } else {
136
+ exportsSection = """
137
+ \( classLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " ) )
138
+ return {
139
+ \( exportsLines. map { $0. indent ( count: 16 ) } . joined ( separator: " \n " ) )
140
+ };
141
+ },
142
+ """
143
+ }
144
+
111
145
let outputJs = """
112
146
// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
113
147
// DO NOT EDIT.
@@ -169,15 +203,67 @@ struct BridgeJSLink {
169
203
/** @param {WebAssembly.Instance} instance */
170
204
createExports: (instance) => {
171
205
const js = swift.memory.heap;
172
- \( classLines. map { $0. indent ( count: 12 ) } . joined ( separator: " \n " ) )
173
- return {
174
- \( exportsLines. map { $0. indent ( count: 16 ) } . joined ( separator: " \n " ) )
175
- };
176
- },
206
+ \( exportsSection)
177
207
}
178
208
}
179
209
"""
210
+
211
+ // Collect namespace declarations for TypeScript
212
+ var namespaceDeclarations : [ String : [ ( name: String , parameters: [ Parameter ] , returnType: BridgeType ) ] ] = [ : ]
213
+
214
+ for skeleton in exportedSkeletons {
215
+ for function in skeleton. functions {
216
+ if let namespace = function. namespace {
217
+ let namespaceKey = namespace. joined ( separator: " . " )
218
+ if namespaceDeclarations [ namespaceKey] == nil {
219
+ namespaceDeclarations [ namespaceKey] = [ ]
220
+ }
221
+ namespaceDeclarations [ namespaceKey] ? . append ( ( function. name, function. parameters, function. returnType) )
222
+ }
223
+ }
224
+ }
225
+
226
+ // Generate namespace declarations in TypeScript
180
227
var dtsLines : [ String ] = [ ]
228
+
229
+ // Only add export {} and declare global block if we have namespace declarations
230
+ let hasNamespaceDeclarations = !namespaceDeclarations. isEmpty
231
+
232
+ if hasNamespaceDeclarations {
233
+ dtsLines. append ( " export {}; " )
234
+ dtsLines. append ( " " )
235
+ dtsLines. append ( " declare global { " )
236
+ }
237
+
238
+ // Generate namespace structure using nested declarations
239
+ for (namespacePath, functions) in namespaceDeclarations. sorted ( by: { $0. key < $1. key } ) {
240
+ let parts = namespacePath. split ( separator: " . " ) . map ( String . init)
241
+
242
+ // Open namespaces with proper indentation
243
+ for i in 0 ..< parts. count {
244
+ dtsLines. append ( " namespace \( parts [ i] ) { " . indent ( count: 4 * ( hasNamespaceDeclarations ? i + 1 : 1 ) ) )
245
+ }
246
+
247
+ // Add function signatures with proper indentation
248
+ let functionIndentationLevel = hasNamespaceDeclarations ? parts. count + 1 : parts. count
249
+ for (name, parameters, returnType) in functions {
250
+ let signature = " function \( name) \( renderTSSignature ( parameters: parameters, returnType: returnType) ) ; "
251
+ dtsLines. append ( " \( signature) " . indent ( count: 4 * functionIndentationLevel) )
252
+ }
253
+
254
+ // Close namespaces with proper indentation (in reverse order)
255
+ for i in ( 0 ..< parts. count) . reversed ( ) {
256
+ let indentationLevel = hasNamespaceDeclarations ? i + 1 : i
257
+ dtsLines. append ( " } " . indent ( count: 4 * indentationLevel) )
258
+ }
259
+ }
260
+
261
+ if hasNamespaceDeclarations {
262
+ dtsLines. append ( " } " )
263
+ dtsLines. append ( " " )
264
+ }
265
+
266
+ // Add remaining class lines
181
267
dtsLines. append ( contentsOf: dtsClassLines)
182
268
dtsLines. append ( " export type Exports = { " )
183
269
dtsLines. append ( contentsOf: dtsExportLines. map { $0. indent ( count: 4 ) } )
@@ -395,6 +481,47 @@ struct BridgeJSLink {
395
481
396
482
return ( jsLines, dtsTypeLines, dtsExportEntryLines)
397
483
}
484
+
485
+ // __Swift.Foundation.UUID
486
+
487
+ // [__Swift, Foundation, UUID]
488
+ // [[__Swift, Foundation, UUID], [__Swift, Foundation]]
489
+
490
+ // __Swift
491
+ // __Swift.Foundation
492
+ // __Swift.Foundation.UUID
493
+
494
+ func renderGlobalNamespace( namespacedFunctions: [ ExportedFunction ] ) -> [ String ] {
495
+ var lines : [ String ] = [ ]
496
+ var uniqueNamespaces : [ String ] = [ ]
497
+
498
+ var namespacePaths : Set < [ String ] > = Set ( namespacedFunctions
499
+ . compactMap { $0. namespace } )
500
+
501
+ namespacePaths. forEach { namespacePath in
502
+ namespacePath. makeIterator ( ) . enumerated ( ) . forEach { ( index, element) in
503
+ let path = namespacePath [ 0 ... index] . joined ( separator: " . " )
504
+ if !uniqueNamespaces. contains ( path) {
505
+ uniqueNamespaces. append ( path)
506
+ }
507
+ }
508
+ }
509
+
510
+ uniqueNamespaces. map { namespace in
511
+ lines. append ( " if (typeof globalThis. \( namespace) === 'undefined') { " )
512
+ lines. append ( " globalThis. \( namespace) = {}; " )
513
+ lines. append ( " } " )
514
+ }
515
+
516
+ for function in namespacedFunctions {
517
+ if let namespace = function. namespace {
518
+ let namespacePath = namespace. joined ( separator: " . " )
519
+ lines. append ( " globalThis. \( namespacePath) . \( function. name) = exports. \( function. name) ; " )
520
+ }
521
+ }
522
+
523
+ return lines
524
+ }
398
525
399
526
class ImportedThunkBuilder {
400
527
var bodyLines : [ String ] = [ ]
0 commit comments