@@ -62,6 +62,7 @@ struct BridgeJSLink {
6262 var classLines : [ String ] = [ ]
6363 var dtsExportLines : [ String ] = [ ]
6464 var dtsClassLines : [ String ] = [ ]
65+ var namespacedFunctions : [ ExportedFunction ] = [ ]
6566
6667 if exportedSkeletons. contains ( where: { $0. classes. count > 0 } ) {
6768 classLines. append (
@@ -87,9 +88,15 @@ struct BridgeJSLink {
8788
8889 for function in skeleton. functions {
8990 var ( js, dts) = renderExportedFunction ( function: function)
91+
92+ if function. namespace != nil {
93+ namespacedFunctions. append ( function)
94+ }
95+
9096 js [ 0 ] = " \( function. name) : " + js[ 0 ]
9197 js [ js. count - 1 ] += " , "
9298 exportsLines. append ( contentsOf: js)
99+
93100 dtsExportLines. append ( contentsOf: dts)
94101 }
95102 }
@@ -108,6 +115,33 @@ struct BridgeJSLink {
108115 importObjectBuilders. append ( importObjectBuilder)
109116 }
110117
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+
111145 let outputJs = """
112146 // NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
113147 // DO NOT EDIT.
@@ -169,15 +203,67 @@ struct BridgeJSLink {
169203 /** @param {WebAssembly.Instance} instance */
170204 createExports: (instance) => {
171205 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)
177207 }
178208 }
179209 """
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
180227 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
181267 dtsLines. append ( contentsOf: dtsClassLines)
182268 dtsLines. append ( " export type Exports = { " )
183269 dtsLines. append ( contentsOf: dtsExportLines. map { $0. indent ( count: 4 ) } )
@@ -395,6 +481,47 @@ struct BridgeJSLink {
395481
396482 return ( jsLines, dtsTypeLines, dtsExportEntryLines)
397483 }
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+ }
398525
399526 class ImportedThunkBuilder {
400527 var bodyLines : [ String ] = [ ]
0 commit comments