Skip to content

Commit 1fda970

Browse files
authored
Merge pull request #469 from PassiveLogic/feat/configurable-global-namespace
BridgeJS: exposeToGlobal configuration option to control declare global declaration
2 parents 8f31637 + 4a682aa commit 1fda970

File tree

86 files changed

+6801
-540
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+6801
-540
lines changed

Benchmarks/Sources/Generated/JavaScript/BridgeJS.ExportSwift.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,8 @@
502502
"staticProperties" : [
503503

504504
],
505-
"swiftCallName" : "APIResult"
505+
"swiftCallName" : "APIResult",
506+
"tsFullPath" : "APIResult"
506507
},
507508
{
508509
"cases" : [
@@ -698,9 +699,11 @@
698699
"staticProperties" : [
699700

700701
],
701-
"swiftCallName" : "ComplexResult"
702+
"swiftCallName" : "ComplexResult",
703+
"tsFullPath" : "ComplexResult"
702704
}
703705
],
706+
"exposeToGlobal" : false,
704707
"functions" : [
705708
{
706709
"abiName" : "bjs_run",

Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/JavaScript/BridgeJS.ExportSwift.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
"enums" : [
136136

137137
],
138+
"exposeToGlobal" : false,
138139
"functions" : [
139140

140141
],

Examples/PlayBridgeJS/Sources/PlayBridgeJS/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import class Foundation.JSONDecoder
1717
}
1818

1919
func _update(swiftSource: String, dtsSource: String) throws -> PlayBridgeJSOutput {
20-
let exportSwift = ExportSwift(progress: .silent, moduleName: "Playground")
20+
let exportSwift = ExportSwift(progress: .silent, moduleName: "Playground", exposeToGlobal: false)
2121
let sourceFile = Parser.parse(source: swiftSource)
2222
try exportSwift.addSourceFile(sourceFile, "Playground.swift")
2323
let exportResult = try exportSwift.finalize()

Package.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,5 +180,18 @@ let package = Package(
180180
],
181181
linkerSettings: testingLinkerFlags
182182
),
183+
.testTarget(
184+
name: "BridgeJSGlobalTests",
185+
dependencies: ["JavaScriptKit", "JavaScriptEventLoop"],
186+
exclude: [
187+
"bridge-js.config.json",
188+
"bridge-js.d.ts",
189+
"Generated/JavaScript",
190+
],
191+
swiftSettings: [
192+
.enableExperimentalFeature("Extern")
193+
],
194+
linkerSettings: testingLinkerFlags
195+
),
183196
]
184197
)

