Skip to content

Commit f2327ec

Browse files
Merge pull request #641 from swiftwasm/katei/be1a-playbridgejs-sho
2 parents 76e0362 + 312e715 commit f2327ec

File tree

8 files changed

+452
-171
lines changed

8 files changed

+452
-171
lines changed

Examples/PlayBridgeJS/Sources/JavaScript/app.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,19 +268,38 @@ export class BridgeJSPlayground {
268268

269269
try {
270270
this.hideError();
271+
this.editorSystem.clearDiagnostics();
271272

272273
const inputs = this.editorSystem.getInputs();
273274
const swiftCode = inputs.swift;
274275
const dtsCode = inputs.dts;
275276

276277
// Process the code and get PlayBridgeJSOutput
277-
const result = this.playBridgeJS.update(swiftCode, dtsCode);
278-
279-
// Update outputs using the PlayBridgeJSOutput object
280-
this.editorSystem.updateOutputs(result);
281-
282-
console.log('Code generated successfully');
278+
const result = this.playBridgeJS.updateDetailed(swiftCode, dtsCode);
279+
280+
const diagnostics = result.diagnostics;
281+
if (diagnostics && diagnostics.length > 0) {
282+
const mapped = diagnostics.map(d => ({
283+
file: d.file,
284+
startLineNumber: d.startLine,
285+
startColumn: d.startColumn,
286+
endLineNumber: d.endLine,
287+
endColumn: d.endColumn,
288+
message: d.message
289+
}));
290+
this.editorSystem.showDiagnostics(mapped);
291+
return;
292+
}
283293

294+
const output = result.output;
295+
if (output) {
296+
// Update outputs using the PlayBridgeJSOutput object
297+
this.editorSystem.updateOutputs(output);
298+
this.hideError();
299+
console.log('Code generated successfully');
300+
} else {
301+
this.showError('No output produced.');
302+
}
284303
} catch (error) {
285304
console.error('Error generating code:', error);
286305
this.showError('Error generating code: ' + error.message);

Examples/PlayBridgeJS/Sources/JavaScript/editor.js

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class EditorSystem {
4343
language: 'swift',
4444
placeholder: '// Import Swift Macros will appear here...',
4545
readOnly: true,
46-
modelUri: 'BridgeJS.Macros.swift'
46+
modelUri: 'Playground.Macros.swift'
4747
},
4848
{
4949
key: 'swift-glue',
@@ -206,10 +206,10 @@ export class EditorSystem {
206206

207207
updateOutputs(result) {
208208
const outputMap = {
209-
'swift-glue': () => result.swiftGlue(),
210-
'swift-import-macros': () => result.importSwiftMacroDecls(),
211-
'js-generated': () => result.outputJs(),
212-
'dts-generated': () => result.outputDts()
209+
'swift-glue': () => result.swiftGlue,
210+
'swift-import-macros': () => result.importSwiftMacroDecls,
211+
'js-generated': () => result.outputJs,
212+
'dts-generated': () => result.outputDts
213213
};
214214

215215
Object.entries(outputMap).forEach(([key, getContent]) => {
@@ -230,6 +230,63 @@ export class EditorSystem {
230230
});
231231
}
232232

233+
clearDiagnostics() {
234+
// Remove all diagnostics owned by the playground.
235+
this.editors.forEach(editor => {
236+
const model = editor.getModel();
237+
if (!model || typeof monaco === 'undefined') return;
238+
monaco.editor.setModelMarkers(model, 'bridgejs', []);
239+
});
240+
}
241+
242+
/**
243+
* @param {{file: string, startLineNumber: number, startColumn: number, endLineNumber?: number, endColumn?: number, message: string}[]} diagnostics
244+
*/
245+
showDiagnostics(diagnostics) {
246+
if (typeof monaco === 'undefined') return;
247+
248+
// Group diagnostics per model so we can set markers in batches.
249+
const markersByModel = new Map();
250+
251+
diagnostics.forEach(diag => {
252+
const model = this.findModelForFile(diag.file);
253+
if (!model) return;
254+
255+
const markers = markersByModel.get(model) ?? [];
256+
const lineLength = model.getLineMaxColumn(diag.startLineNumber);
257+
const endLine = diag.endLineNumber ?? diag.startLineNumber;
258+
const endColumn = Math.min(lineLength, diag.endColumn ?? diag.startColumn + 1);
259+
260+
markers.push({
261+
severity: monaco.MarkerSeverity.Error,
262+
message: diag.message,
263+
startLineNumber: diag.startLineNumber,
264+
startColumn: diag.startColumn,
265+
endLineNumber: endLine,
266+
endColumn
267+
});
268+
269+
markersByModel.set(model, markers);
270+
});
271+
272+
markersByModel.forEach((markers, model) => {
273+
monaco.editor.setModelMarkers(model, 'bridgejs', markers);
274+
});
275+
}
276+
277+
findModelForFile(fileName) {
278+
const normalized = fileName.startsWith('/') ? fileName.slice(1) : fileName;
279+
for (const editor of this.editors.values()) {
280+
const model = editor.getModel();
281+
if (!model) continue;
282+
const uriPath = model.uri.path.startsWith('/') ? model.uri.path.slice(1) : model.uri.path;
283+
if (uriPath === normalized || uriPath.endsWith('/' + normalized)) {
284+
return model;
285+
}
286+
}
287+
return null;
288+
}
289+
233290
// Utility methods
234291
getConfigByKey(key) {
235292
return [...this.config.input, ...this.config.output].find(c => c.key === key);

Examples/PlayBridgeJS/Sources/PlayBridgeJS/Generated/BridgeJS.swift

Lines changed: 152 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,153 @@
77

88
@_spi(BridgeJS) import JavaScriptKit
99

10+
extension PlayBridgeJSOutput: _BridgedSwiftStruct {
11+
@_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PlayBridgeJSOutput {
12+
let swiftGlue = String.bridgeJSStackPop()
13+
let importSwiftMacroDecls = String.bridgeJSStackPop()
14+
let outputDts = String.bridgeJSStackPop()
15+
let outputJs = String.bridgeJSStackPop()
16+
return PlayBridgeJSOutput(outputJs: outputJs, outputDts: outputDts, importSwiftMacroDecls: importSwiftMacroDecls, swiftGlue: swiftGlue)
17+
}
18+
19+
@_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() {
20+
self.outputJs.bridgeJSStackPush()
21+
self.outputDts.bridgeJSStackPush()
22+
self.importSwiftMacroDecls.bridgeJSStackPush()
23+
self.swiftGlue.bridgeJSStackPush()
24+
}
25+
26+
init(unsafelyCopying jsObject: JSObject) {
27+
let __bjs_cleanupId = _bjs_struct_lower_PlayBridgeJSOutput(jsObject.bridgeJSLowerParameter())
28+
defer {
29+
_swift_js_struct_cleanup(__bjs_cleanupId)
30+
}
31+
self = Self.bridgeJSStackPop()
32+
}
33+
34+
func toJSObject() -> JSObject {
35+
let __bjs_self = self
36+
__bjs_self.bridgeJSStackPush()
37+
return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_PlayBridgeJSOutput()))
38+
}
39+
}
40+
41+
#if arch(wasm32)
42+
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_PlayBridgeJSOutput")
43+
fileprivate func _bjs_struct_lower_PlayBridgeJSOutput(_ objectId: Int32) -> Int32
44+
#else
45+
fileprivate func _bjs_struct_lower_PlayBridgeJSOutput(_ objectId: Int32) -> Int32 {
46+
fatalError("Only available on WebAssembly")
47+
}
48+
#endif
49+
50+
#if arch(wasm32)
51+
@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_PlayBridgeJSOutput")
52+
fileprivate func _bjs_struct_lift_PlayBridgeJSOutput() -> Int32
53+
#else
54+
fileprivate func _bjs_struct_lift_PlayBridgeJSOutput() -> Int32 {
55+
fatalError("Only available on WebAssembly")
56+
}
57+
#endif
58+
59+
extension PlayBridgeJSDiagnostic: _BridgedSwiftStruct {
60+
@_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PlayBridgeJSDiagnostic {
61+
let endColumn = Int.bridgeJSStackPop()
62+
let endLine = Int.bridgeJSStackPop()
63+
let startColumn = Int.bridgeJSStackPop()
64+
let startLine = Int.bridgeJSStackPop()
65+
let message = String.bridgeJSStackPop()
66+
let file = String.bridgeJSStackPop()
67+
return PlayBridgeJSDiagnostic(file: file, message: message, startLine: startLine, startColumn: startColumn, endLine: endLine, endColumn: endColumn)
68+
}
69+
70+
@_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() {
71+
self.file.bridgeJSStackPush()
72+
self.message.bridgeJSStackPush()
73+
self.startLine.bridgeJSStackPush()
74+
self.startColumn.bridgeJSStackPush()
75+
self.endLine.bridgeJSStackPush()
76+
self.endColumn.bridgeJSStackPush()
77+
}
78+
79+
init(unsafelyCopying jsObject: JSObject) {
80+
let __bjs_cleanupId = _bjs_struct_lower_PlayBridgeJSDiagnostic(jsObject.bridgeJSLowerParameter())
81+
defer {
82+
_swift_js_struct_cleanup(__bjs_cleanupId)
83+
}
84+
self = Self.bridgeJSStackPop()
85+
}
86+
87+
func toJSObject() -> JSObject {
88+
let __bjs_self = self
89+
__bjs_self.bridgeJSStackPush()
90+
return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_PlayBridgeJSDiagnostic()))
91+
}
92+
}
93+
94+
#if arch(wasm32)
95+
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_PlayBridgeJSDiagnostic")
96+
fileprivate func _bjs_struct_lower_PlayBridgeJSDiagnostic(_ objectId: Int32) -> Int32
97+
#else
98+
fileprivate func _bjs_struct_lower_PlayBridgeJSDiagnostic(_ objectId: Int32) -> Int32 {
99+
fatalError("Only available on WebAssembly")
100+
}
101+
#endif
102+
103+
#if arch(wasm32)
104+
@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_PlayBridgeJSDiagnostic")
105+
fileprivate func _bjs_struct_lift_PlayBridgeJSDiagnostic() -> Int32
106+
#else
107+
fileprivate func _bjs_struct_lift_PlayBridgeJSDiagnostic() -> Int32 {
108+
fatalError("Only available on WebAssembly")
109+
}
110+
#endif
111+
112+
extension PlayBridgeJSResult: _BridgedSwiftStruct {
113+
@_spi(BridgeJS) @_transparent public static func bridgeJSStackPop() -> PlayBridgeJSResult {
114+
let diagnostics = [PlayBridgeJSDiagnostic].bridgeJSStackPop()
115+
let output = Optional<PlayBridgeJSOutput>.bridgeJSStackPop()
116+
return PlayBridgeJSResult(output: output, diagnostics: diagnostics)
117+
}
118+
119+
@_spi(BridgeJS) @_transparent public consuming func bridgeJSStackPush() {
120+
self.output.bridgeJSStackPush()
121+
self.diagnostics.bridgeJSStackPush()
122+
}
123+
124+
init(unsafelyCopying jsObject: JSObject) {
125+
let __bjs_cleanupId = _bjs_struct_lower_PlayBridgeJSResult(jsObject.bridgeJSLowerParameter())
126+
defer {
127+
_swift_js_struct_cleanup(__bjs_cleanupId)
128+
}
129+
self = Self.bridgeJSStackPop()
130+
}
131+
132+
func toJSObject() -> JSObject {
133+
let __bjs_self = self
134+
__bjs_self.bridgeJSStackPush()
135+
return JSObject(id: UInt32(bitPattern: _bjs_struct_lift_PlayBridgeJSResult()))
136+
}
137+
}
138+
139+
#if arch(wasm32)
140+
@_extern(wasm, module: "bjs", name: "swift_js_struct_lower_PlayBridgeJSResult")
141+
fileprivate func _bjs_struct_lower_PlayBridgeJSResult(_ objectId: Int32) -> Int32
142+
#else
143+
fileprivate func _bjs_struct_lower_PlayBridgeJSResult(_ objectId: Int32) -> Int32 {
144+
fatalError("Only available on WebAssembly")
145+
}
146+
#endif
147+
148+
#if arch(wasm32)
149+
@_extern(wasm, module: "bjs", name: "swift_js_struct_lift_PlayBridgeJSResult")
150+
fileprivate func _bjs_struct_lift_PlayBridgeJSResult() -> Int32
151+
#else
152+
fileprivate func _bjs_struct_lift_PlayBridgeJSResult() -> Int32 {
153+
fatalError("Only available on WebAssembly")
154+
}
155+
#endif
156+
10157
@_expose(wasm, "bjs_PlayBridgeJS_init")
11158
@_cdecl("bjs_PlayBridgeJS_init")
12159
public func _bjs_PlayBridgeJS_init() -> UnsafeMutableRawPointer {
@@ -18,12 +165,12 @@ public func _bjs_PlayBridgeJS_init() -> UnsafeMutableRawPointer {
18165
#endif
19166
}
20167

21-
@_expose(wasm, "bjs_PlayBridgeJS_update")
22-
@_cdecl("bjs_PlayBridgeJS_update")
23-
public func _bjs_PlayBridgeJS_update(_ _self: UnsafeMutableRawPointer, _ swiftSourceBytes: Int32, _ swiftSourceLength: Int32, _ dtsSourceBytes: Int32, _ dtsSourceLength: Int32) -> UnsafeMutableRawPointer {
168+
@_expose(wasm, "bjs_PlayBridgeJS_updateDetailed")
169+
@_cdecl("bjs_PlayBridgeJS_updateDetailed")
170+
public func _bjs_PlayBridgeJS_updateDetailed(_ _self: UnsafeMutableRawPointer, _ swiftSourceBytes: Int32, _ swiftSourceLength: Int32, _ dtsSourceBytes: Int32, _ dtsSourceLength: Int32) -> Void {
24171
#if arch(wasm32)
25172
do {
26-
let ret = try PlayBridgeJS.bridgeJSLiftParameter(_self).update(swiftSource: String.bridgeJSLiftParameter(swiftSourceBytes, swiftSourceLength), dtsSource: String.bridgeJSLiftParameter(dtsSourceBytes, dtsSourceLength))
173+
let ret = try PlayBridgeJS.bridgeJSLiftParameter(_self).updateDetailed(swiftSource: String.bridgeJSLiftParameter(swiftSourceBytes, swiftSourceLength), dtsSource: String.bridgeJSLiftParameter(dtsSourceBytes, dtsSourceLength))
27174
return ret.bridgeJSLowerReturn()
28175
} catch let error {
29176
if let error = error.thrownValue.object {
@@ -36,7 +183,7 @@ public func _bjs_PlayBridgeJS_update(_ _self: UnsafeMutableRawPointer, _ swiftSo
36183
_swift_js_throw(Int32(bitPattern: $0.id))
37184
}
38185
}
39-
return UnsafeMutableRawPointer(bitPattern: -1).unsafelyUnwrapped
186+
return
40187
}
41188
#else
42189
fatalError("Only available on WebAssembly")
@@ -68,75 +215,6 @@ fileprivate func _bjs_PlayBridgeJS_wrap(_ pointer: UnsafeMutableRawPointer) -> I
68215
}
69216
#endif
70217

71-
@_expose(wasm, "bjs_PlayBridgeJSOutput_outputJs")
72-
@_cdecl("bjs_PlayBridgeJSOutput_outputJs")
73-
public func _bjs_PlayBridgeJSOutput_outputJs(_ _self: UnsafeMutableRawPointer) -> Void {
74-
#if arch(wasm32)
75-
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).outputJs()
76-
return ret.bridgeJSLowerReturn()
77-
#else
78-
fatalError("Only available on WebAssembly")
79-
#endif
80-
}
81-
82-
@_expose(wasm, "bjs_PlayBridgeJSOutput_outputDts")
83-
@_cdecl("bjs_PlayBridgeJSOutput_outputDts")
84-
public func _bjs_PlayBridgeJSOutput_outputDts(_ _self: UnsafeMutableRawPointer) -> Void {
85-
#if arch(wasm32)
86-
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).outputDts()
87-
return ret.bridgeJSLowerReturn()
88-
#else
89-
fatalError("Only available on WebAssembly")
90-
#endif
91-
}
92-
93-
@_expose(wasm, "bjs_PlayBridgeJSOutput_importSwiftMacroDecls")
94-
@_cdecl("bjs_PlayBridgeJSOutput_importSwiftMacroDecls")
95-
public func _bjs_PlayBridgeJSOutput_importSwiftMacroDecls(_ _self: UnsafeMutableRawPointer) -> Void {
96-
#if arch(wasm32)
97-
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).importSwiftMacroDecls()
98-
return ret.bridgeJSLowerReturn()
99-
#else
100-
fatalError("Only available on WebAssembly")
101-
#endif
102-
}
103-
104-
@_expose(wasm, "bjs_PlayBridgeJSOutput_swiftGlue")
105-
@_cdecl("bjs_PlayBridgeJSOutput_swiftGlue")
106-
public func _bjs_PlayBridgeJSOutput_swiftGlue(_ _self: UnsafeMutableRawPointer) -> Void {
107-
#if arch(wasm32)
108-
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).swiftGlue()
109-
return ret.bridgeJSLowerReturn()
110-
#else
111-
fatalError("Only available on WebAssembly")
112-
#endif
113-
}
114-
115-
@_expose(wasm, "bjs_PlayBridgeJSOutput_deinit")
116-
@_cdecl("bjs_PlayBridgeJSOutput_deinit")
117-
public func _bjs_PlayBridgeJSOutput_deinit(_ pointer: UnsafeMutableRawPointer) -> Void {
118-
#if arch(wasm32)
119-
Unmanaged<PlayBridgeJSOutput>.fromOpaque(pointer).release()
120-
#else
121-
fatalError("Only available on WebAssembly")
122-
#endif
123-
}
124-
125-
extension PlayBridgeJSOutput: ConvertibleToJSValue, _BridgedSwiftHeapObject {
126-
var jsValue: JSValue {
127-
return .object(JSObject(id: UInt32(bitPattern: _bjs_PlayBridgeJSOutput_wrap(Unmanaged.passRetained(self).toOpaque()))))
128-
}
129-
}
130-
131-
#if arch(wasm32)
132-
@_extern(wasm, module: "PlayBridgeJS", name: "bjs_PlayBridgeJSOutput_wrap")
133-
fileprivate func _bjs_PlayBridgeJSOutput_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32
134-
#else
135-
fileprivate func _bjs_PlayBridgeJSOutput_wrap(_ pointer: UnsafeMutableRawPointer) -> Int32 {
136-
fatalError("Only available on WebAssembly")
137-
}
138-
#endif
139-
140218
#if arch(wasm32)
141219
@_extern(wasm, module: "PlayBridgeJS", name: "bjs_createTS2Swift")
142220
fileprivate func bjs_createTS2Swift() -> Int32

0 commit comments

Comments
 (0)