Skip to content

Commit 72ff3c7

Browse files
committed
BridgeJS: Global namespace configuration and tests
1 parent b53ec16 commit 72ff3c7

File tree

67 files changed

+2863
-415
lines changed

Some content is hidden

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

67 files changed

+2863
-415
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: 2 additions & 3 deletions
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()
@@ -40,8 +40,7 @@ import class Foundation.JSONDecoder
4040
children: [importSkeleton]
4141
)
4242
],
43-
sharedMemory: false,
44-
exposeToGlobal: true
43+
sharedMemory: false
4544
)
4645
let linked = try linker.link()
4746

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ unittest:
1111
--disable-sandbox \
1212
js test --prelude ./Tests/prelude.mjs -Xnode --expose-gc
1313

14+
.PHONY: unittest-with-global
15+
unittest-with-global:
16+
cp Tests/BridgeJSRuntimeTests/bridge-js.config.exposeToGlobal.json Tests/BridgeJSRuntimeTests/bridge-js.config.local.json
17+
swift package --allow-writing-to-directory Tests/BridgeJSRuntimeTests \
18+
bridge-js --package-path Tests/BridgeJSRuntimeTests
19+
rm -f Tests/BridgeJSRuntimeTests/bridge-js.config.local.json
20+
env JAVASCRIPTKIT_EXPERIMENTAL_BRIDGEJS=1 swift package --swift-sdk "$(SWIFT_SDK_ID)" \
21+
--disable-sandbox \
22+
js test --prelude ./Tests/prelude.exposeToGlobal.mjs -Xnode --expose-gc
23+
1424
.PHONY: regenerate_swiftpm_resources
1525
regenerate_swiftpm_resources:
1626
npm run build

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: 7 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
}

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,26 @@ struct BridgeJSLink {
1212
var exportedSkeletons: [ExportedSkeleton] = []
1313
var importedSkeletons: [ImportedModuleSkeleton] = []
1414
let sharedMemory: Bool
15-
let exposeToGlobal: Bool
15+
var exposeToGlobal: Bool
1616
private let namespaceBuilder = NamespaceBuilder()
1717

1818
init(
1919
exportedSkeletons: [ExportedSkeleton] = [],
2020
importedSkeletons: [ImportedModuleSkeleton] = [],
21-
sharedMemory: Bool,
22-
exposeToGlobal: Bool = true
21+
sharedMemory: Bool
2322
) {
2423
self.exportedSkeletons = exportedSkeletons
2524
self.importedSkeletons = importedSkeletons
2625
self.sharedMemory = sharedMemory
27-
self.exposeToGlobal = exposeToGlobal
26+
self.exposeToGlobal = exportedSkeletons.contains { $0.exposeToGlobal }
2827
}
2928

3029
mutating func addExportedSkeletonFile(data: Data) throws {
3130
let skeleton = try JSONDecoder().decode(ExportedSkeleton.self, from: data)
3231
exportedSkeletons.append(skeleton)
32+
if skeleton.exposeToGlobal {
33+
exposeToGlobal = true
34+
}
3335
}
3436

3537
mutating func addImportedSkeletonFile(data: Data) throws {
@@ -80,7 +82,7 @@ struct BridgeJSLink {
8082
var enumStaticAssignments: [String] = []
8183
}
8284

83-
private func collectLinkData(exposeToGlobal: Bool) throws -> LinkData {
85+
private func collectLinkData() throws -> LinkData {
8486
var data = LinkData()
8587

8688
// Swift heap object class definitions
@@ -1079,11 +1081,11 @@ struct BridgeJSLink {
10791081
)
10801082
printer.write(lines: namespaceInitCode)
10811083

1082-
let propertyAssignments = try generateNamespacePropertyAssignments(
1083-
data: data,
1084-
exportedSkeletons: exportedSkeletons,
1085-
namespaceBuilder: namespaceBuilder,
1086-
exposeToGlobal: exposeToGlobal
1084+
let propertyAssignments = try generateNamespacePropertyAssignments(
1085+
data: data,
1086+
exportedSkeletons: exportedSkeletons,
1087+
namespaceBuilder: namespaceBuilder,
1088+
exposeToGlobal: exposeToGlobal
10871089
)
10881090
printer.write(lines: propertyAssignments)
10891091
}
@@ -1097,7 +1099,7 @@ struct BridgeJSLink {
10971099
}
10981100

10991101
func link() throws -> (outputJs: String, outputDts: String) {
1100-
let data = try collectLinkData(exposeToGlobal: exposeToGlobal)
1102+
let data = try collectLinkData()
11011103
let outputJs = try generateJavaScript(data: data)
11021104
let outputDts = generateTypeScript(data: data)
11031105
return (outputJs, outputDts)
@@ -1160,7 +1162,6 @@ struct BridgeJSLink {
11601162
) throws -> [String] {
11611163
let printer = CodeFragmentPrinter()
11621164

1163-
// Only write globalThis property assignments when exposeToGlobal is true
11641165
if exposeToGlobal {
11651166
printer.write(lines: data.enumStaticAssignments)
11661167
}
@@ -1171,7 +1172,6 @@ struct BridgeJSLink {
11711172

11721173
let hierarchicalLines = try namespaceBuilder.buildHierarchicalExportsObject(
11731174
exportedSkeletons: exportedSkeletons,
1174-
exposeToGlobal: exposeToGlobal,
11751175
renderFunctionImpl: { function in
11761176
let (js, _) = try self.renderExportedFunction(function: function)
11771177
return js
@@ -2478,7 +2478,6 @@ extension BridgeJSLink {
24782478

24792479
fileprivate func buildHierarchicalExportsObject(
24802480
exportedSkeletons: [ExportedSkeleton],
2481-
exposeToGlobal: Bool,
24822481
renderFunctionImpl: (ExportedFunction) throws -> [String]
24832482
) throws -> [String] {
24842483
let printer = CodeFragmentPrinter()
@@ -2698,7 +2697,7 @@ extension BridgeJSLink {
26982697
guard hasContent(node: childNode) else {
26992698
continue
27002699
}
2701-
2700+
27022701
let exportKeyword = exposeToGlobal ? "" : "export "
27032702
printer.write("\(exportKeyword)namespace \(childName) {")
27042703
printer.indent()

Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,19 +499,27 @@ public struct ExportedSkeleton: Codable {
499499
public let classes: [ExportedClass]
500500
public let enums: [ExportedEnum]
501501
public let protocols: [ExportedProtocol]
502+
/// Whether to expose exported APIs to the global namespace.
503+
///
504+
/// When `true`, exported functions, classes, and namespaces are available
505+
/// via `globalThis` in JavaScript. When `false`, they are only available
506+
/// through the exports object.
507+
public var exposeToGlobal: Bool
502508

503509
public init(
504510
moduleName: String,
505511
functions: [ExportedFunction],
506512
classes: [ExportedClass],
507513
enums: [ExportedEnum],
508-
protocols: [ExportedProtocol] = []
514+
protocols: [ExportedProtocol] = [],
515+
exposeToGlobal: Bool
509516
) {
510517
self.moduleName = moduleName
511518
self.functions = functions
512519
self.classes = classes
513520
self.enums = enums
514521
self.protocols = protocols
522+
self.exposeToGlobal = exposeToGlobal
515523
}
516524
}
517525

0 commit comments

Comments
 (0)