Skip to content

Commit 1b802c8

Browse files
Merge pull request #388 from swiftwasm/yt/bridge-js-play
Add BridgeJS playground
2 parents 81bafa7 + 1702e73 commit 1b802c8

Some content is hidden

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

53 files changed

+1500
-140
lines changed

.github/workflows/test.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,36 @@ jobs:
8888
echo "::error::The formatting changed some files. Please run \`./Utilities/format.swift\` and commit the changes."
8989
exit 1
9090
}
91+
build-examples:
92+
runs-on: ubuntu-latest
93+
steps:
94+
- uses: actions/checkout@v4
95+
- uses: ./.github/actions/install-swift
96+
with:
97+
download-url: https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2025-06-12-a/swift-DEVELOPMENT-SNAPSHOT-2025-06-12-a-ubuntu22.04.tar.gz
98+
- uses: swiftwasm/setup-swiftwasm@v2
99+
id: setup-wasm32-unknown-wasi
100+
with: { target: wasm32-unknown-wasi }
101+
- uses: swiftwasm/setup-swiftwasm@v2
102+
id: setup-wasm32-unknown-wasip1-threads
103+
with: { target: wasm32-unknown-wasip1-threads }
104+
- run: ./Utilities/build-examples.sh
105+
env:
106+
SWIFT_SDK_ID_wasm32_unknown_wasip1_threads: ${{ steps.setup-wasm32-unknown-wasip1-threads.outputs.swift-sdk-id }}
107+
SWIFT_SDK_ID_wasm32_unknown_wasi: ${{ steps.setup-wasm32-unknown-wasi.outputs.swift-sdk-id }}
108+
- name: Upload static files as artifact
109+
id: deployment
110+
uses: actions/upload-pages-artifact@v3
111+
with:
112+
path: Examples/
113+
deploy-examples:
114+
runs-on: ubuntu-latest
115+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
116+
environment:
117+
name: github-pages
118+
url: ${{ steps.deployment.outputs.page_url }}
119+
needs: build-examples
120+
steps:
121+
- name: Deploy to GitHub Pages
122+
id: deployment
123+
uses: actions/deploy-pages@v4

Examples/ActorOnWebWorker/build.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}" -c release \
1+
#!/bin/bash
2+
set -euxo pipefail
3+
swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" -c release \
24
plugin --allow-writing-to-package-directory \
35
js --use-cdn --output ./Bundle

Examples/Basic/build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/bin/bash
2-
set -ex
3-
swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasi}" -c "${1:-debug}" js --use-cdn
2+
set -euxo pipefail
3+
swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasi:-${SWIFT_SDK_ID:-wasm32-unknown-wasi}}" -c "${1:-debug}" js --use-cdn

Examples/Embedded/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/bin/bash
2+
set -euxo pipefail
23
package_dir="$(cd "$(dirname "$0")" && pwd)"
34
JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM=true \
45
swift package --package-path "$package_dir" \

Examples/Multithreading/build.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}" -c release \
1+
#!/bin/bash
2+
set -euxo pipefail
3+
swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" -c release \
24
plugin --allow-writing-to-package-directory \
35
js --use-cdn --output ./Bundle

Examples/OffscrenCanvas/build.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}" -c release \
1+
#!/bin/bash
2+
set -euxo pipefail
3+
swift package --swift-sdk "${SWIFT_SDK_ID_wasm32_unknown_wasip1_threads:-${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}}" -c release \
24
plugin --allow-writing-to-package-directory \
35
js --use-cdn --output ./Bundle

Examples/PlayBridgeJS/Package.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// swift-tools-version:6.0
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "PlayBridgeJS",
7+
platforms: [
8+
.macOS(.v14)
9+
],
10+
dependencies: [
11+
.package(name: "JavaScriptKit", path: "../../"),
12+
.package(url: "https://github.com/swiftlang/swift-syntax", from: "600.0.1"),
13+
],
14+
targets: [
15+
.executableTarget(
16+
name: "PlayBridgeJS",
17+
dependencies: [
18+
"JavaScriptKit",
19+
.product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
20+
.product(name: "SwiftParser", package: "swift-syntax"),
21+
.product(name: "SwiftSyntax", package: "swift-syntax"),
22+
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
23+
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
24+
],
25+
swiftSettings: [
26+
.enableExperimentalFeature("Extern")
27+
],
28+
linkerSettings: [
29+
.unsafeFlags(
30+
[
31+
"-Xlinker", "--stack-first",
32+
"-Xlinker", "--global-base=524288",
33+
"-Xlinker", "-z", "-Xlinker", "stack-size=524288",
34+
],
35+
.when(platforms: [.wasi])
36+
)
37+
]
38+
)
39+
]
40+
)

