Skip to content

Commit 5431c5e

Browse files
committed
feat: update documentation for newly added macro, code cleanup (+1 squashed commit)
Squashed commits: [70b015d] feat: namespace tests for functions, code cleanup
1 parent a6915eb commit 5431c5e

File tree

8 files changed

+267
-115
lines changed

8 files changed

+267
-115
lines changed

Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class ExportSwift {
127127
return nil
128128
}
129129

130-
let (baseName, namespace) = extractNameAndNamespace(from: node, jsAttribute: jsAttribute)
130+
let (name, namespace) = extractNameAndNamespace(from: node, jsAttribute: jsAttribute)
131131

132132
var parameters: [Parameter] = []
133133
for param in node.signature.parameterClause.parameters {
@@ -153,17 +153,17 @@ class ExportSwift {
153153
let abiName: String
154154
switch state {
155155
case .topLevel:
156-
abiName = "bjs_\(baseName)"
156+
abiName = "bjs_\(name)"
157157
case .classBody(let className):
158-
abiName = "bjs_\(className)_\(baseName)"
158+
abiName = "bjs_\(className)_\(name)"
159159
}
160160

161161
guard let effects = collectEffects(signature: node.signature) else {
162162
return nil
163163
}
164164

165165
return ExportedFunction(
166-
name: baseName,
166+
name: name,
167167
abiName: abiName,
168168
parameters: parameters,
169169
returnType: returnType,
@@ -243,7 +243,7 @@ class ExportSwift {
243243
let name = node.name.text
244244
stateStack.push(state: .classBody(name: name))
245245

246-
guard let jsAttribute = node.attributes.firstJSAttribute else { return .skipChildren }
246+
guard node.attributes.hasJSAttribute() else { return .skipChildren }
247247

248248
exportedClassByName[name] = ExportedClass(
249249
name: name,

Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift

Lines changed: 47 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ struct BridgeJSLink {
9696
js[0] = "\(function.name): " + js[0]
9797
js[js.count - 1] += ","
9898
exportsLines.append(contentsOf: js)
99-
10099
dtsExportLines.append(contentsOf: dts)
101100
}
102101
}
@@ -119,8 +118,8 @@ struct BridgeJSLink {
119118

120119
let exportsSection: String
121120
if hasNamespacedFunctions {
122-
let setupLines = renderGlobalNamespace(namespacedFunctions: namespacedFunctions)
123-
let namespaceSetupCode = setupLines.map { $0.indent(count: 12) }.joined(separator: "\n")
121+
let namespaceSetupCode = renderGlobalNamespace(namespacedFunctions: namespacedFunctions)
122+
.map { $0.indent(count: 12) }.joined(separator: "\n")
124123
exportsSection = """
125124
\(classLines.map { $0.indent(count: 12) }.joined(separator: "\n"))
126125
const exports = {
@@ -203,12 +202,41 @@ struct BridgeJSLink {
203202
/** @param {WebAssembly.Instance} instance */
204203
createExports: (instance) => {
205204
const js = swift.memory.heap;
206-
\(exportsSection)
205+
\(exportsSection)
207206
}
208207
}
209208
"""
210-
211-
// Collect namespace declarations for TypeScript
209+
210+
var dtsLines: [String] = []
211+
dtsLines.append(contentsOf: namespaceDeclarations())
212+
dtsLines.append(contentsOf: dtsClassLines)
213+
dtsLines.append("export type Exports = {")
214+
dtsLines.append(contentsOf: dtsExportLines.map { $0.indent(count: 4) })
215+
dtsLines.append("}")
216+
dtsLines.append("export type Imports = {")
217+
dtsLines.append(contentsOf: importObjectBuilders.flatMap { $0.dtsImportLines }.map { $0.indent(count: 4) })
218+
dtsLines.append("}")
219+
let outputDts = """
220+
// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
221+
// DO NOT EDIT.
222+
//
223+
// To update this file, just rebuild your project or run
224+
// `swift package bridge-js`.
225+
226+
\(dtsLines.joined(separator: "\n"))
227+
export function createInstantiator(options: {
228+
imports: Imports;
229+
}, swift: any): Promise<{
230+
addImports: (importObject: WebAssembly.Imports) => void;
231+
setInstance: (instance: WebAssembly.Instance) => void;
232+
createExports: (instance: WebAssembly.Instance) => Exports;
233+
}>;
234+
"""
235+
return (outputJs, outputDts)
236+
}
237+
238+
private func namespaceDeclarations() -> [String] {
239+
var dtsLines: [String] = []
212240
var namespaceDeclarations: [String: [(name: String, parameters: [Parameter], returnType: BridgeType)]] = [:]
213241

214242
for skeleton in exportedSkeletons {
@@ -223,71 +251,34 @@ struct BridgeJSLink {
223251
}
224252
}
225253

226-
// Generate namespace declarations in TypeScript
227-
var dtsLines: [String] = []
254+
guard !namespaceDeclarations.isEmpty else { return dtsLines }
228255

229-
// Only add export {} and declare global block if we have namespace declarations
230-
let hasNamespaceDeclarations = !namespaceDeclarations.isEmpty
256+
dtsLines.append("export {};")
257+
dtsLines.append("")
258+
dtsLines.append("declare global {")
231259

232-
if hasNamespaceDeclarations {
233-
dtsLines.append("export {};")
234-
dtsLines.append("")
235-
dtsLines.append("declare global {")
236-
}
237-
238-
// Generate namespace structure using nested declarations
260+
let identBaseSize = 4
239261
for (namespacePath, functions) in namespaceDeclarations.sorted(by: { $0.key < $1.key }) {
240262
let parts = namespacePath.split(separator: ".").map(String.init)
241263

242-
// Open namespaces with proper indentation
243264
for i in 0..<parts.count {
244-
dtsLines.append("namespace \(parts[i]) {".indent(count: 4*(hasNamespaceDeclarations ? i + 1: 1)) )
265+
dtsLines.append("namespace \(parts[i]) {".indent(count: identBaseSize*(i + 1)) )
245266
}
246267

247-
// Add function signatures with proper indentation
248-
let functionIndentationLevel = hasNamespaceDeclarations ? parts.count + 1 : parts.count
249268
for (name, parameters, returnType) in functions {
250269
let signature = "function \(name)\(renderTSSignature(parameters: parameters, returnType: returnType));"
251-
dtsLines.append("\(signature)".indent(count: 4*functionIndentationLevel))
270+
dtsLines.append("\(signature)".indent(count: identBaseSize*(parts.count + 1)))
252271
}
253272

254-
// Close namespaces with proper indentation (in reverse order)
255273
for i in (0..<parts.count).reversed() {
256-
let indentationLevel = hasNamespaceDeclarations ? i + 1 : i
257-
dtsLines.append("}".indent(count: 4*indentationLevel))
274+
dtsLines.append("}".indent(count: identBaseSize*(i+1)))
258275
}
259276
}
260277

261-
if hasNamespaceDeclarations {
262-
dtsLines.append("}")
263-
dtsLines.append("")
264-
}
265-
266-
// Add remaining class lines
267-
dtsLines.append(contentsOf: dtsClassLines)
268-
dtsLines.append("export type Exports = {")
269-
dtsLines.append(contentsOf: dtsExportLines.map { $0.indent(count: 4) })
270-
dtsLines.append("}")
271-
dtsLines.append("export type Imports = {")
272-
dtsLines.append(contentsOf: importObjectBuilders.flatMap { $0.dtsImportLines }.map { $0.indent(count: 4) })
273278
dtsLines.append("}")
274-
let outputDts = """
275-
// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
276-
// DO NOT EDIT.
277-
//
278-
// To update this file, just rebuild your project or run
279-
// `swift package bridge-js`.
280-
281-
\(dtsLines.joined(separator: "\n"))
282-
export function createInstantiator(options: {
283-
imports: Imports;
284-
}, swift: any): Promise<{
285-
addImports: (importObject: WebAssembly.Imports) => void;
286-
setInstance: (instance: WebAssembly.Instance) => void;
287-
createExports: (instance: WebAssembly.Instance) => Exports;
288-
}>;
289-
"""
290-
return (outputJs, outputDts)
279+
dtsLines.append("")
280+
281+
return dtsLines
291282
}
292283

293284
class ExportedThunkBuilder {
@@ -482,20 +473,11 @@ struct BridgeJSLink {
482473
return (jsLines, dtsTypeLines, dtsExportEntryLines)
483474
}
484475

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-
494476
func renderGlobalNamespace(namespacedFunctions: [ExportedFunction]) -> [String] {
495477
var lines: [String] = []
496478
var uniqueNamespaces: [String] = []
497479

498-
var namespacePaths: Set<[String]> = Set(namespacedFunctions
480+
let namespacePaths: Set<[String]> = Set(namespacedFunctions
499481
.compactMap { $0.namespace })
500482

501483
namespacePaths.forEach { namespacePath in
@@ -507,7 +489,7 @@ struct BridgeJSLink {
507489
}
508490
}
509491

510-
uniqueNamespaces.map { namespace in
492+
uniqueNamespaces.forEach { namespace in
511493
lines.append("if (typeof globalThis.\(namespace) === 'undefined') {")
512494
lines.append(" globalThis.\(namespace) = {};")
513495
lines.append("}")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@JS("__Swift.Foundation.UUID") func create() -> String { UUID().uuidString }
2+
@JS("__Swift.Foundation.UUID") func validate(uuid: String) -> Bool { true }
3+
@JS func plainFunction() -> String { "plain" }
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// NOTICE: This is auto-generated code by BridgeJS from JavaScriptKit,
2+
// DO NOT EDIT.
3+
//
4+
// To update this file, just rebuild your project or run
5+
// `swift package bridge-js`.
6+
7+
export {};
8+
9+
declare global {
10+
namespace __Swift {
11+
namespace Foundation {
12+
namespace UUID {
13+
function create(): string;
14+
function validate(uuid: string): boolean;
15+
}
16+
}
17+
}
18+
}
19+
20+
export type Exports = {
21+
create(): string;
22+
validate(uuid: string): boolean;
23+
plainFunction(): string;
24+
}
25+
export type Imports = {
26+
}
27+
export function createInstantiator(options: {
28+
imports: Imports;
29+
}, swift: any): Promise<{
30+
addImports: (importObject: WebAssembly.Imports) => void;
31+
setInstance: (instance: WebAssembly.Instance) => void;
32+
createExports: (instance: WebAssembly.Instance) => Exports;
33+
}>;
Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -46,34 +46,7 @@ export async function createInstantiator(options, swift) {
4646
bjs["swift_js_release"] = function(id) {
4747
swift.memory.release(id);
4848
}
49-
const TestModule = importObject["TestModule"] = {};
50-
TestModule["bjs_returnAnimatable"] = function bjs_returnAnimatable() {
51-
try {
52-
let ret = options.imports.returnAnimatable();
53-
return swift.memory.retain(ret);
54-
} catch (error) {
55-
setException(error);
56-
return 0
57-
}
58-
}
59-
TestModule["bjs_Animatable_animate"] = function bjs_Animatable_animate(self, keyframes, options) {
60-
try {
61-
let ret = swift.memory.getObject(self).animate(swift.memory.getObject(keyframes), swift.memory.getObject(options));
62-
return swift.memory.retain(ret);
63-
} catch (error) {
64-
setException(error);
65-
return 0
66-
}
67-
}
68-
TestModule["bjs_Animatable_getAnimations"] = function bjs_Animatable_getAnimations(self, options) {
69-
try {
70-
let ret = swift.memory.getObject(self).getAnimations(swift.memory.getObject(options));
71-
return swift.memory.retain(ret);
72-
} catch (error) {
73-
setException(error);
74-
return 0
75-
}
76-
}
49+
7750
},
7851
setInstance: (i) => {
7952
instance = i;
@@ -85,10 +58,42 @@ export async function createInstantiator(options, swift) {
8558
/** @param {WebAssembly.Instance} instance */
8659
createExports: (instance) => {
8760
const js = swift.memory.heap;
88-
89-
return {
9061

62+
const exports = {
63+
create: function bjs_create() {
64+
instance.exports.bjs_create();
65+
const ret = tmpRetString;
66+
tmpRetString = undefined;
67+
return ret;
68+
},
69+
validate: function bjs_validate(uuid) {
70+
const uuidBytes = textEncoder.encode(uuid);
71+
const uuidId = swift.memory.retain(uuidBytes);
72+
const ret = instance.exports.bjs_validate(uuidId, uuidBytes.length) !== 0;
73+
swift.memory.release(uuidId);
74+
return ret;
75+
},
76+
plainFunction: function bjs_plainFunction() {
77+
instance.exports.bjs_plainFunction();
78+
const ret = tmpRetString;
79+
tmpRetString = undefined;
80+
return ret;
81+
},
9182
};
83+
84+
if (typeof globalThis.__Swift === 'undefined') {
85+
globalThis.__Swift = {};
86+
}
87+
if (typeof globalThis.__Swift.Foundation === 'undefined') {
88+
globalThis.__Swift.Foundation = {};
89+
}
90+
if (typeof globalThis.__Swift.Foundation.UUID === 'undefined') {
91+
globalThis.__Swift.Foundation.UUID = {};
92+
}
93+
globalThis.__Swift.Foundation.UUID.create = exports.create;
94+
globalThis.__Swift.Foundation.UUID.validate = exports.validate;
95+
96+
return exports;
9297
},
9398
}
9499
}

0 commit comments

Comments
 (0)