Plugins/BridgeJS/Sources/BridgeJSBuildPlugin/BridgeJSBuildPlugin.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ struct BridgeJSBuildPlugin: BuildToolPlugin {
4444
"export",
4545
"--module-name",
4646
target.name,
47+
"--target-dir",
48+
target.directoryURL.path,
4749
"--output-skeleton",
4850
outputSkeletonPath.path,
4951
"--output-swift",

Plugins/BridgeJS/Sources/BridgeJSCommandPlugin/BridgeJSCommandPlugin.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ extension BridgeJSCommandPlugin.Context {
107107
"export",
108108
"--module-name",
109109
target.name,
110+
"--target-dir",
111+
target.directoryURL.path,
110112
"--output-skeleton",
111113
generatedJavaScriptDirectory.appending(path: "BridgeJS.ExportSwift.json").path,
112114
"--output-swift",

Plugins/BridgeJS/Sources/BridgeJSCore/BridgeJSConfig.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@ public struct BridgeJSConfig: Codable {
1010
/// If not present, the tool will be searched for in the system PATH.
1111
public var tools: [String: String]?
1212

13+
/// Whether to expose exported Swift APIs to the global namespace.
14+
///
15+
/// When `true`, exported functions, classes, and namespaces are available
16+
/// via `globalThis` in JavaScript. When `false`, they are only available
17+
/// through the exports object returned by `createExports()`.
18+
///
19+
/// Default: `false`
20+
public var exposeToGlobal: Bool
21+
22+
public init(tools: [String: String]? = nil, exposeToGlobal: Bool = false) {
23+
self.tools = tools
24+
self.exposeToGlobal = exposeToGlobal
25+
}
26+
27+
enum CodingKeys: String, CodingKey {
28+
case tools
29+
case exposeToGlobal
30+
}
31+
32+
public init(from decoder: Decoder) throws {
33+
let container = try decoder.container(keyedBy: CodingKeys.self)
34+
tools = try container.decodeIfPresent([String: String].self, forKey: .tools)
35+
exposeToGlobal = try container.decodeIfPresent(Bool.self, forKey: .exposeToGlobal) ?? false
36+
}
37+
1338
/// Load the configuration file from the SwiftPM package target directory.
1439
///
1540
/// Files are loaded **in this order** and merged (later files override earlier ones):
@@ -49,7 +74,8 @@ public struct BridgeJSConfig: Codable {
4974
/// Merge the current configuration with the overrides.
5075
func merging(overrides: BridgeJSConfig) -> BridgeJSConfig {
5176
return BridgeJSConfig(
52-
tools: (tools ?? [:]).merging(overrides.tools ?? [:], uniquingKeysWith: { $1 })
77+
tools: (tools ?? [:]).merging(overrides.tools ?? [:], uniquingKeysWith: { $1 }),
78+
exposeToGlobal: overrides.exposeToGlobal
5379
)
5480
}
5581
}

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import BridgeJSUtilities
2020
public class ExportSwift {
2121
let progress: ProgressReporting
2222
let moduleName: String
23-
23+
private let exposeToGlobal: Bool
2424
private var exportedFunctions: [ExportedFunction] = []
2525
private var exportedClasses: [ExportedClass] = []
2626
private var exportedEnums: [ExportedEnum] = []
@@ -30,9 +30,10 @@ public class ExportSwift {
3030
private let enumCodegen: EnumCodegen = EnumCodegen()
3131
private let closureCodegen = ClosureCodegen()
3232

33-
public init(progress: ProgressReporting, moduleName: String) {
33+
public init(progress: ProgressReporting, moduleName: String, exposeToGlobal: Bool) {
3434
self.progress = progress
3535
self.moduleName = moduleName
36+
self.exposeToGlobal = exposeToGlobal
3637
}
3738

3839
/// Processes a Swift source file to find declarations marked with @JS
@@ -55,6 +56,8 @@ public class ExportSwift {
5556

5657
/// Finalizes the export process and generates the bridge code
5758
///
59+
/// - Parameters:
60+
/// - exposeToGlobal: Whether to expose exported APIs to the global namespace (default: false)
5861
/// - Returns: A tuple containing the generated Swift code and a skeleton
5962
/// describing the exported APIs
6063
public func finalize() throws -> (outputSwift: String, outputSkeleton: ExportedSkeleton)? {
@@ -68,7 +71,8 @@ public class ExportSwift {
6871
functions: exportedFunctions,
6972
classes: exportedClasses,
7073
enums: exportedEnums,
71-
protocols: exportedProtocols
74+
protocols: exportedProtocols,
75+
exposeToGlobal: exposeToGlobal
7276
)
7377
)
7478
}
@@ -882,10 +886,18 @@ public class ExportSwift {
882886
message: "Enum visibility must be at least internal"
883887
)
884888

889+
let tsFullPath: String
890+
if let namespace = namespaceResult.namespace, !namespace.isEmpty {
891+
tsFullPath = namespace.joined(separator: ".") + "." + name
892+
} else {
893+
tsFullPath = name
894+
}
895+
885896
// Create enum directly in dictionary
886897
let exportedEnum = ExportedEnum(
887898
name: name,
888899
swiftCallName: swiftCallName,
900+
tsFullPath: tsFullPath,
889901
explicitAccessControl: explicitAccessControl,
890902
cases: [], // Will be populated in visit(EnumCaseDeclSyntax)
891903
rawType: SwiftEnumRawType(rawType),

0 commit comments

Comments
 (0)