Examples/PlayBridgeJS/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Playground for BridgeJS example
2+
3+
Install Development Snapshot toolchain `DEVELOPMENT-SNAPSHOT-2024-07-08-a` from [swift.org/install](https://www.swift.org/install/) and run the following commands:
4+
5+
```sh
6+
$ swift sdk install https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-07-09-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-07-09-a-wasm32-unknown-wasi.artifactbundle.zip
7+
$ ./build.sh
8+
$ npx serve
9+
```
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// BridgeJS Playground Main Application
2+
import { EditorSystem } from './editor.js';
3+
import ts from 'typescript';
4+
import { TypeProcessor } from './processor.js';
5+
6+
export class BridgeJSPlayground {
7+
constructor() {
8+
this.editorSystem = new EditorSystem();
9+
this.playBridgeJS = null;
10+
this.generateTimeout = null;
11+
this.isInitialized = false;
12+
13+
// DOM Elements
14+
this.errorDisplay = document.getElementById('errorDisplay');
15+
this.errorMessage = document.getElementById('errorMessage');
16+
}
17+
18+
// Initialize the application
19+
async initialize() {
20+
if (this.isInitialized) {
21+
return;
22+
}
23+
24+
try {
25+
// Initialize editor system
26+
await this.editorSystem.init();
27+
28+
// Initialize BridgeJS
29+
await this.initializeBridgeJS();
30+
31+
// Set up event listeners
32+
this.setupEventListeners();
33+
34+
// Load sample code
35+
this.editorSystem.loadSampleCode();
36+
37+
this.isInitialized = true;
38+
console.log('BridgeJS Playground initialized successfully');
39+
} catch (error) {
40+
console.error('Failed to initialize BridgeJS Playground:', error);
41+
this.showError('Failed to initialize application: ' + error.message);
42+
}
43+
}
44+
45+
// Initialize BridgeJS
46+
async initializeBridgeJS() {
47+
try {
48+
// Import the BridgeJS module
49+
const { init } = await import("../../.build/plugins/PackageToJS/outputs/Package/index.js");
50+
const { exports } = await init({
51+
imports: {
52+
createTS2Skeleton: this.createTS2Skeleton
53+
}
54+
});
55+
this.playBridgeJS = new exports.PlayBridgeJS();
56+
console.log('BridgeJS initialized successfully');
57+
} catch (error) {
58+
console.error('Failed to initialize BridgeJS:', error);
59+
throw new Error('BridgeJS initialization failed: ' + error.message);
60+
}
61+
}
62+
63+
// Set up event listeners
64+
setupEventListeners() {
65+
// Add change listeners for real-time generation
66+
this.editorSystem.addChangeListeners(() => {
67+
// Debounce generation to avoid excessive calls
68+
if (this.generateTimeout) {
69+
clearTimeout(this.generateTimeout);
70+
}
71+
this.generateTimeout = setTimeout(() => this.generateCode(), 300);
72+
});
73+
}
74+
75+
createTS2Skeleton() {
76+
return {
77+
convert: (dtsCode) => {
78+
const virtualFilePath = "bridge-js.d.ts"
79+
const virtualHost = {
80+
fileExists: fileName => fileName === virtualFilePath,
81+
readFile: fileName => dtsCode,
82+
getSourceFile: (fileName, languageVersion) => {
83+
const sourceText = dtsCode;
84+
if (sourceText === undefined) return undefined;
85+
return ts.createSourceFile(fileName, sourceText, languageVersion);
86+
},
87+
getDefaultLibFileName: options => "lib.d.ts",
88+
writeFile: (fileName, data) => {
89+
console.log(`[emit] ${fileName}:\n${data}`);
90+
},
91+
getCurrentDirectory: () => "",
92+
getDirectories: () => [],
93+
getCanonicalFileName: fileName => fileName,
94+
getNewLine: () => "\n",
95+
useCaseSensitiveFileNames: () => true
96+
}
97+
// Create TypeScript program from d.ts content
98+
const tsProgram = ts.createProgram({
99+
rootNames: [virtualFilePath],
100+
host: virtualHost,
101+
options: {
102+
noEmit: true,
103+
declaration: true,
104+
}
105+
})
106+
107+
// Create diagnostic engine for error reporting
108+
const diagnosticEngine = {
109+
print: (level, message, node) => {
110+
console.log(`[${level}] ${message}`);
111+
if (level === 'error') {
112+
this.showError(`TypeScript Error: ${message}`);
113+
}
114+
}
115+
};
116+
117+
// Process the TypeScript definitions to generate skeleton
118+
const processor = new TypeProcessor(tsProgram.getTypeChecker(), diagnosticEngine);
119+
120+
const skeleton = processor.processTypeDeclarations(tsProgram, virtualFilePath);
121+
122+
return JSON.stringify(skeleton);
123+
}
124+
}
125+
}
126+
127+
// Generate code through BridgeJS
128+
async generateCode() {
129+
if (!this.playBridgeJS) {
130+
this.showError('BridgeJS is not initialized');
131+
return;
132+
}
133+
134+
try {
135+
this.hideError();
136+
137+
const inputs = this.editorSystem.getInputs();
138+
const swiftCode = inputs.swift;
139+
const dtsCode = inputs.dts;
140+
141+
// Process the code and get PlayBridgeJSOutput
142+
const result = this.playBridgeJS.update(swiftCode, dtsCode);
143+
144+
// Update outputs using the PlayBridgeJSOutput object
145+
this.editorSystem.updateOutputs(result);
146+
147+
console.log('Code generated successfully');
148+
149+
} catch (error) {
150+
console.error('Error generating code:', error);
151+
this.showError('Error generating code: ' + error.message);
152+
}
153+
}
154+
155+
// Show error message
156+
showError(message) {
157+
this.errorMessage.textContent = message;
158+
this.errorDisplay.classList.add('show');
159+
}
160+
161+
// Hide error message
162+
hideError() {
163+
this.errorDisplay.classList.remove('show');
164+
}
165+
}

0 commit comments

Comments
 (0)