├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── actions
│ └── install-swift
│ │ └── action.yml
├── dependabot.yml
└── workflows
│ └── test.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .spi.yml
├── .swift-format
├── Benchmarks
├── Package.swift
├── README.md
├── Sources
│ ├── Benchmarks.swift
│ ├── Generated
│ │ ├── ExportSwift.swift
│ │ ├── ImportTS.swift
│ │ └── JavaScript
│ │ │ ├── ExportSwift.json
│ │ │ └── ImportTS.json
│ └── bridge.d.ts
├── package.json
└── run.js
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Examples
├── ActorOnWebWorker
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ │ └── MyApp.swift
│ ├── build.sh
│ ├── index.html
│ └── serve.json
├── Basic
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ │ └── main.swift
│ ├── build.sh
│ └── index.html
├── Embedded
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ │ └── EmbeddedApp
│ │ │ ├── _thingsThatShouldNotBeNeeded.swift
│ │ │ └── main.swift
│ ├── build.sh
│ └── index.html
├── ExportSwift
│ ├── Package.swift
│ ├── Sources
│ │ └── main.swift
│ ├── index.html
│ └── index.js
├── ImportTS
│ ├── Package.swift
│ ├── Sources
│ │ ├── bridge.d.ts
│ │ └── main.swift
│ ├── index.html
│ └── index.js
├── Multithreading
│ ├── Package.resolved
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ │ └── MyApp
│ │ │ ├── Scene.swift
│ │ │ └── main.swift
│ ├── build.sh
│ ├── index.html
│ └── serve.json
├── OffscrenCanvas
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ │ └── MyApp
│ │ │ ├── main.swift
│ │ │ └── render.swift
│ ├── build.sh
│ ├── index.html
│ └── serve.json
└── Testing
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ └── Counter
│ │ └── Counter.swift
│ ├── Tests
│ └── CounterTests
│ │ └── CounterTests.swift
│ └── package.json
├── LICENSE
├── Makefile
├── Package.swift
├── Plugins
├── BridgeJS
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ │ ├── BridgeJSBuildPlugin
│ │ │ └── BridgeJSBuildPlugin.swift
│ │ ├── BridgeJSCommandPlugin
│ │ │ └── BridgeJSCommandPlugin.swift
│ │ ├── BridgeJSLink
│ │ │ ├── BridgeJSLink.swift
│ │ │ └── BridgeJSSkeleton
│ │ ├── BridgeJSSkeleton
│ │ │ └── BridgeJSSkeleton.swift
│ │ ├── BridgeJSTool
│ │ │ ├── BridgeJSSkeleton
│ │ │ ├── BridgeJSTool.swift
│ │ │ ├── DiagnosticError.swift
│ │ │ ├── ExportSwift.swift
│ │ │ ├── ImportTS.swift
│ │ │ └── TypeDeclResolver.swift
│ │ └── JavaScript
│ │ │ ├── README.md
│ │ │ ├── bin
│ │ │ └── ts2skeleton.js
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ ├── cli.js
│ │ │ ├── index.d.ts
│ │ │ └── processor.js
│ └── Tests
│ │ └── BridgeJSToolTests
│ │ ├── BridgeJSLinkTests.swift
│ │ ├── ExportSwiftTests.swift
│ │ ├── ImportTSTests.swift
│ │ ├── Inputs
│ │ ├── ArrayParameter.d.ts
│ │ ├── Interface.d.ts
│ │ ├── PrimitiveParameters.d.ts
│ │ ├── PrimitiveParameters.swift
│ │ ├── PrimitiveReturn.d.ts
│ │ ├── PrimitiveReturn.swift
│ │ ├── StringParameter.d.ts
│ │ ├── StringParameter.swift
│ │ ├── StringReturn.d.ts
│ │ ├── StringReturn.swift
│ │ ├── SwiftClass.swift
│ │ ├── TypeAlias.d.ts
│ │ ├── TypeScriptClass.d.ts
│ │ ├── VoidParameterVoidReturn.d.ts
│ │ └── VoidParameterVoidReturn.swift
│ │ ├── SnapshotTesting.swift
│ │ ├── TemporaryDirectory.swift
│ │ └── __Snapshots__
│ │ ├── BridgeJSLinkTests
│ │ ├── ArrayParameter.Import.d.ts
│ │ ├── ArrayParameter.Import.js
│ │ ├── Interface.Import.d.ts
│ │ ├── Interface.Import.js
│ │ ├── PrimitiveParameters.Export.d.ts
│ │ ├── PrimitiveParameters.Export.js
│ │ ├── PrimitiveParameters.Import.d.ts
│ │ ├── PrimitiveParameters.Import.js
│ │ ├── PrimitiveReturn.Export.d.ts
│ │ ├── PrimitiveReturn.Export.js
│ │ ├── PrimitiveReturn.Import.d.ts
│ │ ├── PrimitiveReturn.Import.js
│ │ ├── StringParameter.Export.d.ts
│ │ ├── StringParameter.Export.js
│ │ ├── StringParameter.Import.d.ts
│ │ ├── StringParameter.Import.js
│ │ ├── StringReturn.Export.d.ts
│ │ ├── StringReturn.Export.js
│ │ ├── StringReturn.Import.d.ts
│ │ ├── StringReturn.Import.js
│ │ ├── SwiftClass.Export.d.ts
│ │ ├── SwiftClass.Export.js
│ │ ├── TypeAlias.Import.d.ts
│ │ ├── TypeAlias.Import.js
│ │ ├── TypeScriptClass.Import.d.ts
│ │ ├── TypeScriptClass.Import.js
│ │ ├── VoidParameterVoidReturn.Export.d.ts
│ │ ├── VoidParameterVoidReturn.Export.js
│ │ ├── VoidParameterVoidReturn.Import.d.ts
│ │ └── VoidParameterVoidReturn.Import.js
│ │ ├── ExportSwiftTests
│ │ ├── PrimitiveParameters.json
│ │ ├── PrimitiveParameters.swift
│ │ ├── PrimitiveReturn.json
│ │ ├── PrimitiveReturn.swift
│ │ ├── StringParameter.json
│ │ ├── StringParameter.swift
│ │ ├── StringReturn.json
│ │ ├── StringReturn.swift
│ │ ├── SwiftClass.json
│ │ ├── SwiftClass.swift
│ │ ├── VoidParameterVoidReturn.json
│ │ └── VoidParameterVoidReturn.swift
│ │ └── ImportTSTests
│ │ ├── ArrayParameter.swift
│ │ ├── Interface.swift
│ │ ├── PrimitiveParameters.swift
│ │ ├── PrimitiveReturn.swift
│ │ ├── StringParameter.swift
│ │ ├── StringReturn.swift
│ │ ├── TypeAlias.swift
│ │ ├── TypeScriptClass.swift
│ │ └── VoidParameterVoidReturn.swift
└── PackageToJS
│ ├── Fixtures
│ └── ContinuationLeakInTest
│ │ ├── SwiftTesting
│ │ ├── Package.swift
│ │ └── Tests
│ │ │ └── CheckTests.swift
│ │ └── XCTest
│ │ ├── Package.swift
│ │ └── Tests
│ │ └── CheckTests.swift
│ ├── Package.swift
│ ├── README.md
│ ├── Sources
│ ├── BridgeJSLink
│ ├── MiniMake.swift
│ ├── PackageToJS.swift
│ ├── PackageToJSPlugin.swift
│ ├── ParseWasm.swift
│ ├── Preprocess.swift
│ └── TestsParser.swift
│ ├── Templates
│ ├── bin
│ │ └── test.js
│ ├── index.d.ts
│ ├── index.js
│ ├── instantiate.d.ts
│ ├── instantiate.js
│ ├── package.json
│ ├── platforms
│ │ ├── browser.d.ts
│ │ ├── browser.js
│ │ ├── browser.worker.js
│ │ ├── node.d.ts
│ │ └── node.js
│ ├── runtime.d.ts
│ ├── runtime.mjs
│ ├── test.browser.html
│ ├── test.d.ts
│ ├── test.js
│ └── tsconfig.json
│ └── Tests
│ ├── ExampleTests.swift
│ ├── MiniMakeTests.swift
│ ├── PackagingPlannerTests.swift
│ ├── PreprocessTests.swift
│ ├── SnapshotTesting.swift
│ ├── TemplatesTests.swift
│ ├── TemporaryDirectory.swift
│ ├── TestsParserTests.swift
│ └── __Snapshots__
│ ├── PackagingPlannerTests
│ ├── planBuild_debug.json
│ ├── planBuild_release.json
│ ├── planBuild_release_dwarf.json
│ ├── planBuild_release_name.json
│ ├── planBuild_release_no_optimize.json
│ └── planTestBuild.json
│ └── TestsParserTests
│ ├── testAllPassed.txt
│ ├── testAssertFailure.txt
│ ├── testCrash.txt
│ ├── testSkipped.txt
│ └── testThrowFailure.txt
├── README.md
├── Runtime
├── .gitignore
├── .npmignore
├── rollup.config.mjs
├── src
│ ├── closure-heap.ts
│ ├── find-global.ts
│ ├── index.ts
│ ├── itc.ts
│ ├── js-value.ts
│ ├── memory.ts
│ ├── object-heap.ts
│ └── types.ts
└── tsconfig.json
├── Sources
├── JavaScriptBigIntSupport
│ ├── Int64+I64.swift
│ └── JSBigInt+I64.swift
├── JavaScriptEventLoop
│ ├── JSSending.swift
│ ├── JavaScriptEventLoop+ExecutorFactory.swift
│ ├── JavaScriptEventLoop+LegacyHooks.swift
│ ├── JavaScriptEventLoop.swift
│ ├── JobQueue.swift
│ ├── WebWorkerDedicatedExecutor.swift
│ └── WebWorkerTaskExecutor.swift
├── JavaScriptEventLoopTestSupport
│ └── JavaScriptEventLoopTestSupport.swift
├── JavaScriptKit
│ ├── BasicObjects
│ │ ├── JSArray.swift
│ │ ├── JSDate.swift
│ │ ├── JSError.swift
│ │ ├── JSPromise.swift
│ │ ├── JSTimer.swift
│ │ └── JSTypedArray.swift
│ ├── ConstructibleFromJSValue.swift
│ ├── ConvertibleToJSValue.swift
│ ├── Deprecated.swift
│ ├── Documentation.docc
│ │ ├── Articles
│ │ │ ├── Ahead-of-Time-Code-Generation.md
│ │ │ ├── Deploying-Pages.md
│ │ │ ├── Exporting-Swift-to-JavaScript.md
│ │ │ ├── Importing-TypeScript-into-Swift.md
│ │ │ └── JavaScript-Environment-Requirements.md
│ │ ├── Documentation.md
│ │ └── Tutorials
│ │ │ ├── Hello-World
│ │ │ ├── Hello-World.tutorial
│ │ │ └── Resources
│ │ │ │ ├── hello-world-0-1-swift-version.txt
│ │ │ │ ├── hello-world-0-2-select-sdk.txt
│ │ │ │ ├── hello-world-1-1-init-package.txt
│ │ │ │ ├── hello-world-1-2-add-dependency.txt
│ │ │ │ ├── hello-world-1-3-add-target-dependency.txt
│ │ │ │ ├── hello-world-2-1-main-swift.swift
│ │ │ │ ├── hello-world-2-2-index-html.html
│ │ │ │ ├── hello-world-3-1-build.txt
│ │ │ │ ├── hello-world-3-2-server.txt
│ │ │ │ ├── hello-world-3-3-app.png
│ │ │ │ └── hello-world-3-3-open.txt
│ │ │ ├── Resources
│ │ │ └── image.png
│ │ │ └── Table-of-Contents.tutorial
│ ├── Features.swift
│ ├── FundamentalObjects
│ │ ├── JSBigInt.swift
│ │ ├── JSClosure.swift
│ │ ├── JSFunction.swift
│ │ ├── JSObject.swift
│ │ ├── JSString.swift
│ │ ├── JSSymbol.swift
│ │ └── JSThrowingFunction.swift
│ ├── JSBridgedType.swift
│ ├── JSException.swift
│ ├── JSValue.swift
│ ├── JSValueDecoder.swift
│ ├── Macros.swift
│ ├── Runtime
│ │ ├── index.d.ts
│ │ └── index.mjs
│ └── ThreadLocal.swift
├── _CJavaScriptBigIntSupport
│ ├── _CJavaScriptKit+I64.c
│ └── include
│ │ ├── _CJavaScriptKit+I64.h
│ │ └── module.modulemap
├── _CJavaScriptEventLoop
│ ├── _CJavaScriptEventLoop.c
│ └── include
│ │ ├── _CJavaScriptEventLoop.h
│ │ └── module.modulemap
├── _CJavaScriptEventLoopTestSupport
│ ├── _CJavaScriptEventLoopTestSupport.c
│ └── include
│ │ └── dummy.h
└── _CJavaScriptKit
│ ├── _CJavaScriptKit.c
│ └── include
│ ├── _CJavaScriptKit.h
│ └── module.modulemap
├── Tests
├── BridgeJSRuntimeTests
│ ├── ExportAPITests.swift
│ └── Generated
│ │ ├── ExportSwift.swift
│ │ └── JavaScript
│ │ └── ExportSwift.json
├── JavaScriptBigIntSupportTests
│ └── JavaScriptBigIntSupportTests.swift
├── JavaScriptEventLoopTestSupportTests
│ └── JavaScriptEventLoopTestSupportTests.swift
├── JavaScriptEventLoopTests
│ ├── JSPromiseTests.swift
│ ├── JSTimerTests.swift
│ ├── JavaScriptEventLoopTests.swift
│ ├── WebWorkerDedicatedExecutorTests.swift
│ └── WebWorkerTaskExecutorTests.swift
├── JavaScriptKitTests
│ ├── JSObjectTests.swift
│ ├── JSStringTests.swift
│ ├── JSTypedArrayTests.swift
│ ├── JavaScriptKitTests.swift
│ └── ThreadLocalTests.swift
└── prelude.mjs
├── Utilities
└── format.swift
├── package-lock.json
└── package.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | trim_trailing_whitespace = true
7 | insert_final_newline = true
8 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | Sources/JavaScriptKit/Runtime/** linguist-generated
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [swiftwasm] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: swiftwasm # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/actions/install-swift/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Install Swift toolchain'
2 | description: 'Install Swift toolchain tarball from URL'
3 | inputs:
4 | download-url:
5 | description: 'URL to download Swift toolchain tarball'
6 | required: true
7 |
8 | runs:
9 | using: composite
10 | steps:
11 | # https://www.swift.org/install/linux/#installation-via-tarball
12 | - name: Install dependent packages for Swift
13 | shell: bash
14 | run: >
15 | sudo apt-get -q update &&
16 | sudo apt-get install -y
17 | binutils
18 | git
19 | gnupg2
20 | libc6-dev
21 | libcurl4-openssl-dev
22 | libedit2
23 | libgcc-9-dev
24 | libpython3.8
25 | libsqlite3-0
26 | libstdc++-9-dev
27 | libxml2-dev
28 | libz3-dev
29 | pkg-config
30 | tzdata
31 | unzip
32 | zlib1g-dev
33 | curl
34 |
35 | - name: Install Swift
36 | shell: bash
37 | run: curl -fL ${{ inputs.download-url }} | sudo tar xfz - --strip-components=2 -C /usr/local
38 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: 'github-actions'
9 | directory: '/'
10 | schedule:
11 | interval: 'weekly'
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | .DS_Store
4 | .build
5 | /Packages
6 | /*.xcodeproj
7 | xcuserdata/
8 | .swiftpm
9 | .vscode
10 | Examples/*/Bundle
11 | Examples/*/package-lock.json
12 | Package.resolved
13 | Plugins/BridgeJS/Sources/JavaScript/package-lock.json
14 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .build
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "overrides": [
3 | {
4 | "files": ["tsconfig.json", "*.js", "*.ts"],
5 | "options": {
6 | "tabWidth": 4
7 | }
8 | }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.spi.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | builder:
3 | configs:
4 | - documentation_targets:
5 | - JavaScriptKit
6 | - JavaScriptEventLoop
7 | - JavaScriptBigIntSupport
8 |
--------------------------------------------------------------------------------
/.swift-format:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "lineLength": 120,
4 | "indentation": {
5 | "spaces": 4
6 | },
7 | "lineBreakBeforeEachArgument": true,
8 | "indentConditionalCompilationBlocks": false,
9 | "prioritizeKeepingFunctionOutputTogether": true,
10 | "rules": {
11 | "AlwaysUseLowerCamelCase": false
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Benchmarks/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Benchmarks",
7 | dependencies: [
8 | .package(path: "../")
9 | ],
10 | targets: [
11 | .executableTarget(
12 | name: "Benchmarks",
13 | dependencies: ["JavaScriptKit"],
14 | exclude: ["Generated/JavaScript", "bridge.d.ts"],
15 | swiftSettings: [
16 | .enableExperimentalFeature("Extern")
17 | ]
18 | )
19 | ]
20 | )
21 |
--------------------------------------------------------------------------------
/Benchmarks/README.md:
--------------------------------------------------------------------------------
1 | # JavaScriptKit Benchmarks
2 |
3 | This directory contains performance benchmarks for JavaScriptKit.
4 |
5 | ## Building Benchmarks
6 |
7 | Before running the benchmarks, you need to build the test suite:
8 |
9 | ```bash
10 | JAVASCRIPTKIT_EXPERIMENTAL_BRIDGEJS=1 swift package --swift-sdk $SWIFT_SDK_ID js -c release
11 | ```
12 |
13 | ## Running Benchmarks
14 |
15 | ```bash
16 | # Run with default settings
17 | node run.js
18 |
19 | # Save results to a JSON file
20 | node run.js --output=results.json
21 |
22 | # Specify number of iterations
23 | node run.js --runs=20
24 |
25 | # Run in adaptive mode until results stabilize
26 | node run.js --adaptive --output=stable-results.json
27 |
28 | # Run benchmarks and compare with previous results
29 | node run.js --baseline=previous-results.json
30 | ```
31 |
--------------------------------------------------------------------------------
/Benchmarks/Sources/Benchmarks.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 |
3 | class Benchmark {
4 | init(_ title: String) {
5 | self.title = title
6 | }
7 |
8 | let title: String
9 |
10 | func testSuite(_ name: String, _ body: @escaping () -> Void) {
11 | let jsBody = JSClosure { arguments -> JSValue in
12 | body()
13 | return .undefined
14 | }
15 | benchmarkRunner("\(title)/\(name)", jsBody)
16 | }
17 | }
18 |
19 | @JS func run() {
20 |
21 | let call = Benchmark("Call")
22 |
23 | call.testSuite("JavaScript function call through Wasm import") {
24 | for _ in 0..<20_000_000 {
25 | benchmarkHelperNoop()
26 | }
27 | }
28 |
29 | call.testSuite("JavaScript function call through Wasm import with int") {
30 | for _ in 0..<10_000_000 {
31 | benchmarkHelperNoopWithNumber(42)
32 | }
33 | }
34 |
35 | let propertyAccess = Benchmark("Property access")
36 |
37 | do {
38 | let swiftInt: Double = 42
39 | let object = JSObject()
40 | object.jsNumber = JSValue.number(swiftInt)
41 | propertyAccess.testSuite("Write Number") {
42 | for _ in 0..<1_000_000 {
43 | object.jsNumber = JSValue.number(swiftInt)
44 | }
45 | }
46 | }
47 |
48 | do {
49 | let object = JSObject()
50 | object.jsNumber = JSValue.number(42)
51 | propertyAccess.testSuite("Read Number") {
52 | for _ in 0..<1_000_000 {
53 | _ = object.jsNumber.number
54 | }
55 | }
56 | }
57 |
58 | do {
59 | let swiftString = "Hello, world"
60 | let object = JSObject()
61 | object.jsString = swiftString.jsValue
62 | propertyAccess.testSuite("Write String") {
63 | for _ in 0..<1_000_000 {
64 | object.jsString = swiftString.jsValue
65 | }
66 | }
67 | }
68 |
69 | do {
70 | let object = JSObject()
71 | object.jsString = JSValue.string("Hello, world")
72 | propertyAccess.testSuite("Read String") {
73 | for _ in 0..<1_000_000 {
74 | _ = object.jsString.string
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Benchmarks/Sources/Generated/ExportSwift.swift:
--------------------------------------------------------------------------------
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 | @_extern(wasm, module: "bjs", name: "return_string")
7 | private func _return_string(_ ptr: UnsafePointer?, _ len: Int32)
8 | @_extern(wasm, module: "bjs", name: "init_memory")
9 | private func _init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer?)
10 |
11 | @_expose(wasm, "bjs_main")
12 | @_cdecl("bjs_main")
13 | public func _bjs_main() -> Void {
14 | main()
15 | }
--------------------------------------------------------------------------------
/Benchmarks/Sources/Generated/ImportTS.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func benchmarkHelperNoop() -> Void {
19 | @_extern(wasm, module: "Benchmarks", name: "bjs_benchmarkHelperNoop")
20 | func bjs_benchmarkHelperNoop() -> Void
21 | bjs_benchmarkHelperNoop()
22 | }
23 |
24 | func benchmarkHelperNoopWithNumber(_ n: Double) -> Void {
25 | @_extern(wasm, module: "Benchmarks", name: "bjs_benchmarkHelperNoopWithNumber")
26 | func bjs_benchmarkHelperNoopWithNumber(_ n: Float64) -> Void
27 | bjs_benchmarkHelperNoopWithNumber(n)
28 | }
29 |
30 | func benchmarkRunner(_ name: String, _ body: JSObject) -> Void {
31 | @_extern(wasm, module: "Benchmarks", name: "bjs_benchmarkRunner")
32 | func bjs_benchmarkRunner(_ name: Int32, _ body: Int32) -> Void
33 | var name = name
34 | let nameId = name.withUTF8 { b in
35 | _make_jsstring(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
36 | }
37 | bjs_benchmarkRunner(nameId, Int32(bitPattern: body.id))
38 | }
--------------------------------------------------------------------------------
/Benchmarks/Sources/Generated/JavaScript/ExportSwift.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [
3 |
4 | ],
5 | "functions" : [
6 | {
7 | "abiName" : "bjs_main",
8 | "name" : "main",
9 | "parameters" : [
10 |
11 | ],
12 | "returnType" : {
13 | "void" : {
14 |
15 | }
16 | }
17 | }
18 | ]
19 | }
--------------------------------------------------------------------------------
/Benchmarks/Sources/Generated/JavaScript/ImportTS.json:
--------------------------------------------------------------------------------
1 | {
2 | "children" : [
3 | {
4 | "functions" : [
5 | {
6 | "name" : "benchmarkHelperNoop",
7 | "parameters" : [
8 |
9 | ],
10 | "returnType" : {
11 | "void" : {
12 |
13 | }
14 | }
15 | },
16 | {
17 | "name" : "benchmarkHelperNoopWithNumber",
18 | "parameters" : [
19 | {
20 | "name" : "n",
21 | "type" : {
22 | "double" : {
23 |
24 | }
25 | }
26 | }
27 | ],
28 | "returnType" : {
29 | "void" : {
30 |
31 | }
32 | }
33 | },
34 | {
35 | "name" : "benchmarkRunner",
36 | "parameters" : [
37 | {
38 | "name" : "name",
39 | "type" : {
40 | "string" : {
41 |
42 | }
43 | }
44 | },
45 | {
46 | "name" : "body",
47 | "type" : {
48 | "jsObject" : {
49 |
50 | }
51 | }
52 | }
53 | ],
54 | "returnType" : {
55 | "void" : {
56 |
57 | }
58 | }
59 | }
60 | ],
61 | "types" : [
62 |
63 | ]
64 | }
65 | ],
66 | "moduleName" : "Benchmarks"
67 | }
--------------------------------------------------------------------------------
/Benchmarks/Sources/bridge.d.ts:
--------------------------------------------------------------------------------
1 | declare function benchmarkHelperNoop(): void;
2 | declare function benchmarkHelperNoopWithNumber(n: number): void;
3 | declare function benchmarkRunner(name: string, body: (n: number) => void): void;
4 |
--------------------------------------------------------------------------------
/Benchmarks/package.json:
--------------------------------------------------------------------------------
1 | { "type": "module" }
2 |
--------------------------------------------------------------------------------
/Examples/ActorOnWebWorker/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Example",
7 | platforms: [.macOS("15"), .iOS("18"), .watchOS("11"), .tvOS("18"), .visionOS("2")],
8 | dependencies: [
9 | .package(path: "../../")
10 | ],
11 | targets: [
12 | .executableTarget(
13 | name: "MyApp",
14 | dependencies: [
15 | .product(name: "JavaScriptKit", package: "JavaScriptKit"),
16 | .product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
17 | ]
18 | )
19 | ]
20 | )
21 |
--------------------------------------------------------------------------------
/Examples/ActorOnWebWorker/README.md:
--------------------------------------------------------------------------------
1 | # WebWorker + Actor example
2 |
3 | Install Development Snapshot toolchain `DEVELOPMENT-SNAPSHOT-2024-07-08-a` or later from [swift.org/install](https://www.swift.org/install/) and run the following commands:
4 |
5 | ```sh
6 | $ (
7 | set -eo pipefail; \
8 | V="$(swiftc --version | head -n1)"; \
9 | TAG="$(curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/tag-by-version.json" | jq -e -r --arg v "$V" '.[$v] | .[-1]')"; \
10 | curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/builds/$TAG.json" | \
11 | jq -r '.["swift-sdks"]["wasm32-unknown-wasip1-threads"] | "swift sdk install \"\(.url)\" --checksum \"\(.checksum)\""' | sh -x
12 | )
13 | $ export SWIFT_SDK_ID=$(
14 | V="$(swiftc --version | head -n1)"; \
15 | TAG="$(curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/tag-by-version.json" | jq -e -r --arg v "$V" '.[$v] | .[-1]')"; \
16 | curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/builds/$TAG.json" | \
17 | jq -r '.["swift-sdks"]["wasm32-unknown-wasip1-threads"]["id"]'
18 | )
19 | $ ./build.sh
20 | $ npx serve
21 | ```
22 |
--------------------------------------------------------------------------------
/Examples/ActorOnWebWorker/build.sh:
--------------------------------------------------------------------------------
1 | swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}" -c release \
2 | plugin --allow-writing-to-package-directory \
3 | js --use-cdn --output ./Bundle
4 |
--------------------------------------------------------------------------------
/Examples/ActorOnWebWorker/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebWorker + Actor example
6 |
7 |
8 |
9 |
13 | Full-text Search with Actor on Web Worker
14 |
15 |
16 |
20 |
21 |
22 |
23 |
25 |
26 |
Ready
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Examples/ActorOnWebWorker/serve.json:
--------------------------------------------------------------------------------
1 | {
2 | "headers": [{
3 | "source": "**/*",
4 | "headers": [
5 | {
6 | "key": "Cross-Origin-Embedder-Policy",
7 | "value": "require-corp"
8 | }, {
9 | "key": "Cross-Origin-Opener-Policy",
10 | "value": "same-origin"
11 | }
12 | ]
13 | }]
14 | }
15 |
--------------------------------------------------------------------------------
/Examples/Basic/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Basic",
7 | platforms: [
8 | .macOS(.v14)
9 | ],
10 | dependencies: [.package(name: "JavaScriptKit", path: "../../")],
11 | targets: [
12 | .executableTarget(
13 | name: "Basic",
14 | dependencies: [
15 | "JavaScriptKit",
16 | .product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
17 | ]
18 | )
19 | ],
20 | swiftLanguageModes: [.v5]
21 | )
22 |
--------------------------------------------------------------------------------
/Examples/Basic/README.md:
--------------------------------------------------------------------------------
1 | # Basic 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 | ```
10 |
--------------------------------------------------------------------------------
/Examples/Basic/Sources/main.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptEventLoop
2 | import JavaScriptKit
3 |
4 | let alert = JSObject.global.alert.function!
5 | let document = JSObject.global.document
6 |
7 | let divElement = document.createElement("div")
8 | divElement.innerText = "Hello, world"
9 | _ = document.body.appendChild(divElement)
10 |
11 | let buttonElement = document.createElement("button")
12 | buttonElement.innerText = "Alert demo"
13 | buttonElement.onclick = .object(
14 | JSClosure { _ in
15 | alert("Swift is running on browser!")
16 | return .undefined
17 | }
18 | )
19 |
20 | _ = document.body.appendChild(buttonElement)
21 |
22 | private let jsFetch = JSObject.global.fetch.function!
23 | func fetch(_ url: String) -> JSPromise {
24 | JSPromise(jsFetch(url).object!)!
25 | }
26 |
27 | JavaScriptEventLoop.installGlobalExecutor()
28 |
29 | struct Response: Decodable {
30 | let uuid: String
31 | }
32 |
33 | let asyncButtonElement = document.createElement("button")
34 | asyncButtonElement.innerText = "Fetch UUID demo"
35 | asyncButtonElement.onclick = .object(
36 | JSClosure { _ in
37 | Task {
38 | do {
39 | let response = try await fetch("https://httpbin.org/uuid").value
40 | let json = try await JSPromise(response.json().object!)!.value
41 | let parsedResponse = try JSValueDecoder().decode(Response.self, from: json)
42 | alert(parsedResponse.uuid)
43 | } catch {
44 | print(error)
45 | }
46 | }
47 |
48 | return .undefined
49 | }
50 | )
51 |
52 | _ = document.body.appendChild(asyncButtonElement)
53 |
--------------------------------------------------------------------------------
/Examples/Basic/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -ex
3 | swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasi}" -c "${1:-debug}" js --use-cdn
4 |
--------------------------------------------------------------------------------
/Examples/Basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Getting Started
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Examples/Embedded/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Embedded",
7 | dependencies: [
8 | .package(name: "JavaScriptKit", path: "../../"),
9 | .package(url: "https://github.com/swiftwasm/swift-dlmalloc", branch: "0.1.0"),
10 | ],
11 | targets: [
12 | .executableTarget(
13 | name: "EmbeddedApp",
14 | dependencies: [
15 | "JavaScriptKit",
16 | .product(name: "dlmalloc", package: "swift-dlmalloc"),
17 | ],
18 | cSettings: [.unsafeFlags(["-fdeclspec"])],
19 | swiftSettings: [
20 | .enableExperimentalFeature("Embedded"),
21 | .enableExperimentalFeature("Extern"),
22 | .unsafeFlags([
23 | "-Xfrontend", "-gnone",
24 | "-Xfrontend", "-disable-stack-protector",
25 | ]),
26 | ],
27 | linkerSettings: [
28 | .unsafeFlags([
29 | "-Xclang-linker", "-nostdlib",
30 | "-Xlinker", "--no-entry",
31 | "-Xlinker", "--export-if-defined=__main_argc_argv",
32 | ])
33 | ]
34 | )
35 | ],
36 | swiftLanguageModes: [.v5]
37 | )
38 |
--------------------------------------------------------------------------------
/Examples/Embedded/README.md:
--------------------------------------------------------------------------------
1 | # Embedded example
2 |
3 | Requires a recent DEVELOPMENT-SNAPSHOT toolchain. (tested with swift-6.1-DEVELOPMENT-SNAPSHOT-2025-02-21-a)
4 |
5 | ```sh
6 | $ ./build.sh
7 | $ npx serve
8 | ```
9 |
--------------------------------------------------------------------------------
/Examples/Embedded/Sources/EmbeddedApp/_thingsThatShouldNotBeNeeded.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 |
3 | // NOTE: it seems the embedded tree shaker gets rid of these exports if they are not used somewhere
4 | func _i_need_to_be_here_for_wasm_exports_to_work() {
5 | _ = _swjs_library_features
6 | _ = _swjs_call_host_function
7 | _ = _swjs_free_host_function
8 | }
9 |
10 | // TODO: why do I need this? and surely this is not ideal... figure this out, or at least have this come from a C lib
11 | @_cdecl("strlen")
12 | func strlen(_ s: UnsafePointer) -> Int {
13 | var p = s
14 | while p.pointee != 0 {
15 | p += 1
16 | }
17 | return p - s
18 | }
19 |
20 | enum LCG {
21 | static var x: UInt8 = 0
22 | static let a: UInt8 = 0x05
23 | static let c: UInt8 = 0x0b
24 |
25 | static func next() -> UInt8 {
26 | x = a &* x &+ c
27 | return x
28 | }
29 | }
30 |
31 | @_cdecl("arc4random_buf")
32 | public func arc4random_buf(_ buffer: UnsafeMutableRawPointer, _ size: Int) {
33 | for i in 0..(
34 | unsafelyWrapping: encode(this: textEncoder, textInputElement.value).object!
35 | )
36 | encodeResultElement.innerText = .string(
37 | encodedData.withUnsafeBytes { bytes in
38 | bytes.map { hex($0) }.joined(separator: " ")
39 | }
40 | )
41 | return .undefined
42 | }
43 | )
44 | let encoderContainer = document.createElement("div")
45 | _ = encoderContainer.appendChild(textInputElement)
46 | _ = encoderContainer.appendChild(encodeResultElement)
47 | _ = document.body.appendChild(encoderContainer)
48 |
49 | func print(_ message: String) {
50 | _ = JSObject.global.console.log(message)
51 | }
52 |
53 | func hex(_ value: UInt8) -> String {
54 | var result = "0x"
55 | let hexChars: [Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]
56 | result.append(hexChars[Int(value / 16)])
57 | result.append(hexChars[Int(value % 16)])
58 | return result
59 | }
60 |
--------------------------------------------------------------------------------
/Examples/Embedded/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | package_dir="$(cd "$(dirname "$0")" && pwd)"
3 | JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM=true \
4 | swift package --package-path "$package_dir" \
5 | -c release --triple wasm32-unknown-none-wasm js
6 |
--------------------------------------------------------------------------------
/Examples/Embedded/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Getting Started
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Examples/ExportSwift/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "MyApp",
7 | platforms: [
8 | .macOS(.v14)
9 | ],
10 | dependencies: [.package(name: "JavaScriptKit", path: "../../")],
11 | targets: [
12 | .executableTarget(
13 | name: "MyApp",
14 | dependencies: [
15 | "JavaScriptKit"
16 | ],
17 | swiftSettings: [
18 | .enableExperimentalFeature("Extern")
19 | ],
20 | plugins: [
21 | .plugin(name: "BridgeJS", package: "JavaScriptKit")
22 | ]
23 | )
24 | ]
25 | )
26 |
--------------------------------------------------------------------------------
/Examples/ExportSwift/Sources/main.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 |
3 | // Mark functions you want to export to JavaScript with the @JS attribute
4 | // This function will be available as `renderCircleSVG(size)` in JavaScript
5 | @JS public func renderCircleSVG(size: Int) -> String {
6 | let strokeWidth = 3
7 | let strokeColor = "black"
8 | let fillColor = "red"
9 | let cx = size / 2
10 | let cy = size / 2
11 | let r = (size / 2) - strokeWidth
12 | var svg = ""
16 | return svg
17 | }
18 |
19 | // Classes can also be exported using the @JS attribute
20 | // This class will be available as a constructor in JavaScript: new Greeter("name")
21 | @JS class Greeter {
22 | var name: String
23 |
24 | // Use @JS for initializers you want to expose
25 | @JS init(name: String) {
26 | self.name = name
27 | }
28 |
29 | // Methods need the @JS attribute to be accessible from JavaScript
30 | // This method will be available as greeter.greet() in JavaScript
31 | @JS public func greet() -> String {
32 | "Hello, \(name)!"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Examples/ExportSwift/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Getting Started
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Examples/ExportSwift/index.js:
--------------------------------------------------------------------------------
1 | import { init } from "./.build/plugins/PackageToJS/outputs/Package/index.js";
2 | const { exports } = await init({});
3 |
4 | const Greeter = exports.Greeter;
5 | const greeter = new Greeter("World");
6 | const circle = exports.renderCircleSVG(100);
7 |
8 | // Display the results
9 | const textOutput = document.createElement("div");
10 | textOutput.innerText = greeter.greet()
11 | document.body.appendChild(textOutput);
12 | const circleOutput = document.createElement("div");
13 | circleOutput.innerHTML = circle;
14 | document.body.appendChild(circleOutput);
15 |
--------------------------------------------------------------------------------
/Examples/ImportTS/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "MyApp",
7 | platforms: [
8 | .macOS(.v10_15),
9 | .iOS(.v13),
10 | .tvOS(.v13),
11 | .watchOS(.v6),
12 | .macCatalyst(.v13),
13 | ],
14 | dependencies: [.package(name: "JavaScriptKit", path: "../../")],
15 | targets: [
16 | .executableTarget(
17 | name: "MyApp",
18 | dependencies: [
19 | "JavaScriptKit"
20 | ],
21 | swiftSettings: [
22 | .enableExperimentalFeature("Extern")
23 | ],
24 | plugins: [
25 | .plugin(name: "BridgeJS", package: "JavaScriptKit")
26 | ]
27 | )
28 | ]
29 | )
30 |
--------------------------------------------------------------------------------
/Examples/ImportTS/Sources/bridge.d.ts:
--------------------------------------------------------------------------------
1 | // Function definition to expose console.log to Swift
2 | // Will be imported as a Swift function: consoleLog(message: String)
3 | export function consoleLog(message: string): void
4 |
5 | // TypeScript interface types are converted to Swift structs
6 | // This defines a subset of the browser's HTMLElement interface
7 | type HTMLElement = Pick & {
8 | // Methods with object parameters are properly handled
9 | appendChild(child: HTMLElement): void
10 | }
11 |
12 | // TypeScript object type with read-only properties
13 | // Properties will become Swift properties with appropriate access level
14 | type Document = {
15 | // Regular property - will be read/write in Swift
16 | title: string
17 | // Read-only property - will be read-only in Swift
18 | readonly body: HTMLElement
19 | // Method returning an object - will become a Swift method returning an HTMLElement
20 | createElement(tagName: string): HTMLElement
21 | }
22 | // Function returning a complex object
23 | // Will be imported as a Swift function: getDocument() -> Document
24 | export function getDocument(): Document
25 |
--------------------------------------------------------------------------------
/Examples/ImportTS/Sources/main.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 |
3 | // This function is automatically generated by the @JS plugin
4 | // It demonstrates how to use TypeScript functions and types imported from bridge.d.ts
5 | @JS public func run() {
6 | // Call the imported consoleLog function defined in bridge.d.ts
7 | consoleLog("Hello, World!")
8 |
9 | // Get the document object - this comes from the imported getDocument() function
10 | let document = getDocument()
11 |
12 | // Access and modify properties - the title property is read/write
13 | document.title = "Hello, World!"
14 |
15 | // Access read-only properties - body is defined as readonly in TypeScript
16 | let body = document.body
17 |
18 | // Create a new element using the document.createElement method
19 | let h1 = document.createElement("h1")
20 |
21 | // Set properties on the created element
22 | h1.innerText = "Hello, World!"
23 |
24 | // Call methods on objects - appendChild is defined in the HTMLElement interface
25 | body.appendChild(h1)
26 | }
27 |
--------------------------------------------------------------------------------
/Examples/ImportTS/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Getting Started
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Examples/ImportTS/index.js:
--------------------------------------------------------------------------------
1 | import { init } from "./.build/plugins/PackageToJS/outputs/Package/index.js";
2 | const { exports } = await init({
3 | imports: {
4 | consoleLog: (message) => {
5 | console.log(message);
6 | },
7 | getDocument: () => {
8 | return document;
9 | },
10 | }
11 | });
12 |
13 | exports.run()
14 |
--------------------------------------------------------------------------------
/Examples/Multithreading/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "072d03a6e24e01bd372682a6090adb80cf29dea39421e065de6ff8853de704c9",
3 | "pins" : [
4 | {
5 | "identity" : "chibi-ray",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/kateinoigakukun/chibi-ray",
8 | "state" : {
9 | "revision" : "c8cab621a3338dd2f8e817d3785362409d3b8cf1"
10 | }
11 | },
12 | {
13 | "identity" : "swift-syntax",
14 | "kind" : "remoteSourceControl",
15 | "location" : "https://github.com/swiftlang/swift-syntax",
16 | "state" : {
17 | "revision" : "0687f71944021d616d34d922343dcef086855920",
18 | "version" : "600.0.1"
19 | }
20 | }
21 | ],
22 | "version" : 3
23 | }
24 |
--------------------------------------------------------------------------------
/Examples/Multithreading/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.10
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Example",
7 | platforms: [.macOS("15"), .iOS("18"), .watchOS("11"), .tvOS("18"), .visionOS("2")],
8 | dependencies: [
9 | .package(path: "../../"),
10 | .package(
11 | url: "https://github.com/kateinoigakukun/chibi-ray",
12 | revision: "c8cab621a3338dd2f8e817d3785362409d3b8cf1"
13 | ),
14 | ],
15 | targets: [
16 | .executableTarget(
17 | name: "MyApp",
18 | dependencies: [
19 | .product(name: "JavaScriptKit", package: "JavaScriptKit"),
20 | .product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
21 | .product(name: "ChibiRay", package: "chibi-ray"),
22 | ]
23 | )
24 | ]
25 | )
26 |
--------------------------------------------------------------------------------
/Examples/Multithreading/README.md:
--------------------------------------------------------------------------------
1 | # Multithreading example
2 |
3 | Install Development Snapshot toolchain `DEVELOPMENT-SNAPSHOT-2024-07-08-a` or later from [swift.org/install](https://www.swift.org/install/) and run the following commands:
4 |
5 | ```sh
6 | $ (
7 | set -eo pipefail; \
8 | V="$(swiftc --version | head -n1)"; \
9 | TAG="$(curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/tag-by-version.json" | jq -e -r --arg v "$V" '.[$v] | .[-1]')"; \
10 | curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/builds/$TAG.json" | \
11 | jq -r '.["swift-sdks"]["wasm32-unknown-wasip1-threads"] | "swift sdk install \"\(.url)\" --checksum \"\(.checksum)\""' | sh -x
12 | )
13 | $ export SWIFT_SDK_ID=$(
14 | V="$(swiftc --version | head -n1)"; \
15 | TAG="$(curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/tag-by-version.json" | jq -e -r --arg v "$V" '.[$v] | .[-1]')"; \
16 | curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/builds/$TAG.json" | \
17 | jq -r '.["swift-sdks"]["wasm32-unknown-wasip1-threads"]["id"]'
18 | )
19 | $ ./build.sh
20 | $ npx serve
21 | ```
22 |
--------------------------------------------------------------------------------
/Examples/Multithreading/build.sh:
--------------------------------------------------------------------------------
1 | swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}" -c release \
2 | plugin --allow-writing-to-package-directory \
3 | js --use-cdn --output ./Bundle
4 |
--------------------------------------------------------------------------------
/Examples/Multithreading/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Threading Example
6 |
13 |
27 |
28 |
29 |
30 |
34 | Threading Example
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
🧵
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/Examples/Multithreading/serve.json:
--------------------------------------------------------------------------------
1 | {
2 | "headers": [{
3 | "source": "**/*",
4 | "headers": [
5 | {
6 | "key": "Cross-Origin-Embedder-Policy",
7 | "value": "require-corp"
8 | }, {
9 | "key": "Cross-Origin-Opener-Policy",
10 | "value": "same-origin"
11 | }
12 | ]
13 | }]
14 | }
15 |
--------------------------------------------------------------------------------
/Examples/OffscrenCanvas/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.10
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Example",
7 | platforms: [.macOS("15"), .iOS("18"), .watchOS("11"), .tvOS("18"), .visionOS("2")],
8 | dependencies: [
9 | .package(path: "../../")
10 | ],
11 | targets: [
12 | .executableTarget(
13 | name: "MyApp",
14 | dependencies: [
15 | .product(name: "JavaScriptKit", package: "JavaScriptKit"),
16 | .product(name: "JavaScriptEventLoop", package: "JavaScriptKit"),
17 | ]
18 | )
19 | ]
20 | )
21 |
--------------------------------------------------------------------------------
/Examples/OffscrenCanvas/README.md:
--------------------------------------------------------------------------------
1 | # OffscreenCanvas example
2 |
3 | Install Development Snapshot toolchain `DEVELOPMENT-SNAPSHOT-2024-07-08-a` or later from [swift.org/install](https://www.swift.org/install/) and run the following commands:
4 |
5 | ```sh
6 | $ (
7 | set -eo pipefail; \
8 | V="$(swiftc --version | head -n1)"; \
9 | TAG="$(curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/tag-by-version.json" | jq -e -r --arg v "$V" '.[$v] | .[-1]')"; \
10 | curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/builds/$TAG.json" | \
11 | jq -r '.["swift-sdks"]["wasm32-unknown-wasip1-threads"] | "swift sdk install \"\(.url)\" --checksum \"\(.checksum)\""' | sh -x
12 | )
13 | $ export SWIFT_SDK_ID=$(
14 | V="$(swiftc --version | head -n1)"; \
15 | TAG="$(curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/tag-by-version.json" | jq -e -r --arg v "$V" '.[$v] | .[-1]')"; \
16 | curl -sL "https://raw.githubusercontent.com/swiftwasm/swift-sdk-index/refs/heads/main/v1/builds/$TAG.json" | \
17 | jq -r '.["swift-sdks"]["wasm32-unknown-wasip1-threads"]["id"]'
18 | )
19 | $ ./build.sh
20 | $ npx serve
21 | ```
22 |
--------------------------------------------------------------------------------
/Examples/OffscrenCanvas/build.sh:
--------------------------------------------------------------------------------
1 | swift package --swift-sdk "${SWIFT_SDK_ID:-wasm32-unknown-wasip1-threads}" -c release \
2 | plugin --allow-writing-to-package-directory \
3 | js --use-cdn --output ./Bundle
4 |
--------------------------------------------------------------------------------
/Examples/OffscrenCanvas/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OffscreenCanvas Example
6 |
68 |
69 |
70 |
71 |
75 | OffscreenCanvas Example
76 |
77 |
78 |
82 |
83 |
84 |
85 |
86 |
87 | CSS Animation (Main Thread Performance Indicator)
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | FPS: 0
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Examples/OffscrenCanvas/serve.json:
--------------------------------------------------------------------------------
1 | {
2 | "headers": [{
3 | "source": "**/*",
4 | "headers": [
5 | {
6 | "key": "Cross-Origin-Embedder-Policy",
7 | "value": "require-corp"
8 | }, {
9 | "key": "Cross-Origin-Opener-Policy",
10 | "value": "same-origin"
11 | }
12 | ]
13 | }]
14 | }
15 |
--------------------------------------------------------------------------------
/Examples/Testing/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Counter",
7 | products: [
8 | .library(
9 | name: "Counter",
10 | targets: ["Counter"]
11 | )
12 | ],
13 | dependencies: [.package(name: "JavaScriptKit", path: "../../")],
14 | targets: [
15 | .target(
16 | name: "Counter",
17 | dependencies: [
18 | .product(name: "JavaScriptKit", package: "JavaScriptKit")
19 | ]
20 | ),
21 | .testTarget(
22 | name: "CounterTests",
23 | dependencies: [
24 | "Counter",
25 | // This is needed to run the tests in the JavaScript event loop
26 | .product(name: "JavaScriptEventLoopTestSupport", package: "JavaScriptKit"),
27 | ]
28 | ),
29 | ]
30 | )
31 |
--------------------------------------------------------------------------------
/Examples/Testing/README.md:
--------------------------------------------------------------------------------
1 | # Testing example
2 |
3 | This example demonstrates how to write and run tests for Swift code compiled to WebAssembly using JavaScriptKit.
4 |
5 | ## Running Tests
6 |
7 | To run the tests, use the following command:
8 |
9 | ```console
10 | swift package --disable-sandbox --swift-sdk wasm32-unknown-wasi js test
11 | ```
12 |
13 | ## Code Coverage
14 |
15 | To generate and view code coverage reports:
16 |
17 | 1. Run tests with code coverage enabled:
18 |
19 | ```console
20 | swift package --disable-sandbox --swift-sdk wasm32-unknown-wasi js test --enable-code-coverage
21 | ```
22 |
23 | 2. Generate HTML coverage report:
24 |
25 | ```console
26 | llvm-cov show -instr-profile=.build/plugins/PackageToJS/outputs/PackageTests/default.profdata --format=html .build/plugins/PackageToJS/outputs/PackageTests/main.wasm -o .build/coverage/html Sources
27 | ```
28 |
29 | 3. Serve and view the coverage report:
30 |
31 | ```console
32 | npx serve .build/coverage/html
33 | ```
34 |
--------------------------------------------------------------------------------
/Examples/Testing/Sources/Counter/Counter.swift:
--------------------------------------------------------------------------------
1 | public struct Counter {
2 | public private(set) var count = 0
3 |
4 | public mutating func increment() {
5 | count += 1
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Examples/Testing/Tests/CounterTests/CounterTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | @testable import Counter
4 |
5 | #if canImport(Testing)
6 | import Testing
7 |
8 | @Test func increment() async throws {
9 | var counter = Counter()
10 | counter.increment()
11 | #expect(counter.count == 1)
12 | }
13 |
14 | @Test func incrementTwice() async throws {
15 | var counter = Counter()
16 | counter.increment()
17 | counter.increment()
18 | #expect(counter.count == 2)
19 | }
20 |
21 | #endif
22 |
23 | class CounterTests: XCTestCase {
24 | func testIncrement() async {
25 | var counter = Counter()
26 | counter.increment()
27 | XCTAssertEqual(counter.count, 1)
28 | }
29 |
30 | func testIncrementTwice() async {
31 | var counter = Counter()
32 | counter.increment()
33 | counter.increment()
34 | XCTAssertEqual(counter.count, 2)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Examples/Testing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "playwright": "^1.52.0"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Yuta Saito
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SWIFT_SDK_ID ?= wasm32-unknown-wasi
2 |
3 | .PHONY: bootstrap
4 | bootstrap:
5 | npm ci
6 |
7 | .PHONY: unittest
8 | unittest:
9 | @echo Running unit tests
10 | env JAVASCRIPTKIT_EXPERIMENTAL_BRIDGEJS=1 swift package --swift-sdk "$(SWIFT_SDK_ID)" \
11 | --disable-sandbox \
12 | -Xlinker --stack-first \
13 | -Xlinker --global-base=524288 \
14 | -Xlinker -z \
15 | -Xlinker stack-size=524288 \
16 | js test --prelude ./Tests/prelude.mjs
17 |
18 | .PHONY: regenerate_swiftpm_resources
19 | regenerate_swiftpm_resources:
20 | npm run build
21 | cp Runtime/lib/index.mjs Plugins/PackageToJS/Templates/runtime.mjs
22 | cp Runtime/lib/index.d.ts Plugins/PackageToJS/Templates/runtime.d.ts
23 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "BridgeJS",
7 | platforms: [.macOS(.v13)],
8 | dependencies: [
9 | .package(url: "https://github.com/swiftlang/swift-syntax", from: "600.0.1")
10 | ],
11 | targets: [
12 | .target(name: "BridgeJSBuildPlugin"),
13 | .target(name: "BridgeJSLink"),
14 | .executableTarget(
15 | name: "BridgeJSTool",
16 | dependencies: [
17 | .product(name: "SwiftParser", package: "swift-syntax"),
18 | .product(name: "SwiftSyntax", package: "swift-syntax"),
19 | .product(name: "SwiftBasicFormat", package: "swift-syntax"),
20 | .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
21 | ]
22 | ),
23 | .testTarget(
24 | name: "BridgeJSToolTests",
25 | dependencies: ["BridgeJSTool", "BridgeJSLink"],
26 | exclude: ["__Snapshots__", "Inputs"]
27 | ),
28 | ]
29 | )
30 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSSkeleton:
--------------------------------------------------------------------------------
1 | ../BridgeJSSkeleton
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift:
--------------------------------------------------------------------------------
1 | // This file is shared between BridgeTool and BridgeJSLink
2 |
3 | // MARK: - Types
4 |
5 | enum BridgeType: Codable, Equatable {
6 | case int, float, double, string, bool, jsObject(String?), swiftHeapObject(String), void
7 | }
8 |
9 | enum WasmCoreType: String, Codable {
10 | case i32, i64, f32, f64, pointer
11 | }
12 |
13 | struct Parameter: Codable {
14 | let label: String?
15 | let name: String
16 | let type: BridgeType
17 | }
18 |
19 | // MARK: - Exported Skeleton
20 |
21 | struct ExportedFunction: Codable {
22 | var name: String
23 | var abiName: String
24 | var parameters: [Parameter]
25 | var returnType: BridgeType
26 | }
27 |
28 | struct ExportedClass: Codable {
29 | var name: String
30 | var constructor: ExportedConstructor?
31 | var methods: [ExportedFunction]
32 | }
33 |
34 | struct ExportedConstructor: Codable {
35 | var abiName: String
36 | var parameters: [Parameter]
37 | }
38 |
39 | struct ExportedSkeleton: Codable {
40 | let functions: [ExportedFunction]
41 | let classes: [ExportedClass]
42 | }
43 |
44 | // MARK: - Imported Skeleton
45 |
46 | struct ImportedFunctionSkeleton: Codable {
47 | let name: String
48 | let parameters: [Parameter]
49 | let returnType: BridgeType
50 | let documentation: String?
51 |
52 | func abiName(context: ImportedTypeSkeleton?) -> String {
53 | return context.map { "bjs_\($0.name)_\(name)" } ?? "bjs_\(name)"
54 | }
55 | }
56 |
57 | struct ImportedConstructorSkeleton: Codable {
58 | let parameters: [Parameter]
59 |
60 | func abiName(context: ImportedTypeSkeleton) -> String {
61 | return "bjs_\(context.name)_init"
62 | }
63 | }
64 |
65 | struct ImportedPropertySkeleton: Codable {
66 | let name: String
67 | let isReadonly: Bool
68 | let type: BridgeType
69 | let documentation: String?
70 |
71 | func getterAbiName(context: ImportedTypeSkeleton) -> String {
72 | return "bjs_\(context.name)_\(name)_get"
73 | }
74 |
75 | func setterAbiName(context: ImportedTypeSkeleton) -> String {
76 | return "bjs_\(context.name)_\(name)_set"
77 | }
78 | }
79 |
80 | struct ImportedTypeSkeleton: Codable {
81 | let name: String
82 | let constructor: ImportedConstructorSkeleton?
83 | let methods: [ImportedFunctionSkeleton]
84 | let properties: [ImportedPropertySkeleton]
85 | let documentation: String?
86 | }
87 |
88 | struct ImportedFileSkeleton: Codable {
89 | let functions: [ImportedFunctionSkeleton]
90 | let types: [ImportedTypeSkeleton]
91 | }
92 |
93 | struct ImportedModuleSkeleton: Codable {
94 | let moduleName: String
95 | var children: [ImportedFileSkeleton]
96 | }
97 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/BridgeJSTool/BridgeJSSkeleton:
--------------------------------------------------------------------------------
1 | ../BridgeJSSkeleton
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/BridgeJSTool/DiagnosticError.swift:
--------------------------------------------------------------------------------
1 | import SwiftSyntax
2 |
3 | struct DiagnosticError: Error {
4 | let node: Syntax
5 | let message: String
6 | let hint: String?
7 |
8 | init(node: some SyntaxProtocol, message: String, hint: String? = nil) {
9 | self.node = Syntax(node)
10 | self.message = message
11 | self.hint = hint
12 | }
13 |
14 | func formattedDescription(fileName: String) -> String {
15 | let locationConverter = SourceLocationConverter(fileName: fileName, tree: node.root)
16 | let location = locationConverter.location(for: node.position)
17 | var description = "\(fileName):\(location.line):\(location.column): error: \(message)"
18 | if let hint {
19 | description += "\nHint: \(hint)"
20 | }
21 | return description
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/JavaScript/README.md:
--------------------------------------------------------------------------------
1 | # ts2skeleton
2 |
3 | This script analyzes the TypeScript type definitions and produces a structured JSON output with skeleton information that can be used to generate Swift bindings.
4 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/JavaScript/bin/ts2skeleton.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // @ts-check
3 |
4 | /**
5 | * Main entry point for the ts2skeleton tool
6 | *
7 | * This script analyzes the TypeScript type definitions and produces a structured
8 | * JSON output with skeleton information that can be used to generate Swift
9 | * bindings.
10 | */
11 |
12 | import { main } from "../src/cli.js"
13 |
14 | main(process.argv.slice(2));
15 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/JavaScript/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "dependencies": {
4 | "typescript": "5.8.2"
5 | },
6 | "bin": {
7 | "ts2skeleton": "./bin/ts2skeleton.js"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Sources/JavaScript/src/index.d.ts:
--------------------------------------------------------------------------------
1 | export type BridgeType =
2 | | { "int": {} }
3 | | { "float": {} }
4 | | { "double": {} }
5 | | { "string": {} }
6 | | { "bool": {} }
7 | | { "jsObject": { "_0": string } | {} }
8 | | { "void": {} }
9 |
10 | export type Parameter = {
11 | name: string;
12 | type: BridgeType;
13 | }
14 |
15 | export type ImportFunctionSkeleton = {
16 | name: string;
17 | parameters: Parameter[];
18 | returnType: BridgeType;
19 | documentation: string | undefined;
20 | }
21 |
22 | export type ImportConstructorSkeleton = {
23 | parameters: Parameter[];
24 | }
25 |
26 | export type ImportPropertySkeleton = {
27 | name: string;
28 | type: BridgeType;
29 | isReadonly: boolean;
30 | documentation: string | undefined;
31 | }
32 |
33 | export type ImportTypeSkeleton = {
34 | name: string;
35 | documentation: string | undefined;
36 | constructor?: ImportConstructorSkeleton;
37 | properties: ImportPropertySkeleton[];
38 | methods: ImportFunctionSkeleton[];
39 | }
40 |
41 | export type ImportSkeleton = {
42 | functions: ImportFunctionSkeleton[];
43 | types: ImportTypeSkeleton[];
44 | }
45 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/ExportSwiftTests.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import SwiftSyntax
3 | import SwiftParser
4 | import Testing
5 |
6 | @testable import BridgeJSTool
7 |
8 | @Suite struct ExportSwiftTests {
9 | private func snapshot(
10 | swiftAPI: ExportSwift,
11 | name: String? = nil,
12 | filePath: String = #filePath,
13 | function: String = #function,
14 | sourceLocation: Testing.SourceLocation = #_sourceLocation
15 | ) throws {
16 | let (outputSwift, outputSkeleton) = try #require(try swiftAPI.finalize())
17 | try assertSnapshot(
18 | name: name,
19 | filePath: filePath,
20 | function: function,
21 | sourceLocation: sourceLocation,
22 | input: outputSwift.data(using: .utf8)!,
23 | fileExtension: "swift"
24 | )
25 | let encoder = JSONEncoder()
26 | encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
27 | let outputSkeletonData = try encoder.encode(outputSkeleton)
28 | try assertSnapshot(
29 | name: name,
30 | filePath: filePath,
31 | function: function,
32 | sourceLocation: sourceLocation,
33 | input: outputSkeletonData,
34 | fileExtension: "json"
35 | )
36 | }
37 |
38 | static let inputsDirectory = URL(fileURLWithPath: #filePath).deletingLastPathComponent().appendingPathComponent(
39 | "Inputs"
40 | )
41 |
42 | static func collectInputs() -> [String] {
43 | let fileManager = FileManager.default
44 | let inputs = try! fileManager.contentsOfDirectory(atPath: Self.inputsDirectory.path)
45 | return inputs.filter { $0.hasSuffix(".swift") }
46 | }
47 |
48 | @Test(arguments: collectInputs())
49 | func snapshot(input: String) throws {
50 | let swiftAPI = ExportSwift(progress: .silent)
51 | let url = Self.inputsDirectory.appendingPathComponent(input)
52 | let sourceFile = Parser.parse(source: try String(contentsOf: url, encoding: .utf8))
53 | try swiftAPI.addSourceFile(sourceFile, input)
54 | let name = url.deletingPathExtension().lastPathComponent
55 | try snapshot(swiftAPI: swiftAPI, name: name)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/ImportTSTests.swift:
--------------------------------------------------------------------------------
1 | import Testing
2 | import Foundation
3 | @testable import BridgeJSTool
4 |
5 | @Suite struct ImportTSTests {
6 | static let inputsDirectory = URL(fileURLWithPath: #filePath).deletingLastPathComponent().appendingPathComponent(
7 | "Inputs"
8 | )
9 |
10 | static func collectInputs() -> [String] {
11 | let fileManager = FileManager.default
12 | let inputs = try! fileManager.contentsOfDirectory(atPath: Self.inputsDirectory.path)
13 | return inputs.filter { $0.hasSuffix(".d.ts") }
14 | }
15 |
16 | @Test(arguments: collectInputs())
17 | func snapshot(input: String) throws {
18 | var api = ImportTS(progress: .silent, moduleName: "Check")
19 | let url = Self.inputsDirectory.appendingPathComponent(input)
20 | let tsconfigPath = url.deletingLastPathComponent().appendingPathComponent("tsconfig.json")
21 | try api.addSourceFile(url.path, tsconfigPath: tsconfigPath.path)
22 | let outputSwift = try #require(try api.finalize())
23 | let name = url.deletingPathExtension().deletingPathExtension().deletingPathExtension().lastPathComponent
24 | try assertSnapshot(
25 | name: name,
26 | filePath: #filePath,
27 | function: #function,
28 | input: outputSwift.data(using: .utf8)!,
29 | fileExtension: "swift"
30 | )
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/ArrayParameter.d.ts:
--------------------------------------------------------------------------------
1 | export function checkArray(a: number[]): void;
2 | export function checkArrayWithLength(a: number[], b: number): void;
3 | export function checkArray(a: Array): void;
4 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Interface.d.ts:
--------------------------------------------------------------------------------
1 | interface Animatable {
2 | animate(keyframes: any, options: any): any;
3 | getAnimations(options: any): any;
4 | }
5 |
6 | export function returnAnimatable(): Animatable;
7 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/PrimitiveParameters.d.ts:
--------------------------------------------------------------------------------
1 | export function check(a: number, b: boolean): void;
2 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/PrimitiveParameters.swift:
--------------------------------------------------------------------------------
1 | @JS func check(a: Int, b: Float, c: Double, d: Bool) {}
2 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/PrimitiveReturn.d.ts:
--------------------------------------------------------------------------------
1 | export function checkNumber(): number;
2 | export function checkBoolean(): boolean;
3 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/PrimitiveReturn.swift:
--------------------------------------------------------------------------------
1 | @JS func checkInt() -> Int { fatalError() }
2 | @JS func checkFloat() -> Float { fatalError() }
3 | @JS func checkDouble() -> Double { fatalError() }
4 | @JS func checkBool() -> Bool { fatalError() }
5 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/StringParameter.d.ts:
--------------------------------------------------------------------------------
1 | export function checkString(a: string): void;
2 | export function checkStringWithLength(a: string, b: number): void;
3 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/StringParameter.swift:
--------------------------------------------------------------------------------
1 | @JS func checkString(a: String) {}
2 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/StringReturn.d.ts:
--------------------------------------------------------------------------------
1 | export function checkString(): string;
2 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/StringReturn.swift:
--------------------------------------------------------------------------------
1 | @JS func checkString() -> String { fatalError() }
2 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/SwiftClass.swift:
--------------------------------------------------------------------------------
1 | @JS class Greeter {
2 | var name: String
3 |
4 | @JS init(name: String) {
5 | self.name = name
6 | }
7 | @JS func greet() -> String {
8 | return "Hello, " + self.name + "!"
9 | }
10 | @JS func changeName(name: String) {
11 | self.name = name
12 | }
13 | }
14 |
15 | @JS func takeGreeter(greeter: Greeter) {
16 | print(greeter.greet())
17 | }
18 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/TypeAlias.d.ts:
--------------------------------------------------------------------------------
1 | export type MyType = number;
2 |
3 | export function checkSimple(a: MyType): void;
4 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/TypeScriptClass.d.ts:
--------------------------------------------------------------------------------
1 | export class Greeter {
2 | constructor(name: string);
3 | greet(): string;
4 | changeName(name: string): void;
5 | }
6 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/VoidParameterVoidReturn.d.ts:
--------------------------------------------------------------------------------
1 | export function check(): void;
2 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/VoidParameterVoidReturn.swift:
--------------------------------------------------------------------------------
1 | @JS func check() {}
2 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/SnapshotTesting.swift:
--------------------------------------------------------------------------------
1 | import Testing
2 | import Foundation
3 |
4 | func assertSnapshot(
5 | name: String? = nil,
6 | filePath: String = #filePath,
7 | function: String = #function,
8 | sourceLocation: SourceLocation = #_sourceLocation,
9 | variant: String? = nil,
10 | input: Data,
11 | fileExtension: String = "json"
12 | ) throws {
13 | let testFileName = URL(fileURLWithPath: filePath).deletingPathExtension().lastPathComponent
14 | let snapshotDir = URL(fileURLWithPath: filePath)
15 | .deletingLastPathComponent()
16 | .appendingPathComponent("__Snapshots__")
17 | .appendingPathComponent(testFileName)
18 | try FileManager.default.createDirectory(at: snapshotDir, withIntermediateDirectories: true)
19 | let snapshotName = name ?? String(function[.. Comment {
28 | "Snapshot mismatch: \(actualFilePath) \(snapshotPath.path)"
29 | }
30 | if !ok {
31 | try input.write(to: URL(fileURLWithPath: actualFilePath))
32 | }
33 | if ProcessInfo.processInfo.environment["UPDATE_SNAPSHOTS"] == nil {
34 | #expect(ok, buildComment(), sourceLocation: sourceLocation)
35 | } else {
36 | try input.write(to: snapshotPath)
37 | }
38 | } else {
39 | try input.write(to: snapshotPath)
40 | #expect(Bool(false), "Snapshot created at \(snapshotPath.path)", sourceLocation: sourceLocation)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/TemporaryDirectory.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct MakeTemporaryDirectoryError: Error {
4 | let error: CInt
5 | }
6 |
7 | internal func withTemporaryDirectory(body: (URL, _ retain: inout Bool) throws -> T) throws -> T {
8 | // Create a temporary directory using mkdtemp
9 | var template = FileManager.default.temporaryDirectory.appendingPathComponent("PackageToJSTests.XXXXXX").path
10 | return try template.withUTF8 { template in
11 | let copy = UnsafeMutableBufferPointer.allocate(capacity: template.count + 1)
12 | template.copyBytes(to: copy)
13 | copy[template.count] = 0
14 |
15 | guard let result = mkdtemp(copy.baseAddress!) else {
16 | throw MakeTemporaryDirectoryError(error: errno)
17 | }
18 | let tempDir = URL(fileURLWithPath: String(cString: result))
19 | var retain = false
20 | defer {
21 | if !retain {
22 | try? FileManager.default.removeItem(at: tempDir)
23 | }
24 | }
25 | return try body(tempDir, &retain)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | checkArray(a: any): void;
11 | checkArrayWithLength(a: any, b: number): void;
12 | checkArray(a: any): void;
13 | }
14 | export function createInstantiator(options: {
15 | imports: Imports;
16 | }, swift: any): Promise<{
17 | addImports: (importObject: WebAssembly.Imports) => void;
18 | setInstance: (instance: WebAssembly.Instance) => void;
19 | createExports: (instance: WebAssembly.Instance) => Exports;
20 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_checkArray"] = function bjs_checkArray(a) {
40 | options.imports.checkArray(swift.memory.getObject(a));
41 | }
42 | TestModule["bjs_checkArrayWithLength"] = function bjs_checkArrayWithLength(a, b) {
43 | options.imports.checkArrayWithLength(swift.memory.getObject(a), b);
44 | }
45 | TestModule["bjs_checkArray"] = function bjs_checkArray(a) {
46 | options.imports.checkArray(swift.memory.getObject(a));
47 | }
48 | },
49 | setInstance: (i) => {
50 | instance = i;
51 | memory = instance.exports.memory;
52 | },
53 | /** @param {WebAssembly.Instance} instance */
54 | createExports: (instance) => {
55 | const js = swift.memory.heap;
56 |
57 | return {
58 |
59 | };
60 | },
61 | }
62 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | returnAnimatable(): any;
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_returnAnimatable"] = function bjs_returnAnimatable() {
40 | let ret = options.imports.returnAnimatable();
41 | return swift.memory.retain(ret);
42 | }
43 | TestModule["bjs_Animatable_animate"] = function bjs_Animatable_animate(self, keyframes, options) {
44 | let ret = swift.memory.getObject(self).animate(swift.memory.getObject(keyframes), swift.memory.getObject(options));
45 | return swift.memory.retain(ret);
46 | }
47 | TestModule["bjs_Animatable_getAnimations"] = function bjs_Animatable_getAnimations(self, options) {
48 | let ret = swift.memory.getObject(self).getAnimations(swift.memory.getObject(options));
49 | return swift.memory.retain(ret);
50 | }
51 | },
52 | setInstance: (i) => {
53 | instance = i;
54 | memory = instance.exports.memory;
55 | },
56 | /** @param {WebAssembly.Instance} instance */
57 | createExports: (instance) => {
58 | const js = swift.memory.heap;
59 |
60 | return {
61 |
62 | };
63 | },
64 | }
65 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | check(a: number, b: number, c: number, d: boolean): void;
9 | }
10 | export type Imports = {
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 |
39 | },
40 | setInstance: (i) => {
41 | instance = i;
42 | memory = instance.exports.memory;
43 | },
44 | /** @param {WebAssembly.Instance} instance */
45 | createExports: (instance) => {
46 | const js = swift.memory.heap;
47 |
48 | return {
49 | check: function bjs_check(a, b, c, d) {
50 | instance.exports.bjs_check(a, b, c, d);
51 | },
52 | };
53 | },
54 | }
55 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | check(a: number, b: boolean): void;
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_check"] = function bjs_check(a, b) {
40 | options.imports.check(a, b);
41 | }
42 | },
43 | setInstance: (i) => {
44 | instance = i;
45 | memory = instance.exports.memory;
46 | },
47 | /** @param {WebAssembly.Instance} instance */
48 | createExports: (instance) => {
49 | const js = swift.memory.heap;
50 |
51 | return {
52 |
53 | };
54 | },
55 | }
56 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | checkInt(): number;
9 | checkFloat(): number;
10 | checkDouble(): number;
11 | checkBool(): boolean;
12 | }
13 | export type Imports = {
14 | }
15 | export function createInstantiator(options: {
16 | imports: Imports;
17 | }, swift: any): Promise<{
18 | addImports: (importObject: WebAssembly.Imports) => void;
19 | setInstance: (instance: WebAssembly.Instance) => void;
20 | createExports: (instance: WebAssembly.Instance) => Exports;
21 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 |
39 | },
40 | setInstance: (i) => {
41 | instance = i;
42 | memory = instance.exports.memory;
43 | },
44 | /** @param {WebAssembly.Instance} instance */
45 | createExports: (instance) => {
46 | const js = swift.memory.heap;
47 |
48 | return {
49 | checkInt: function bjs_checkInt() {
50 | const ret = instance.exports.bjs_checkInt();
51 | return ret;
52 | },
53 | checkFloat: function bjs_checkFloat() {
54 | const ret = instance.exports.bjs_checkFloat();
55 | return ret;
56 | },
57 | checkDouble: function bjs_checkDouble() {
58 | const ret = instance.exports.bjs_checkDouble();
59 | return ret;
60 | },
61 | checkBool: function bjs_checkBool() {
62 | const ret = instance.exports.bjs_checkBool() !== 0;
63 | return ret;
64 | },
65 | };
66 | },
67 | }
68 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | checkNumber(): number;
11 | checkBoolean(): boolean;
12 | }
13 | export function createInstantiator(options: {
14 | imports: Imports;
15 | }, swift: any): Promise<{
16 | addImports: (importObject: WebAssembly.Imports) => void;
17 | setInstance: (instance: WebAssembly.Instance) => void;
18 | createExports: (instance: WebAssembly.Instance) => Exports;
19 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_checkNumber"] = function bjs_checkNumber() {
40 | let ret = options.imports.checkNumber();
41 | return ret;
42 | }
43 | TestModule["bjs_checkBoolean"] = function bjs_checkBoolean() {
44 | let ret = options.imports.checkBoolean();
45 | return ret !== 0;
46 | }
47 | },
48 | setInstance: (i) => {
49 | instance = i;
50 | memory = instance.exports.memory;
51 | },
52 | /** @param {WebAssembly.Instance} instance */
53 | createExports: (instance) => {
54 | const js = swift.memory.heap;
55 |
56 | return {
57 |
58 | };
59 | },
60 | }
61 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | checkString(a: string): void;
9 | }
10 | export type Imports = {
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 |
39 | },
40 | setInstance: (i) => {
41 | instance = i;
42 | memory = instance.exports.memory;
43 | },
44 | /** @param {WebAssembly.Instance} instance */
45 | createExports: (instance) => {
46 | const js = swift.memory.heap;
47 |
48 | return {
49 | checkString: function bjs_checkString(a) {
50 | const aBytes = textEncoder.encode(a);
51 | const aId = swift.memory.retain(aBytes);
52 | instance.exports.bjs_checkString(aId, aBytes.length);
53 | swift.memory.release(aId);
54 | },
55 | };
56 | },
57 | }
58 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | checkString(a: string): void;
11 | checkStringWithLength(a: string, b: number): void;
12 | }
13 | export function createInstantiator(options: {
14 | imports: Imports;
15 | }, swift: any): Promise<{
16 | addImports: (importObject: WebAssembly.Imports) => void;
17 | setInstance: (instance: WebAssembly.Instance) => void;
18 | createExports: (instance: WebAssembly.Instance) => Exports;
19 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_checkString"] = function bjs_checkString(a) {
40 | const aObject = swift.memory.getObject(a);
41 | swift.memory.release(a);
42 | options.imports.checkString(aObject);
43 | }
44 | TestModule["bjs_checkStringWithLength"] = function bjs_checkStringWithLength(a, b) {
45 | const aObject = swift.memory.getObject(a);
46 | swift.memory.release(a);
47 | options.imports.checkStringWithLength(aObject, b);
48 | }
49 | },
50 | setInstance: (i) => {
51 | instance = i;
52 | memory = instance.exports.memory;
53 | },
54 | /** @param {WebAssembly.Instance} instance */
55 | createExports: (instance) => {
56 | const js = swift.memory.heap;
57 |
58 | return {
59 |
60 | };
61 | },
62 | }
63 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | checkString(): string;
9 | }
10 | export type Imports = {
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 |
39 | },
40 | setInstance: (i) => {
41 | instance = i;
42 | memory = instance.exports.memory;
43 | },
44 | /** @param {WebAssembly.Instance} instance */
45 | createExports: (instance) => {
46 | const js = swift.memory.heap;
47 |
48 | return {
49 | checkString: function bjs_checkString() {
50 | instance.exports.bjs_checkString();
51 | const ret = tmpRetString;
52 | tmpRetString = undefined;
53 | return ret;
54 | },
55 | };
56 | },
57 | }
58 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | checkString(): string;
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_checkString"] = function bjs_checkString() {
40 | let ret = options.imports.checkString();
41 | tmpRetBytes = textEncoder.encode(ret);
42 | return tmpRetBytes.length;
43 | }
44 | },
45 | setInstance: (i) => {
46 | instance = i;
47 | memory = instance.exports.memory;
48 | },
49 | /** @param {WebAssembly.Instance} instance */
50 | createExports: (instance) => {
51 | const js = swift.memory.heap;
52 |
53 | return {
54 |
55 | };
56 | },
57 | }
58 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.d.ts:
--------------------------------------------------------------------------------
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 | /// Represents a Swift heap object like a class instance or an actor instance.
8 | export interface SwiftHeapObject {
9 | /// Release the heap object.
10 | ///
11 | /// Note: Calling this method will release the heap object and it will no longer be accessible.
12 | release(): void;
13 | }
14 | export interface Greeter extends SwiftHeapObject {
15 | greet(): string;
16 | changeName(name: string): void;
17 | }
18 | export type Exports = {
19 | Greeter: {
20 | new(name: string): Greeter;
21 | }
22 | takeGreeter(greeter: Greeter): void;
23 | }
24 | export type Imports = {
25 | }
26 | export function createInstantiator(options: {
27 | imports: Imports;
28 | }, swift: any): Promise<{
29 | addImports: (importObject: WebAssembly.Imports) => void;
30 | setInstance: (instance: WebAssembly.Instance) => void;
31 | createExports: (instance: WebAssembly.Instance) => Exports;
32 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | checkSimple(a: number): void;
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_checkSimple"] = function bjs_checkSimple(a) {
40 | options.imports.checkSimple(a);
41 | }
42 | },
43 | setInstance: (i) => {
44 | instance = i;
45 | memory = instance.exports.memory;
46 | },
47 | /** @param {WebAssembly.Instance} instance */
48 | createExports: (instance) => {
49 | const js = swift.memory.heap;
50 |
51 | return {
52 |
53 | };
54 | },
55 | }
56 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | }
11 | export function createInstantiator(options: {
12 | imports: Imports;
13 | }, swift: any): Promise<{
14 | addImports: (importObject: WebAssembly.Imports) => void;
15 | setInstance: (instance: WebAssembly.Instance) => void;
16 | createExports: (instance: WebAssembly.Instance) => Exports;
17 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_Greeter_greet"] = function bjs_Greeter_greet(self) {
40 | let ret = swift.memory.getObject(self).greet();
41 | tmpRetBytes = textEncoder.encode(ret);
42 | return tmpRetBytes.length;
43 | }
44 | TestModule["bjs_Greeter_changeName"] = function bjs_Greeter_changeName(self, name) {
45 | const nameObject = swift.memory.getObject(name);
46 | swift.memory.release(name);
47 | swift.memory.getObject(self).changeName(nameObject);
48 | }
49 | },
50 | setInstance: (i) => {
51 | instance = i;
52 | memory = instance.exports.memory;
53 | },
54 | /** @param {WebAssembly.Instance} instance */
55 | createExports: (instance) => {
56 | const js = swift.memory.heap;
57 |
58 | return {
59 |
60 | };
61 | },
62 | }
63 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | check(): void;
9 | }
10 | export type Imports = {
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 |
39 | },
40 | setInstance: (i) => {
41 | instance = i;
42 | memory = instance.exports.memory;
43 | },
44 | /** @param {WebAssembly.Instance} instance */
45 | createExports: (instance) => {
46 | const js = swift.memory.heap;
47 |
48 | return {
49 | check: function bjs_check() {
50 | instance.exports.bjs_check();
51 | },
52 | };
53 | },
54 | }
55 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.d.ts:
--------------------------------------------------------------------------------
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 type Exports = {
8 | }
9 | export type Imports = {
10 | check(): void;
11 | }
12 | export function createInstantiator(options: {
13 | imports: Imports;
14 | }, swift: any): Promise<{
15 | addImports: (importObject: WebAssembly.Imports) => void;
16 | setInstance: (instance: WebAssembly.Instance) => void;
17 | createExports: (instance: WebAssembly.Instance) => Exports;
18 | }>;
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js:
--------------------------------------------------------------------------------
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 async function createInstantiator(options, swift) {
8 | let instance;
9 | let memory;
10 | const textDecoder = new TextDecoder("utf-8");
11 | const textEncoder = new TextEncoder("utf-8");
12 |
13 | let tmpRetString;
14 | let tmpRetBytes;
15 | return {
16 | /** @param {WebAssembly.Imports} importObject */
17 | addImports: (importObject) => {
18 | const bjs = {};
19 | importObject["bjs"] = bjs;
20 | bjs["return_string"] = function(ptr, len) {
21 | const bytes = new Uint8Array(memory.buffer, ptr, len);
22 | tmpRetString = textDecoder.decode(bytes);
23 | }
24 | bjs["init_memory"] = function(sourceId, bytesPtr) {
25 | const source = swift.memory.getObject(sourceId);
26 | const bytes = new Uint8Array(memory.buffer, bytesPtr);
27 | bytes.set(source);
28 | }
29 | bjs["make_jsstring"] = function(ptr, len) {
30 | const bytes = new Uint8Array(memory.buffer, ptr, len);
31 | return swift.memory.retain(textDecoder.decode(bytes));
32 | }
33 | bjs["init_memory_with_result"] = function(ptr, len) {
34 | const target = new Uint8Array(memory.buffer, ptr, len);
35 | target.set(tmpRetBytes);
36 | tmpRetBytes = undefined;
37 | }
38 | const TestModule = importObject["TestModule"] = {};
39 | TestModule["bjs_check"] = function bjs_check() {
40 | options.imports.check();
41 | }
42 | },
43 | setInstance: (i) => {
44 | instance = i;
45 | memory = instance.exports.memory;
46 | },
47 | /** @param {WebAssembly.Instance} instance */
48 | createExports: (instance) => {
49 | const js = swift.memory.heap;
50 |
51 | return {
52 |
53 | };
54 | },
55 | }
56 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/PrimitiveParameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [
3 |
4 | ],
5 | "functions" : [
6 | {
7 | "abiName" : "bjs_check",
8 | "name" : "check",
9 | "parameters" : [
10 | {
11 | "label" : "a",
12 | "name" : "a",
13 | "type" : {
14 | "int" : {
15 |
16 | }
17 | }
18 | },
19 | {
20 | "label" : "b",
21 | "name" : "b",
22 | "type" : {
23 | "float" : {
24 |
25 | }
26 | }
27 | },
28 | {
29 | "label" : "c",
30 | "name" : "c",
31 | "type" : {
32 | "double" : {
33 |
34 | }
35 | }
36 | },
37 | {
38 | "label" : "d",
39 | "name" : "d",
40 | "type" : {
41 | "bool" : {
42 |
43 | }
44 | }
45 | }
46 | ],
47 | "returnType" : {
48 | "void" : {
49 |
50 | }
51 | }
52 | }
53 | ]
54 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/PrimitiveParameters.swift:
--------------------------------------------------------------------------------
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 | @_extern(wasm, module: "bjs", name: "return_string")
7 | private func _return_string(_ ptr: UnsafePointer?, _ len: Int32)
8 | @_extern(wasm, module: "bjs", name: "init_memory")
9 | private func _init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer?)
10 |
11 | @_expose(wasm, "bjs_check")
12 | @_cdecl("bjs_check")
13 | public func _bjs_check(a: Int32, b: Float32, c: Float64, d: Int32) -> Void {
14 | check(a: Int(a), b: b, c: c, d: d == 1)
15 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/PrimitiveReturn.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [
3 |
4 | ],
5 | "functions" : [
6 | {
7 | "abiName" : "bjs_checkInt",
8 | "name" : "checkInt",
9 | "parameters" : [
10 |
11 | ],
12 | "returnType" : {
13 | "int" : {
14 |
15 | }
16 | }
17 | },
18 | {
19 | "abiName" : "bjs_checkFloat",
20 | "name" : "checkFloat",
21 | "parameters" : [
22 |
23 | ],
24 | "returnType" : {
25 | "float" : {
26 |
27 | }
28 | }
29 | },
30 | {
31 | "abiName" : "bjs_checkDouble",
32 | "name" : "checkDouble",
33 | "parameters" : [
34 |
35 | ],
36 | "returnType" : {
37 | "double" : {
38 |
39 | }
40 | }
41 | },
42 | {
43 | "abiName" : "bjs_checkBool",
44 | "name" : "checkBool",
45 | "parameters" : [
46 |
47 | ],
48 | "returnType" : {
49 | "bool" : {
50 |
51 | }
52 | }
53 | }
54 | ]
55 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/PrimitiveReturn.swift:
--------------------------------------------------------------------------------
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 | @_extern(wasm, module: "bjs", name: "return_string")
7 | private func _return_string(_ ptr: UnsafePointer?, _ len: Int32)
8 | @_extern(wasm, module: "bjs", name: "init_memory")
9 | private func _init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer?)
10 |
11 | @_expose(wasm, "bjs_checkInt")
12 | @_cdecl("bjs_checkInt")
13 | public func _bjs_checkInt() -> Int32 {
14 | let ret = checkInt()
15 | return Int32(ret)
16 | }
17 |
18 | @_expose(wasm, "bjs_checkFloat")
19 | @_cdecl("bjs_checkFloat")
20 | public func _bjs_checkFloat() -> Float32 {
21 | let ret = checkFloat()
22 | return Float32(ret)
23 | }
24 |
25 | @_expose(wasm, "bjs_checkDouble")
26 | @_cdecl("bjs_checkDouble")
27 | public func _bjs_checkDouble() -> Float64 {
28 | let ret = checkDouble()
29 | return Float64(ret)
30 | }
31 |
32 | @_expose(wasm, "bjs_checkBool")
33 | @_cdecl("bjs_checkBool")
34 | public func _bjs_checkBool() -> Int32 {
35 | let ret = checkBool()
36 | return Int32(ret ? 1 : 0)
37 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StringParameter.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [
3 |
4 | ],
5 | "functions" : [
6 | {
7 | "abiName" : "bjs_checkString",
8 | "name" : "checkString",
9 | "parameters" : [
10 | {
11 | "label" : "a",
12 | "name" : "a",
13 | "type" : {
14 | "string" : {
15 |
16 | }
17 | }
18 | }
19 | ],
20 | "returnType" : {
21 | "void" : {
22 |
23 | }
24 | }
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StringParameter.swift:
--------------------------------------------------------------------------------
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 | @_extern(wasm, module: "bjs", name: "return_string")
7 | private func _return_string(_ ptr: UnsafePointer?, _ len: Int32)
8 | @_extern(wasm, module: "bjs", name: "init_memory")
9 | private func _init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer?)
10 |
11 | @_expose(wasm, "bjs_checkString")
12 | @_cdecl("bjs_checkString")
13 | public func _bjs_checkString(aBytes: Int32, aLen: Int32) -> Void {
14 | let a = String(unsafeUninitializedCapacity: Int(aLen)) { b in
15 | _init_memory(aBytes, b.baseAddress.unsafelyUnwrapped)
16 | return Int(aLen)
17 | }
18 | checkString(a: a)
19 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StringReturn.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [
3 |
4 | ],
5 | "functions" : [
6 | {
7 | "abiName" : "bjs_checkString",
8 | "name" : "checkString",
9 | "parameters" : [
10 |
11 | ],
12 | "returnType" : {
13 | "string" : {
14 |
15 | }
16 | }
17 | }
18 | ]
19 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StringReturn.swift:
--------------------------------------------------------------------------------
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 | @_extern(wasm, module: "bjs", name: "return_string")
7 | private func _return_string(_ ptr: UnsafePointer?, _ len: Int32)
8 | @_extern(wasm, module: "bjs", name: "init_memory")
9 | private func _init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer?)
10 |
11 | @_expose(wasm, "bjs_checkString")
12 | @_cdecl("bjs_checkString")
13 | public func _bjs_checkString() -> Void {
14 | var ret = checkString()
15 | return ret.withUTF8 { ptr in
16 | _return_string(ptr.baseAddress, Int32(ptr.count))
17 | }
18 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClass.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [
3 | {
4 | "constructor" : {
5 | "abiName" : "bjs_Greeter_init",
6 | "parameters" : [
7 | {
8 | "label" : "name",
9 | "name" : "name",
10 | "type" : {
11 | "string" : {
12 |
13 | }
14 | }
15 | }
16 | ]
17 | },
18 | "methods" : [
19 | {
20 | "abiName" : "bjs_Greeter_greet",
21 | "name" : "greet",
22 | "parameters" : [
23 |
24 | ],
25 | "returnType" : {
26 | "string" : {
27 |
28 | }
29 | }
30 | },
31 | {
32 | "abiName" : "bjs_Greeter_changeName",
33 | "name" : "changeName",
34 | "parameters" : [
35 | {
36 | "label" : "name",
37 | "name" : "name",
38 | "type" : {
39 | "string" : {
40 |
41 | }
42 | }
43 | }
44 | ],
45 | "returnType" : {
46 | "void" : {
47 |
48 | }
49 | }
50 | }
51 | ],
52 | "name" : "Greeter"
53 | }
54 | ],
55 | "functions" : [
56 | {
57 | "abiName" : "bjs_takeGreeter",
58 | "name" : "takeGreeter",
59 | "parameters" : [
60 | {
61 | "label" : "greeter",
62 | "name" : "greeter",
63 | "type" : {
64 | "swiftHeapObject" : {
65 | "_0" : "Greeter"
66 | }
67 | }
68 | }
69 | ],
70 | "returnType" : {
71 | "void" : {
72 |
73 | }
74 | }
75 | }
76 | ]
77 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/SwiftClass.swift:
--------------------------------------------------------------------------------
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 | @_extern(wasm, module: "bjs", name: "return_string")
7 | private func _return_string(_ ptr: UnsafePointer?, _ len: Int32)
8 | @_extern(wasm, module: "bjs", name: "init_memory")
9 | private func _init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer?)
10 |
11 | @_expose(wasm, "bjs_takeGreeter")
12 | @_cdecl("bjs_takeGreeter")
13 | public func _bjs_takeGreeter(greeter: UnsafeMutableRawPointer) -> Void {
14 | takeGreeter(greeter: Unmanaged.fromOpaque(greeter).takeUnretainedValue())
15 | }
16 |
17 | @_expose(wasm, "bjs_Greeter_init")
18 | @_cdecl("bjs_Greeter_init")
19 | public func _bjs_Greeter_init(nameBytes: Int32, nameLen: Int32) -> UnsafeMutableRawPointer {
20 | let name = String(unsafeUninitializedCapacity: Int(nameLen)) { b in
21 | _init_memory(nameBytes, b.baseAddress.unsafelyUnwrapped)
22 | return Int(nameLen)
23 | }
24 | let ret = Greeter(name: name)
25 | return Unmanaged.passRetained(ret).toOpaque()
26 | }
27 |
28 | @_expose(wasm, "bjs_Greeter_greet")
29 | @_cdecl("bjs_Greeter_greet")
30 | public func _bjs_Greeter_greet(_self: UnsafeMutableRawPointer) -> Void {
31 | var ret = Unmanaged.fromOpaque(_self).takeUnretainedValue().greet()
32 | return ret.withUTF8 { ptr in
33 | _return_string(ptr.baseAddress, Int32(ptr.count))
34 | }
35 | }
36 |
37 | @_expose(wasm, "bjs_Greeter_changeName")
38 | @_cdecl("bjs_Greeter_changeName")
39 | public func _bjs_Greeter_changeName(_self: UnsafeMutableRawPointer, nameBytes: Int32, nameLen: Int32) -> Void {
40 | let name = String(unsafeUninitializedCapacity: Int(nameLen)) { b in
41 | _init_memory(nameBytes, b.baseAddress.unsafelyUnwrapped)
42 | return Int(nameLen)
43 | }
44 | Unmanaged.fromOpaque(_self).takeUnretainedValue().changeName(name: name)
45 | }
46 |
47 | @_expose(wasm, "bjs_Greeter_deinit")
48 | @_cdecl("bjs_Greeter_deinit")
49 | public func _bjs_Greeter_deinit(pointer: UnsafeMutableRawPointer) {
50 | Unmanaged.fromOpaque(pointer).release()
51 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/VoidParameterVoidReturn.json:
--------------------------------------------------------------------------------
1 | {
2 | "classes" : [
3 |
4 | ],
5 | "functions" : [
6 | {
7 | "abiName" : "bjs_check",
8 | "name" : "check",
9 | "parameters" : [
10 |
11 | ],
12 | "returnType" : {
13 | "void" : {
14 |
15 | }
16 | }
17 | }
18 | ]
19 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/VoidParameterVoidReturn.swift:
--------------------------------------------------------------------------------
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 | @_extern(wasm, module: "bjs", name: "return_string")
7 | private func _return_string(_ ptr: UnsafePointer?, _ len: Int32)
8 | @_extern(wasm, module: "bjs", name: "init_memory")
9 | private func _init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer?)
10 |
11 | @_expose(wasm, "bjs_check")
12 | @_cdecl("bjs_check")
13 | public func _bjs_check() -> Void {
14 | check()
15 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/ArrayParameter.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func checkArray(_ a: JSObject) -> Void {
19 | @_extern(wasm, module: "Check", name: "bjs_checkArray")
20 | func bjs_checkArray(_ a: Int32) -> Void
21 | bjs_checkArray(Int32(bitPattern: a.id))
22 | }
23 |
24 | func checkArrayWithLength(_ a: JSObject, _ b: Double) -> Void {
25 | @_extern(wasm, module: "Check", name: "bjs_checkArrayWithLength")
26 | func bjs_checkArrayWithLength(_ a: Int32, _ b: Float64) -> Void
27 | bjs_checkArrayWithLength(Int32(bitPattern: a.id), b)
28 | }
29 |
30 | func checkArray(_ a: JSObject) -> Void {
31 | @_extern(wasm, module: "Check", name: "bjs_checkArray")
32 | func bjs_checkArray(_ a: Int32) -> Void
33 | bjs_checkArray(Int32(bitPattern: a.id))
34 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/Interface.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func returnAnimatable() -> Animatable {
19 | @_extern(wasm, module: "Check", name: "bjs_returnAnimatable")
20 | func bjs_returnAnimatable() -> Int32
21 | let ret = bjs_returnAnimatable()
22 | return Animatable(takingThis: ret)
23 | }
24 |
25 | struct Animatable {
26 | let this: JSObject
27 |
28 | init(this: JSObject) {
29 | self.this = this
30 | }
31 |
32 | init(takingThis this: Int32) {
33 | self.this = JSObject(id: UInt32(bitPattern: this))
34 | }
35 |
36 | func animate(_ keyframes: JSObject, _ options: JSObject) -> JSObject {
37 | @_extern(wasm, module: "Check", name: "bjs_Animatable_animate")
38 | func bjs_Animatable_animate(_ self: Int32, _ keyframes: Int32, _ options: Int32) -> Int32
39 | let ret = bjs_Animatable_animate(Int32(bitPattern: self.this.id), Int32(bitPattern: keyframes.id), Int32(bitPattern: options.id))
40 | return JSObject(id: UInt32(bitPattern: ret))
41 | }
42 |
43 | func getAnimations(_ options: JSObject) -> JSObject {
44 | @_extern(wasm, module: "Check", name: "bjs_Animatable_getAnimations")
45 | func bjs_Animatable_getAnimations(_ self: Int32, _ options: Int32) -> Int32
46 | let ret = bjs_Animatable_getAnimations(Int32(bitPattern: self.this.id), Int32(bitPattern: options.id))
47 | return JSObject(id: UInt32(bitPattern: ret))
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/PrimitiveParameters.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func check(_ a: Double, _ b: Bool) -> Void {
19 | @_extern(wasm, module: "Check", name: "bjs_check")
20 | func bjs_check(_ a: Float64, _ b: Int32) -> Void
21 | bjs_check(a, Int32(b ? 1 : 0))
22 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/PrimitiveReturn.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func checkNumber() -> Double {
19 | @_extern(wasm, module: "Check", name: "bjs_checkNumber")
20 | func bjs_checkNumber() -> Float64
21 | let ret = bjs_checkNumber()
22 | return Double(ret)
23 | }
24 |
25 | func checkBoolean() -> Bool {
26 | @_extern(wasm, module: "Check", name: "bjs_checkBoolean")
27 | func bjs_checkBoolean() -> Int32
28 | let ret = bjs_checkBoolean()
29 | return ret == 1
30 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/StringParameter.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func checkString(_ a: String) -> Void {
19 | @_extern(wasm, module: "Check", name: "bjs_checkString")
20 | func bjs_checkString(_ a: Int32) -> Void
21 | var a = a
22 | let aId = a.withUTF8 { b in
23 | _make_jsstring(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
24 | }
25 | bjs_checkString(aId)
26 | }
27 |
28 | func checkStringWithLength(_ a: String, _ b: Double) -> Void {
29 | @_extern(wasm, module: "Check", name: "bjs_checkStringWithLength")
30 | func bjs_checkStringWithLength(_ a: Int32, _ b: Float64) -> Void
31 | var a = a
32 | let aId = a.withUTF8 { b in
33 | _make_jsstring(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
34 | }
35 | bjs_checkStringWithLength(aId, b)
36 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/StringReturn.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func checkString() -> String {
19 | @_extern(wasm, module: "Check", name: "bjs_checkString")
20 | func bjs_checkString() -> Int32
21 | let ret = bjs_checkString()
22 | return String(unsafeUninitializedCapacity: Int(ret)) { b in
23 | _init_memory_with_result(b.baseAddress.unsafelyUnwrapped, Int32(ret))
24 | return Int(ret)
25 | }
26 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/TypeAlias.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func checkSimple(_ a: Double) -> Void {
19 | @_extern(wasm, module: "Check", name: "bjs_checkSimple")
20 | func bjs_checkSimple(_ a: Float64) -> Void
21 | bjs_checkSimple(a)
22 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/TypeScriptClass.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | struct Greeter {
19 | let this: JSObject
20 |
21 | init(this: JSObject) {
22 | self.this = this
23 | }
24 |
25 | init(takingThis this: Int32) {
26 | self.this = JSObject(id: UInt32(bitPattern: this))
27 | }
28 |
29 | init(_ name: String) {
30 | @_extern(wasm, module: "Check", name: "bjs_Greeter_init")
31 | func bjs_Greeter_init(_ name: Int32) -> Int32
32 | var name = name
33 | let nameId = name.withUTF8 { b in
34 | _make_jsstring(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
35 | }
36 | let ret = bjs_Greeter_init(nameId)
37 | self.this = ret
38 | }
39 |
40 | func greet() -> String {
41 | @_extern(wasm, module: "Check", name: "bjs_Greeter_greet")
42 | func bjs_Greeter_greet(_ self: Int32) -> Int32
43 | let ret = bjs_Greeter_greet(Int32(bitPattern: self.this.id))
44 | return String(unsafeUninitializedCapacity: Int(ret)) { b in
45 | _init_memory_with_result(b.baseAddress.unsafelyUnwrapped, Int32(ret))
46 | return Int(ret)
47 | }
48 | }
49 |
50 | func changeName(_ name: String) -> Void {
51 | @_extern(wasm, module: "Check", name: "bjs_Greeter_changeName")
52 | func bjs_Greeter_changeName(_ self: Int32, _ name: Int32) -> Void
53 | var name = name
54 | let nameId = name.withUTF8 { b in
55 | _make_jsstring(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
56 | }
57 | bjs_Greeter_changeName(Int32(bitPattern: self.this.id), nameId)
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ImportTSTests/VoidParameterVoidReturn.swift:
--------------------------------------------------------------------------------
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 | @_spi(JSObject_id) import JavaScriptKit
8 |
9 | @_extern(wasm, module: "bjs", name: "make_jsstring")
10 | private func _make_jsstring(_ ptr: UnsafePointer?, _ len: Int32) -> Int32
11 |
12 | @_extern(wasm, module: "bjs", name: "init_memory_with_result")
13 | private func _init_memory_with_result(_ ptr: UnsafePointer?, _ len: Int32)
14 |
15 | @_extern(wasm, module: "bjs", name: "free_jsobject")
16 | private func _free_jsobject(_ ptr: Int32) -> Void
17 |
18 | func check() -> Void {
19 | @_extern(wasm, module: "Check", name: "bjs_check")
20 | func bjs_check() -> Void
21 | bjs_check()
22 | }
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Fixtures/ContinuationLeakInTest/SwiftTesting/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "Check",
6 | dependencies: [.package(name: "JavaScriptKit", path: "../../../../../")],
7 | targets: [
8 | .testTarget(
9 | name: "CheckTests",
10 | dependencies: [
11 | "JavaScriptKit",
12 | .product(name: "JavaScriptEventLoopTestSupport", package: "JavaScriptKit"),
13 | ],
14 | path: "Tests"
15 | )
16 | ]
17 | )
18 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Fixtures/ContinuationLeakInTest/SwiftTesting/Tests/CheckTests.swift:
--------------------------------------------------------------------------------
1 | import Testing
2 |
3 | @Test func never() async throws {
4 | let _: Void = await withUnsafeContinuation { _ in }
5 | }
6 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Fixtures/ContinuationLeakInTest/XCTest/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "Check",
6 | dependencies: [.package(name: "JavaScriptKit", path: "../../../../../")],
7 | targets: [
8 | .testTarget(
9 | name: "CheckTests",
10 | dependencies: [
11 | "JavaScriptKit",
12 | .product(name: "JavaScriptEventLoopTestSupport", package: "JavaScriptKit"),
13 | ],
14 | path: "Tests"
15 | )
16 | ]
17 | )
18 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Fixtures/ContinuationLeakInTest/XCTest/Tests/CheckTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | final class CheckTests: XCTestCase {
4 | func testNever() async throws {
5 | let _: Void = await withUnsafeContinuation { _ in }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "PackageToJS",
7 | platforms: [.macOS(.v13)],
8 | targets: [
9 | .target(name: "PackageToJS"),
10 | .testTarget(
11 | name: "PackageToJSTests",
12 | dependencies: ["PackageToJS"],
13 | exclude: ["__Snapshots__"]
14 | ),
15 | ]
16 | )
17 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/README.md:
--------------------------------------------------------------------------------
1 | # PackageToJS
2 |
3 | A Swift Package Manager plugin that facilitates building and packaging Swift WebAssembly applications for JavaScript environments.
4 |
5 | ## Overview
6 |
7 | PackageToJS is a command plugin for Swift Package Manager that simplifies the process of compiling Swift code to WebAssembly and generating the necessary JavaScript bindings. It's an essential tool for SwiftWasm projects, especially those using JavaScriptKit to interact with JavaScript from Swift.
8 |
9 | ## Features
10 |
11 | - Build WebAssembly file and generate JavaScript wrappers
12 | - Test driver for Swift Testing and XCTest
13 | - Generated JS files can be consumed by JS bundler tools like Vite
14 |
15 | ## Requirements
16 |
17 | - Swift 6.0 or later
18 | - A compatible WebAssembly SDK
19 |
20 | ## Relationship with Carton
21 |
22 | PackageToJS is intended to replace Carton by providing a more integrated solution for building and packaging Swift WebAssembly applications. Unlike Carton, which offers a development server and hot-reloading, PackageToJS focuses solely on compilation and JavaScript wrapper generation.
23 |
24 | ## Internal Architecture
25 |
26 | PackageToJS consists of several components:
27 | - `PackageToJSPlugin.swift`: Main entry point for the Swift Package Manager plugin (Note that this file is not included when running unit tests for the plugin)
28 | - `PackageToJS.swift`: Core functionality for building and packaging
29 | - `MiniMake.swift`: Build system utilities
30 | - `ParseWasm.swift`: WebAssembly binary parsing
31 | - `Preprocess.swift`: Preprocessor for `./Templates` files
32 |
33 | ## Internal Testing
34 |
35 | To run the unit tests for the `PackageToJS` plugin, use the following command:
36 |
37 | ```bash
38 | swift test --package-path ./Plugins/PackageToJS
39 | ```
40 |
41 | Please define the following environment variables when you want to run E2E tests:
42 |
43 | - `SWIFT_SDK_ID`: Specifies the Swift SDK identifier to use
44 | - `SWIFT_PATH`: Specifies the `bin` path to the Swift toolchain to use
45 |
46 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Sources/BridgeJSLink:
--------------------------------------------------------------------------------
1 | ../../BridgeJS/Sources/BridgeJSLink
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/index.d.ts:
--------------------------------------------------------------------------------
1 | import type { Exports, Imports, ModuleSource } from './instantiate.js'
2 |
3 | export type Options = {
4 | /**
5 | * The WebAssembly module to instantiate
6 | *
7 | * If not provided, the module will be fetched from the default path.
8 | */
9 | module?: ModuleSource
10 | /* #if HAS_IMPORTS */
11 | /**
12 | * The imports to use for the module
13 | */
14 | imports: Imports
15 | /* #endif */
16 | }
17 |
18 | /**
19 | * Instantiate and initialize the module
20 | *
21 | * This is a convenience function for browser environments.
22 | * If you need a more flexible API, see `instantiate`.
23 | */
24 | export declare function init(options?: Options): Promise<{
25 | instance: WebAssembly.Instance,
26 | exports: Exports
27 | }>
28 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/index.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import { instantiate } from './instantiate.js';
3 | import { defaultBrowserSetup /* #if USE_SHARED_MEMORY */, createDefaultWorkerFactory /* #endif */} from './platforms/browser.js';
4 |
5 | /** @type {import('./index.d').init} */
6 | export async function init(_options) {
7 | /** @type {import('./index.d').Options} */
8 | const options = _options || {
9 | /* #if HAS_IMPORTS */
10 | /** @returns {import('./instantiate.d').Imports} */
11 | get imports() { (() => { throw new Error("No imports provided") })() }
12 | /* #endif */
13 | };
14 | let module = options.module;
15 | if (!module) {
16 | module = fetch(new URL("@PACKAGE_TO_JS_MODULE_PATH@", import.meta.url))
17 | }
18 | const instantiateOptions = await defaultBrowserSetup({
19 | module,
20 | /* #if HAS_IMPORTS */
21 | imports: options.imports,
22 | /* #endif */
23 | /* #if USE_SHARED_MEMORY */
24 | spawnWorker: createDefaultWorkerFactory()
25 | /* #endif */
26 | })
27 | return await instantiate(instantiateOptions);
28 | }
29 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@PACKAGE_TO_JS_PACKAGE_NAME@",
3 | "version": "0.0.0",
4 | "type": "module",
5 | "private": true,
6 | "exports": {
7 | ".": "./index.js",
8 | "./wasm": "./@PACKAGE_TO_JS_MODULE_PATH@"
9 | },
10 | "dependencies": {
11 | "@bjorn3/browser_wasi_shim": "0.3.0"
12 | },
13 | "peerDependencies": {
14 | "playwright": "^1.51.0"
15 | },
16 | "peerDependenciesMeta": {
17 | "playwright": {
18 | "optional": true
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/platforms/browser.d.ts:
--------------------------------------------------------------------------------
1 | import type { InstantiateOptions, ModuleSource/* #if HAS_IMPORTS */, Imports/* #endif */ } from "../instantiate.js"
2 |
3 | export function defaultBrowserSetup(options: {
4 | module: ModuleSource,
5 | /* #if IS_WASI */
6 | args?: string[],
7 | onStdoutLine?: (line: string) => void,
8 | onStderrLine?: (line: string) => void,
9 | /* #endif */
10 | /* #if HAS_IMPORTS */
11 | imports: Imports,
12 | /* #endif */
13 | /* #if USE_SHARED_MEMORY */
14 | spawnWorker: (module: WebAssembly.Module, memory: WebAssembly.Memory, startArg: any) => Worker,
15 | /* #endif */
16 | }): Promise
17 |
18 | export function createDefaultWorkerFactory(preludeScript?: string): (module: WebAssembly.Module, memory: WebAssembly.Memory, startArg: any) => Worker
19 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/platforms/browser.worker.js:
--------------------------------------------------------------------------------
1 | import { instantiateForThread } from "../instantiate.js"
2 | import { defaultBrowserThreadSetup } from "./browser.js"
3 |
4 | self.onmessage = async (event) => {
5 | const { module, memory, tid, startArg, preludeScript } = event.data;
6 | let options = await defaultBrowserThreadSetup();
7 | if (preludeScript) {
8 | const prelude = await import(preludeScript);
9 | if (prelude.setupOptions) {
10 | options = prelude.setupOptions(options, { isMainThread: false })
11 | }
12 | }
13 | await instantiateForThread(tid, startArg, {
14 | ...options,
15 | module, memory,
16 | imports: {},
17 | })
18 | }
19 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/platforms/node.d.ts:
--------------------------------------------------------------------------------
1 | import type { InstantiateOptions } from "../instantiate.js"
2 | import type { Worker } from "node:worker_threads"
3 |
4 | export function defaultNodeSetup(options: {
5 | /* #if IS_WASI */
6 | args?: string[],
7 | /* #endif */
8 | onExit?: (code: number) => void,
9 | /* #if USE_SHARED_MEMORY */
10 | spawnWorker: (module: WebAssembly.Module, memory: WebAssembly.Memory, startArg: any) => Worker,
11 | /* #endif */
12 | }): Promise
13 |
14 | export function createDefaultWorkerFactory(preludeScript: string): (module: WebAssembly.Module, memory: WebAssembly.Memory, startArg: any) => Worker
15 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/test.browser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/test.d.ts:
--------------------------------------------------------------------------------
1 | import type { InstantiateOptions, instantiate } from "./instantiate";
2 |
3 | export function testBrowser(
4 | options: {
5 | preludeScript?: string,
6 | args?: string[],
7 | }
8 | ): Promise
9 |
10 | export function testBrowserInPage(
11 | options: InstantiateOptions
12 | ): ReturnType
13 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Templates/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "esnext",
4 | "noEmit": true,
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "moduleResolution": "node"
8 | },
9 | "include": ["**/*.d.ts", "**/*.js"]
10 | }
11 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/SnapshotTesting.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Testing
3 |
4 | func assertSnapshot(
5 | filePath: String = #filePath,
6 | function: String = #function,
7 | sourceLocation: SourceLocation = #_sourceLocation,
8 | variant: String? = nil,
9 | input: Data,
10 | fileExtension: String = "json"
11 | ) throws {
12 | let testFileName = URL(fileURLWithPath: filePath).deletingPathExtension().lastPathComponent
13 | let snapshotDir = URL(fileURLWithPath: filePath)
14 | .deletingLastPathComponent()
15 | .appendingPathComponent("__Snapshots__")
16 | .appendingPathComponent(testFileName)
17 | try FileManager.default.createDirectory(at: snapshotDir, withIntermediateDirectories: true)
18 | let snapshotFileName: String =
19 | "\(function[.. Comment {
27 | "Snapshot mismatch: \(actualFilePath) \(snapshotPath.path)"
28 | }
29 | if !ok {
30 | try input.write(to: URL(fileURLWithPath: actualFilePath))
31 | }
32 | #expect(ok, buildComment(), sourceLocation: sourceLocation)
33 | } else {
34 | try input.write(to: snapshotPath)
35 | #expect(Bool(false), "Snapshot created at \(snapshotPath.path)", sourceLocation: sourceLocation)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/TemplatesTests.swift:
--------------------------------------------------------------------------------
1 | import Testing
2 | import Foundation
3 | @testable import PackageToJS
4 |
5 | @Suite struct TemplatesTests {
6 | static let templatesPath = URL(fileURLWithPath: #filePath)
7 | .deletingLastPathComponent()
8 | .deletingLastPathComponent()
9 | .appendingPathComponent("Templates")
10 |
11 | /// `npx tsc -p Templates/tsconfig.json`
12 | @Test func tscCheck() throws {
13 | let tsc = Process()
14 | tsc.executableURL = try which("npx")
15 | tsc.arguments = ["tsc", "-p", Self.templatesPath.appending(path: "tsconfig.json").path]
16 | try tsc.run()
17 | tsc.waitUntilExit()
18 | #expect(tsc.terminationStatus == 0)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/TemporaryDirectory.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct MakeTemporaryDirectoryError: Error {
4 | let error: CInt
5 | }
6 |
7 | internal func withTemporaryDirectory(body: (URL, _ retain: inout Bool) throws -> T) throws -> T {
8 | // Create a temporary directory using mkdtemp
9 | var template = FileManager.default.temporaryDirectory.appendingPathComponent("PackageToJSTests.XXXXXX").path
10 | return try template.withUTF8 { template in
11 | let copy = UnsafeMutableBufferPointer.allocate(capacity: template.count + 1)
12 | template.copyBytes(to: copy)
13 | copy[template.count] = 0
14 |
15 | guard let result = mkdtemp(copy.baseAddress!) else {
16 | throw MakeTemporaryDirectoryError(error: errno)
17 | }
18 | let tempDir = URL(fileURLWithPath: String(cString: result))
19 | var retain = false
20 | defer {
21 | if !retain {
22 | try? FileManager.default.removeItem(at: tempDir)
23 | }
24 | }
25 | return try body(tempDir, &retain)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/__Snapshots__/TestsParserTests/testAllPassed.txt:
--------------------------------------------------------------------------------
1 | [1m[97m[42m PASSED [0m CounterTests
2 | [92m✔[0m testIncrement [90m(0.002s)[0m
3 | [92m✔[0m testIncrementTwice [90m(0.001s)[0m
4 | [1m[97m[42m PASSED [0m /.xctest
5 | [1m[97m[42m PASSED [0m All tests
6 |
7 | Test Suites: [32m1 passed[0m, [0m1 total
8 | Tests: [32m2 passed[0m, [0m2 total
9 | [90mRan all test suites.[0m
10 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/__Snapshots__/TestsParserTests/testAssertFailure.txt:
--------------------------------------------------------------------------------
1 | /tmp/Tests/CounterTests/CounterTests.swift:27: error: CounterTests.testAssertailure : XCTAssertEqual failed: ("1") is not equal to ("2") -
2 | [1m[97m[101m FAILED [0m CounterTests
3 | [91m✘[0m testAssertailure [90m(0.001s)[0m
4 | [1m[97m[101m FAILED [0m /.xctest
5 | [1m[97m[101m FAILED [0m All tests
6 |
7 | Test Suites: [31m1 failed[0m, [0m1 total
8 | Tests: [31m1 failed[0m, [0m1 total
9 | [90mRan all test suites.[0m
10 |
11 | [31mFailed test cases:[0m
12 | [91m✘[0m CounterTests.testAssertailure
13 |
14 | [33mSome tests failed. Use --verbose for raw test output.[0m
15 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/__Snapshots__/TestsParserTests/testCrash.txt:
--------------------------------------------------------------------------------
1 | CounterTests/CounterTests.swift:26: Fatal error: Crash
2 | wasm://wasm/CounterPackageTests.xctest-0ef3150a:1
3 | RuntimeError: unreachable
4 | at CounterPackageTests.xctest.$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_SSAHSus6UInt32VtF (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[5087]:0x1475da)
5 | at CounterPackageTests.xctest.$s12CounterTestsAAC13testIncrementyyYaKFTY1_ (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[1448]:0x9a33b)
6 | at CounterPackageTests.xctest.swift::runJobInEstablishedExecutorContext(swift::Job*) (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[29848]:0x58cb39)
7 | at CounterPackageTests.xctest.swift_job_run (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[29863]:0x58d720)
8 | at CounterPackageTests.xctest.$sScJ16runSynchronously2onySce_tF (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[1571]:0x9fe5a)
9 | at CounterPackageTests.xctest.$s19JavaScriptEventLoopAAC10runAllJobsyyF (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[1675]:0xa32c4)
10 | at CounterPackageTests.xctest.$s19JavaScriptEventLoopAAC14insertJobQueue3jobyScJ_tFyycfU0_ (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[1674]:0xa30b7)
11 | at CounterPackageTests.xctest.$s19JavaScriptEventLoopAAC14insertJobQueue3jobyScJ_tFyycfU0_TA (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[1666]:0xa2c6b)
12 | at CounterPackageTests.xctest.$s19JavaScriptEventLoopAAC6create33_F9DB15AFB1FFBEDBFE9D13500E01F3F2LLAByFZyyyccfU0_0aB3Kit20ConvertibleToJSValue_pAE0Q0OcfU_ (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[1541]:0x9de13)
13 | at CounterPackageTests.xctest.$s19JavaScriptEventLoopAAC6create33_F9DB15AFB1FFBEDBFE9D13500E01F3F2LLAByFZyyyccfU0_0aB3Kit20ConvertibleToJSValue_pAE0Q0OcfU_TA (wasm://wasm/CounterPackageTests.xctest-0ef3150a:wasm-function[1540]:0x9dd8d)
14 |
15 | Test Suites: [31m1 unknown[0m, [0m1 total
16 | Tests: [31m1 unknown[0m, [0m1 total
17 | [90mRan all test suites.[0m
18 |
19 | [31mFailed test cases:[0m
20 | [97m?[0m CounterTests.testIncrement
21 |
22 | [33mSome tests failed. Use --verbose for raw test output.[0m
23 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/__Snapshots__/TestsParserTests/testSkipped.txt:
--------------------------------------------------------------------------------
1 | /tmp/Tests/CounterTests/CounterTests.swift:25: CounterTests.testIncrement : Test skipped - Skip it
2 | [1m[97m[42m PASSED [0m CounterTests
3 | [97m➜[0m testIncrement [90m(0.006s)[0m
4 | [92m✔[0m testIncrementTwice [90m(0.0s)[0m
5 | [1m[97m[42m PASSED [0m /.xctest
6 | [1m[97m[42m PASSED [0m All tests
7 |
8 | Test Suites: [32m1 passed[0m, [0m1 total
9 | Tests: [32m1 passed[0m, [97m1 skipped[0m, [0m2 total
10 | [90mRan all test suites.[0m
11 |
--------------------------------------------------------------------------------
/Plugins/PackageToJS/Tests/__Snapshots__/TestsParserTests/testThrowFailure.txt:
--------------------------------------------------------------------------------
1 | :0: error: CounterTests.testThrowFailure : threw error "TestError()"
2 | [1m[97m[101m FAILED [0m CounterTests
3 | [91m✘[0m testThrowFailure [90m(0.002s)[0m
4 | [1m[97m[101m FAILED [0m /.xctest
5 | [1m[97m[101m FAILED [0m All tests
6 |
7 | Test Suites: [31m1 failed[0m, [0m1 total
8 | Tests: [31m1 failed[0m, [0m1 total
9 | [90mRan all test suites.[0m
10 |
11 | [31mFailed test cases:[0m
12 | [91m✘[0m CounterTests.testThrowFailure
13 |
14 | [33mSome tests failed. Use --verbose for raw test output.[0m
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JavaScriptKit
2 |
3 | [](https://github.com/swiftwasm/JavaScriptKit/actions/workflows/test.yml)
4 | [](https://swiftpackageindex.com/swiftwasm/JavaScriptKit/documentation)
5 |
6 | Swift framework to interact with JavaScript through WebAssembly.
7 |
8 | ## Quick Start
9 |
10 | Check out the [Hello World](https://swiftpackageindex.com/swiftwasm/JavaScriptKit/tutorials/javascriptkit/hello-world) tutorial for a step-by-step guide to getting started.
11 |
12 | ## Overview
13 |
14 | JavaScriptKit provides a seamless way to interact with JavaScript from Swift code when compiled to WebAssembly. It allows Swift developers to:
15 |
16 | - Access JavaScript objects and functions
17 | - Create closures that can be called from JavaScript
18 | - Convert between Swift and JavaScript data types
19 | - Use JavaScript promises with Swift's `async/await`
20 | - Work with multi-threading
21 |
22 | ```swift
23 | import JavaScriptKit
24 |
25 | // Access global JavaScript objects
26 | let document = JSObject.global.document
27 |
28 | // Create and manipulate DOM elements
29 | var div = document.createElement("div")
30 | div.innerText = "Hello from Swift!"
31 | _ = document.body.appendChild(div)
32 |
33 | // Handle events with Swift closures
34 | var button = document.createElement("button")
35 | button.innerText = "Click me"
36 | button.onclick = .object(JSClosure { _ in
37 | JSObject.global.alert!("Button clicked!")
38 | return .undefined
39 | })
40 | _ = document.body.appendChild(button)
41 | ```
42 |
43 | Check out the [examples](https://github.com/swiftwasm/JavaScriptKit/tree/main/Examples) for more detailed usage.
44 |
45 | ## Contributing
46 |
47 | Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to the project.
48 |
49 | ## Sponsoring
50 |
51 | [Become a gold or platinum sponsor](https://github.com/sponsors/swiftwasm/) and contact maintainers to add your logo on our README on Github with a link to your site.
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Runtime/.gitignore:
--------------------------------------------------------------------------------
1 | /lib
2 | /node_modules
--------------------------------------------------------------------------------
/Runtime/.npmignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftwasm/JavaScriptKit/8563ff73cf05e97ba4a2be36f713aca8d8fd7974/Runtime/.npmignore
--------------------------------------------------------------------------------
/Runtime/rollup.config.mjs:
--------------------------------------------------------------------------------
1 | import typescript from "@rollup/plugin-typescript";
2 | import dts from "rollup-plugin-dts";
3 |
4 | /** @type {import('rollup').RollupOptions} */
5 | const config = [
6 | {
7 | input: "src/index.ts",
8 | output: [
9 | {
10 | file: "lib/index.mjs",
11 | format: "esm",
12 | },
13 | ],
14 | plugins: [typescript()],
15 | },
16 | {
17 | input: "src/index.ts",
18 | output: {
19 | file: "lib/index.d.ts",
20 | format: "esm",
21 | },
22 | plugins: [dts()],
23 | },
24 | ];
25 |
26 | export default config;
27 |
--------------------------------------------------------------------------------
/Runtime/src/closure-heap.ts:
--------------------------------------------------------------------------------
1 | import { ExportedFunctions } from "./types.js";
2 |
3 | /// Memory lifetime of closures in Swift are managed by Swift side
4 | export class SwiftClosureDeallocator {
5 | private functionRegistry: FinalizationRegistry;
6 |
7 | constructor(exports: ExportedFunctions) {
8 | if (typeof FinalizationRegistry === "undefined") {
9 | throw new Error(
10 | "The Swift part of JavaScriptKit was configured to require " +
11 | "the availability of JavaScript WeakRefs. Please build " +
12 | "with `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS` to " +
13 | "disable features that use WeakRefs."
14 | );
15 | }
16 |
17 | this.functionRegistry = new FinalizationRegistry((id) => {
18 | exports.swjs_free_host_function(id);
19 | });
20 | }
21 |
22 | track(func: Function, func_ref: number) {
23 | this.functionRegistry.register(func, func_ref);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Runtime/src/find-global.ts:
--------------------------------------------------------------------------------
1 | interface GlobalVariable {}
2 | declare const global: GlobalVariable;
3 |
4 | export let globalVariable: any;
5 | if (typeof globalThis !== "undefined") {
6 | globalVariable = globalThis;
7 | } else if (typeof window !== "undefined") {
8 | globalVariable = window;
9 | } else if (typeof global !== "undefined") {
10 | globalVariable = global;
11 | } else if (typeof self !== "undefined") {
12 | globalVariable = self;
13 | }
14 |
--------------------------------------------------------------------------------
/Runtime/src/memory.ts:
--------------------------------------------------------------------------------
1 | import { SwiftRuntimeHeap } from "./object-heap.js";
2 | import { pointer } from "./types.js";
3 |
4 | export class Memory {
5 | readonly rawMemory: WebAssembly.Memory;
6 |
7 | private readonly heap = new SwiftRuntimeHeap();
8 |
9 | constructor(exports: WebAssembly.Exports) {
10 | this.rawMemory = exports.memory as WebAssembly.Memory;
11 | }
12 |
13 | retain = (value: any) => this.heap.retain(value);
14 | getObject = (ref: number) => this.heap.referenceHeap(ref);
15 | release = (ref: number) => this.heap.release(ref);
16 |
17 | bytes = () => new Uint8Array(this.rawMemory.buffer);
18 | dataView = () => new DataView(this.rawMemory.buffer);
19 |
20 | writeBytes = (ptr: pointer, bytes: Uint8Array) =>
21 | this.bytes().set(bytes, ptr);
22 |
23 | readUint32 = (ptr: pointer) => this.dataView().getUint32(ptr, true);
24 | readUint64 = (ptr: pointer) => this.dataView().getBigUint64(ptr, true);
25 | readInt64 = (ptr: pointer) => this.dataView().getBigInt64(ptr, true);
26 | readFloat64 = (ptr: pointer) => this.dataView().getFloat64(ptr, true);
27 |
28 | writeUint32 = (ptr: pointer, value: number) =>
29 | this.dataView().setUint32(ptr, value, true);
30 | writeUint64 = (ptr: pointer, value: bigint) =>
31 | this.dataView().setBigUint64(ptr, value, true);
32 | writeInt64 = (ptr: pointer, value: bigint) =>
33 | this.dataView().setBigInt64(ptr, value, true);
34 | writeFloat64 = (ptr: pointer, value: number) =>
35 | this.dataView().setFloat64(ptr, value, true);
36 | }
37 |
--------------------------------------------------------------------------------
/Runtime/src/object-heap.ts:
--------------------------------------------------------------------------------
1 | import { globalVariable } from "./find-global.js";
2 | import { ref } from "./types.js";
3 |
4 | type SwiftRuntimeHeapEntry = {
5 | id: number;
6 | rc: number;
7 | };
8 | export class SwiftRuntimeHeap {
9 | private _heapValueById: Map;
10 | private _heapEntryByValue: Map;
11 | private _heapNextKey: number;
12 |
13 | constructor() {
14 | this._heapValueById = new Map();
15 | this._heapValueById.set(0, globalVariable);
16 |
17 | this._heapEntryByValue = new Map();
18 | this._heapEntryByValue.set(globalVariable, { id: 0, rc: 1 });
19 |
20 | // Note: 0 is preserved for global
21 | this._heapNextKey = 1;
22 | }
23 |
24 | retain(value: any) {
25 | const entry = this._heapEntryByValue.get(value);
26 | if (entry) {
27 | entry.rc++;
28 | return entry.id;
29 | }
30 | const id = this._heapNextKey++;
31 | this._heapValueById.set(id, value);
32 | this._heapEntryByValue.set(value, { id: id, rc: 1 });
33 | return id;
34 | }
35 |
36 | release(ref: ref) {
37 | const value = this._heapValueById.get(ref);
38 | const entry = this._heapEntryByValue.get(value)!;
39 | entry.rc--;
40 | if (entry.rc != 0) return;
41 |
42 | this._heapEntryByValue.delete(value);
43 | this._heapValueById.delete(ref);
44 | }
45 |
46 | referenceHeap(ref: ref) {
47 | const value = this._heapValueById.get(ref);
48 | if (value === undefined) {
49 | throw new ReferenceError(
50 | "Attempted to read invalid reference " + ref
51 | );
52 | }
53 | return value;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Runtime/src/types.ts:
--------------------------------------------------------------------------------
1 | export type ref = number;
2 | export type pointer = number;
3 | export type bool = number;
4 | export type JavaScriptValueKind = number;
5 | export type JavaScriptValueKindAndFlags = number;
6 |
7 | export interface ExportedFunctions {
8 | swjs_library_version(): number;
9 | swjs_library_features(): number;
10 | swjs_prepare_host_function_call(size: number): pointer;
11 | swjs_cleanup_host_function_call(argv: pointer): void;
12 | swjs_call_host_function(
13 | host_func_id: number,
14 | argv: pointer,
15 | argc: number,
16 | callback_func_ref: ref
17 | ): bool;
18 |
19 | swjs_free_host_function(host_func_id: number): void;
20 |
21 | swjs_enqueue_main_job_from_worker(unowned_job: number): void;
22 | swjs_wake_worker_thread(): void;
23 | swjs_receive_response(object: ref, transferring: pointer): void;
24 | swjs_receive_error(error: ref, context: number): void;
25 | }
26 |
27 | export const enum LibraryFeatures {
28 | WeakRefs = 1 << 0,
29 | }
30 |
31 | export function assertNever(x: never, message: string) {
32 | throw new Error(message);
33 | }
34 |
35 | export const MAIN_THREAD_TID = -1;
36 |
--------------------------------------------------------------------------------
/Runtime/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": false,
4 | "importHelpers": true,
5 | "module": "esnext",
6 | "noEmit": true,
7 | "rootDir": "src",
8 | "strict": true,
9 | "target": "es2017",
10 | "lib": ["es2020", "DOM", "ESNext.WeakRef"],
11 | "skipLibCheck": true
12 | },
13 | "include": ["src/**/*"],
14 | "exclude": ["node_modules"]
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/JavaScriptBigIntSupport/Int64+I64.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 |
3 | extension UInt64: JavaScriptKit.ConvertibleToJSValue, JavaScriptKit.TypedArrayElement {
4 | public static var typedArrayClass: JSFunction { JSObject.global.BigUint64Array.function! }
5 |
6 | public var jsValue: JSValue { .bigInt(JSBigInt(unsigned: self)) }
7 | }
8 |
9 | extension Int64: JavaScriptKit.ConvertibleToJSValue, JavaScriptKit.TypedArrayElement {
10 | public static var typedArrayClass: JSFunction { JSObject.global.BigInt64Array.function! }
11 |
12 | public var jsValue: JSValue { .bigInt(JSBigInt(self)) }
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/JavaScriptBigIntSupport/JSBigInt+I64.swift:
--------------------------------------------------------------------------------
1 | @_spi(JSObject_id) import JavaScriptKit
2 | import _CJavaScriptBigIntSupport
3 |
4 | extension JSBigInt: JavaScriptKit.JSBigIntExtended {
5 | public var int64Value: Int64 {
6 | swjs_bigint_to_i64(id, true)
7 | }
8 |
9 | public var uInt64Value: UInt64 {
10 | UInt64(bitPattern: swjs_bigint_to_i64(id, false))
11 | }
12 |
13 | public convenience init(_ value: Int64) {
14 | self.init(id: swjs_i64_to_bigint(value, true))
15 | }
16 |
17 | public convenience init(unsigned value: UInt64) {
18 | self.init(id: swjs_i64_to_bigint(Int64(bitPattern: value), false))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/JavaScriptEventLoop/WebWorkerDedicatedExecutor.swift:
--------------------------------------------------------------------------------
1 | #if !hasFeature(Embedded)
2 | import JavaScriptKit
3 | import _CJavaScriptEventLoop
4 | import _Concurrency
5 |
6 | #if canImport(Synchronization)
7 | import Synchronization
8 | #endif
9 | #if canImport(wasi_pthread)
10 | import wasi_pthread
11 | import WASILibc
12 | #endif
13 |
14 | /// A serial executor that runs on a dedicated web worker thread.
15 | ///
16 | /// This executor is useful for running actors on a dedicated web worker thread.
17 | ///
18 | /// ## Usage
19 | ///
20 | /// ```swift
21 | /// actor MyActor {
22 | /// let executor: WebWorkerDedicatedExecutor
23 | /// nonisolated var unownedExecutor: UnownedSerialExecutor {
24 | /// self.executor.asUnownedSerialExecutor()
25 | /// }
26 | /// init(executor: WebWorkerDedicatedExecutor) {
27 | /// self.executor = executor
28 | /// }
29 | /// }
30 | ///
31 | /// let executor = try await WebWorkerDedicatedExecutor()
32 | /// let actor = MyActor(executor: executor)
33 | /// ```
34 | ///
35 | /// - SeeAlso: ``WebWorkerTaskExecutor``
36 | @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
37 | public final class WebWorkerDedicatedExecutor: SerialExecutor, TaskExecutor {
38 |
39 | private let underlying: WebWorkerTaskExecutor
40 |
41 | /// - Parameters:
42 | /// - timeout: The maximum time to wait for all worker threads to be started. Default is 3 seconds.
43 | /// - checkInterval: The interval to check if all worker threads are started. Default is 5 microseconds.
44 | /// - Throws: An error if any worker thread fails to initialize within the timeout period.
45 | public init(timeout: Duration = .seconds(3), checkInterval: Duration = .microseconds(5)) async throws {
46 | let underlying = try await WebWorkerTaskExecutor(
47 | numberOfThreads: 1,
48 | timeout: timeout,
49 | checkInterval: checkInterval
50 | )
51 | self.underlying = underlying
52 | }
53 |
54 | /// Terminates the worker thread.
55 | public func terminate() {
56 | self.underlying.terminate()
57 | }
58 |
59 | // MARK: - SerialExecutor conformance
60 |
61 | public func enqueue(_ job: consuming ExecutorJob) {
62 | self.underlying.enqueue(job)
63 | }
64 | }
65 | #endif
66 |
--------------------------------------------------------------------------------
/Sources/JavaScriptEventLoopTestSupport/JavaScriptEventLoopTestSupport.swift:
--------------------------------------------------------------------------------
1 | /// If you need to execute Swift async functions that can be resumed by JS
2 | /// event loop in your XCTest suites, please add `JavaScriptEventLoopTestSupport`
3 | /// to your test target dependencies.
4 | ///
5 | /// ```diff
6 | /// .testTarget(
7 | /// name: "MyAppTests",
8 | /// dependencies: [
9 | /// "MyApp",
10 | /// + "JavaScriptEventLoopTestSupport",
11 | /// ]
12 | /// )
13 | /// ```
14 | ///
15 | /// Linking this module automatically activates JS event loop based global
16 | /// executor by calling `JavaScriptEventLoop.installGlobalExecutor()`
17 |
18 | import JavaScriptEventLoop
19 |
20 | // This module just expose 'JavaScriptEventLoop.installGlobalExecutor' to C ABI
21 | // See _CJavaScriptEventLoopTestSupport.c for why this is needed
22 |
23 | #if compiler(>=5.5)
24 |
25 | @available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
26 | @_cdecl("swift_javascriptkit_activate_js_executor_impl")
27 | func swift_javascriptkit_activate_js_executor_impl() {
28 | MainActor.assumeIsolated {
29 | JavaScriptEventLoop.installGlobalExecutor()
30 | }
31 | }
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/BasicObjects/JSError.swift:
--------------------------------------------------------------------------------
1 | /// A wrapper around [the JavaScript `Error`
2 | /// class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) that
3 | /// exposes its properties in a type-safe way.
4 | public final class JSError: JSBridgedClass {
5 | /// The constructor function used to create new JavaScript `Error` objects.
6 | public static var constructor: JSFunction? { _constructor.wrappedValue }
7 | private static let _constructor = LazyThreadLocal(initialize: { JSObject.global.Error.function })
8 |
9 | /// The underlying JavaScript `Error` object.
10 | public let jsObject: JSObject
11 |
12 | /// Creates a new instance of the JavaScript `Error` class with a given message.
13 | public init(message: String) {
14 | jsObject = Self.constructor!.new([message])
15 | }
16 |
17 | public init(unsafelyWrapping jsObject: JSObject) {
18 | self.jsObject = jsObject
19 | }
20 |
21 | /// The error message of the underlying `Error` object.
22 | public var message: String {
23 | jsObject.message.string!
24 | }
25 |
26 | /// The name (usually corresponds to the name of the underlying class) of a given error.
27 | public var name: String {
28 | jsObject.name.string!
29 | }
30 |
31 | /// The JavaScript call stack that led to the creation of this error object.
32 | public var stack: String? {
33 | jsObject.stack.string
34 | }
35 |
36 | /// Creates a new `JSValue` from this `JSError` instance.
37 | public var jsValue: JSValue {
38 | .object(jsObject)
39 | }
40 | }
41 |
42 | extension JSError: CustomStringConvertible {
43 | /// The textual representation of this error.
44 | public var description: String { jsObject.description }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Deprecated.swift:
--------------------------------------------------------------------------------
1 | @available(*, deprecated, renamed: "JSObject")
2 | public typealias JSObjectRef = JSObject
3 |
4 | @available(*, deprecated, renamed: "JSArray")
5 | public typealias JSArrayRef = JSArray
6 |
7 | @available(*, deprecated, renamed: "JSFunction")
8 | public typealias JSFunctionRef = JSFunction
9 |
10 | @available(*, deprecated, renamed: "ConvertibleToJSValue")
11 | public typealias JSValueConvertible = ConvertibleToJSValue
12 |
13 | @available(*, deprecated, renamed: "ConstructibleFromJSValue")
14 | public typealias JSValueConstructible = ConstructibleFromJSValue
15 |
16 | @available(*, deprecated, renamed: "JSValueCompatible")
17 | public typealias JSValueCodable = JSValueCompatible
18 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Articles/JavaScript-Environment-Requirements.md:
--------------------------------------------------------------------------------
1 | # JavaScript Environment Requirements
2 |
3 | ## Required JavaScript Features
4 |
5 | The JavaScript package produced by the JavaScriptKit packaging plugin requires the following JavaScript features:
6 |
7 | - [`FinalizationRegistry`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry#browser_compatibility)
8 | - [WebAssembly BigInt to i64 conversion in JS API](https://caniuse.com/wasm-bigint)
9 |
10 | ## Browser Compatibility
11 |
12 | These JavaScript features are supported in the following browsers:
13 |
14 | - Chrome 85+ (August 2020)
15 | - Firefox 79+ (July 2020)
16 | - Desktop Safari 14.1+ (April 2021)
17 | - Mobile Safari 14.5+ (April 2021)
18 | - Edge 85+ (August 2020)
19 | - Node.js 15.0+ (October 2020)
20 |
21 | Older browsers will not be able to run applications built with JavaScriptKit unless polyfills are provided.
22 |
23 | ## Handling Missing Features
24 |
25 | ### FinalizationRegistry
26 |
27 | When using JavaScriptKit in environments without `FinalizationRegistry` support, you can:
28 |
29 | 1. Build with the opt-out flag: `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS`
30 | 2. Then manually manage memory by calling `release()` on all `JSClosure` instances:
31 |
32 | ```swift
33 | let closure = JSClosure { args in
34 | // Your code here
35 | return .undefined
36 | }
37 |
38 | // Use the closure...
39 |
40 | // Then release it when done
41 | #if JAVASCRIPTKIT_WITHOUT_WEAKREFS
42 | closure.release()
43 | #endif
44 | ```
45 |
46 | ### WebAssembly BigInt Support
47 |
48 | If you need to work with 64-bit integers in JavaScript, ensure your target environment supports WebAssembly BigInt conversions. For environments that don't support this feature, you'll need to avoid importing `JavaScriptBigIntSupport`
49 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Documentation.md:
--------------------------------------------------------------------------------
1 | # ``JavaScriptKit``
2 |
3 | Swift framework to interact with JavaScript through WebAssembly.
4 |
5 | ## Overview
6 |
7 | **JavaScriptKit** provides a seamless way to interact with JavaScript from Swift code when compiled to WebAssembly.
8 |
9 | ## Quick Start
10 |
11 | Check out the tutorial for a step-by-step guide to getting started.
12 |
13 | ### Key Features
14 |
15 | - Access JavaScript objects and functions
16 | - Create closures that can be called from JavaScript
17 | - Convert between Swift and JavaScript data types
18 | - Use JavaScript promises with Swift's `async/await`
19 | - Work with multi-threading
20 |
21 | ### Example
22 |
23 | ```swift
24 | import JavaScriptKit
25 |
26 | // Access global JavaScript objects
27 | let document = JSObject.global.document
28 |
29 | // Create and manipulate DOM elements
30 | var div = document.createElement("div")
31 | div.innerText = "Hello from Swift!"
32 | _ = document.body.appendChild(div)
33 |
34 | // Handle events with Swift closures
35 | var button = document.createElement("button")
36 | button.innerText = "Click me"
37 | button.onclick = .object(JSClosure { _ in
38 | JSObject.global.alert!("Button clicked!")
39 | return .undefined
40 | })
41 | _ = document.body.appendChild(button)
42 | ```
43 |
44 | Check out the [examples](https://github.com/swiftwasm/JavaScriptKit/tree/main/Examples) for more detailed usage.
45 |
46 | ## Topics
47 |
48 | ### Tutorials
49 |
50 | -
51 |
52 | ### Articles
53 |
54 | -
55 | -
56 | -
57 | -
58 | -
59 |
60 | ### Core APIs
61 |
62 | - ``JSValue``
63 | - ``JSObject``
64 | - ``JS()``
65 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-1-swift-version.txt:
--------------------------------------------------------------------------------
1 | $ swift --version
2 | Apple Swift version 6.0.3 (swift-6.0.3-RELEASE)
3 | or
4 | Swift version 6.0.3 (swift-6.0.3-RELEASE)
5 |
6 | $ swift sdk list
7 | 6.0.3-RELEASE-wasm32-unknown-wasi
8 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-0-2-select-sdk.txt:
--------------------------------------------------------------------------------
1 | $ swift --version
2 | Apple Swift version 6.0.3 (swift-6.0.3-RELEASE)
3 | or
4 | Swift version 6.0.3 (swift-6.0.3-RELEASE)
5 |
6 | $ swift sdk list
7 | 6.0.3-RELEASE-wasm32-unknown-wasi
8 |
9 | $ export SWIFT_SDK_ID=6.0.3-RELEASE-wasm32-unknown-wasi
10 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-1-init-package.txt:
--------------------------------------------------------------------------------
1 | $ swift package init --name Hello --type executable
2 | Creating executable package: Hello
3 | Creating Package.swift
4 | Creating .gitignore
5 | Creating Sources/
6 | Creating Sources/main.swift
7 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-2-add-dependency.txt:
--------------------------------------------------------------------------------
1 | $ swift package init --name Hello --type executable
2 | Creating executable package: Hello
3 | Creating Package.swift
4 | Creating .gitignore
5 | Creating Sources/
6 | Creating Sources/main.swift
7 |
8 | $ swift package add-dependency https://github.com/swiftwasm/JavaScriptKit.git --branch main
9 | Updating package manifest at Package.swift... done.
10 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-1-3-add-target-dependency.txt:
--------------------------------------------------------------------------------
1 | $ swift package init --name Hello --type executable
2 | Creating executable package: Hello
3 | Creating Package.swift
4 | Creating .gitignore
5 | Creating Sources/
6 | Creating Sources/main.swift
7 |
8 | $ swift package add-dependency https://github.com/swiftwasm/JavaScriptKit.git --branch main
9 | Updating package manifest at Package.swift... done.
10 |
11 | $ swift package add-target-dependency --package JavaScriptKit JavaScriptKit Hello
12 | Updating package manifest at Package.swift... done.
13 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-1-main-swift.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 |
3 | let document = JSObject.global.document
4 | var div = document.createElement("div")
5 | div.innerText = "Hello from Swift!"
6 | document.body.appendChild(div)
7 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-2-2-index-html.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Swift Web App
6 |
10 |
11 |
12 | My Swift Web App
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-1-build.txt:
--------------------------------------------------------------------------------
1 | $ swift package --swift-sdk $SWIFT_SDK_ID js --use-cdn
2 | [37/37] Linking Hello.wasm
3 | Build of product 'Hello' complete! (5.16s)
4 | Packaging...
5 | ...
6 | Packaging finished
7 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-2-server.txt:
--------------------------------------------------------------------------------
1 | $ swift package --swift-sdk $SWIFT_SDK_ID js --use-cdn
2 | [37/37] Linking Hello.wasm
3 | Build of product 'Hello' complete! (5.16s)
4 | Packaging...
5 | ...
6 | Packaging finished
7 | $ npx serve
8 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftwasm/JavaScriptKit/8563ff73cf05e97ba4a2be36f713aca8d8fd7974/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-app.png
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-3-3-open.txt:
--------------------------------------------------------------------------------
1 | $ swift package --swift-sdk $SWIFT_SDK_ID js --use-cdn
2 | [37/37] Linking Hello.wasm
3 | Build of product 'Hello' complete! (5.16s)
4 | Packaging...
5 | ...
6 | Packaging finished
7 | $ npx serve
8 | $ open http://localhost:3000
9 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Resources/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftwasm/JavaScriptKit/8563ff73cf05e97ba4a2be36f713aca8d8fd7974/Sources/JavaScriptKit/Documentation.docc/Tutorials/Resources/image.png
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Documentation.docc/Tutorials/Table-of-Contents.tutorial:
--------------------------------------------------------------------------------
1 | @Tutorials(name: "JavaScriptKit") {
2 | @Intro(title: "Working with JavaScriptKit") {
3 | JavaScriptKit is a Swift package that allows you to interact with JavaScript APIs directly from Swift code when targeting WebAssembly.
4 | }
5 | @Chapter(name: "Hello World") {
6 | @Image(source: "image.png")
7 | @TutorialReference(tutorial: "doc:Hello-World")
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Features.swift:
--------------------------------------------------------------------------------
1 | enum LibraryFeatures {
2 | static let weakRefs: Int32 = 1 << 0
3 | }
4 |
5 | @_cdecl("_library_features")
6 | func _library_features() -> Int32 {
7 | var features: Int32 = 0
8 | #if !JAVASCRIPTKIT_WITHOUT_WEAKREFS
9 | features |= LibraryFeatures.weakRefs
10 | #endif
11 | return features
12 | }
13 |
14 | #if compiler(>=6.0) && hasFeature(Embedded)
15 | // cdecls currently don't work in embedded, and expose for wasm only works >=6.0
16 | @_expose(wasm, "swjs_library_features")
17 | public func _swjs_library_features() -> Int32 { _library_features() }
18 | #endif
19 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift:
--------------------------------------------------------------------------------
1 | import _CJavaScriptKit
2 |
3 | private var constructor: JSFunction { JSObject.global.BigInt.function! }
4 |
5 | /// A wrapper around [the JavaScript `BigInt`
6 | /// class](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)
7 | /// that exposes its properties in a type-safe and Swifty way.
8 | public final class JSBigInt: JSObject {
9 | @_spi(JSObject_id)
10 | override public init(id: JavaScriptObjectRef) {
11 | super.init(id: id)
12 | }
13 |
14 | /// Instantiate a new `JSBigInt` with given Int64 value in a slow path
15 | /// This doesn't require [JS-BigInt-integration](https://github.com/WebAssembly/JS-BigInt-integration) feature.
16 | public init(_slowBridge value: Int64) {
17 | let value = UInt64(bitPattern: value)
18 | super.init(id: swjs_i64_to_bigint_slow(UInt32(value & 0xffff_ffff), UInt32(value >> 32), true))
19 | }
20 |
21 | /// Instantiate a new `JSBigInt` with given UInt64 value in a slow path
22 | /// This doesn't require [JS-BigInt-integration](https://github.com/WebAssembly/JS-BigInt-integration) feature.
23 | public init(_slowBridge value: UInt64) {
24 | super.init(id: swjs_i64_to_bigint_slow(UInt32(value & 0xffff_ffff), UInt32(value >> 32), false))
25 | }
26 |
27 | override public var jsValue: JSValue {
28 | .bigInt(self)
29 | }
30 |
31 | public func clamped(bitSize: Int, signed: Bool) -> JSBigInt {
32 | if signed {
33 | return constructor.asIntN(bitSize, self).bigInt!
34 | } else {
35 | return constructor.asUintN(bitSize, self).bigInt!
36 | }
37 | }
38 | }
39 |
40 | public protocol JSBigIntExtended: JSBigInt {
41 | var int64Value: Int64 { get }
42 | var uInt64Value: UInt64 { get }
43 |
44 | init(_ value: Int64)
45 | init(unsigned value: UInt64)
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/JSBridgedType.swift:
--------------------------------------------------------------------------------
1 | /// Use this protocol when your type has no single JavaScript class.
2 | /// For example, a union type of multiple classes or primitive values.
3 | public protocol JSBridgedType: JSValueCompatible, CustomStringConvertible {
4 | /// If your class is incompatible with the provided value, return `nil`.
5 | init?(from value: JSValue)
6 | }
7 |
8 | extension JSBridgedType {
9 | public static func construct(from value: JSValue) -> Self? {
10 | Self(from: value)
11 | }
12 |
13 | public var description: String { jsValue.description }
14 | }
15 |
16 | /// Conform to this protocol when your Swift class wraps a JavaScript class.
17 | public protocol JSBridgedClass: JSBridgedType {
18 | /// The constructor function for the JavaScript class
19 | static var constructor: JSFunction? { get }
20 |
21 | /// The JavaScript object wrapped by this instance.
22 | /// You may assume that `jsObject instanceof Self.constructor == true`
23 | var jsObject: JSObject { get }
24 |
25 | /// Create an instance wrapping the given JavaScript object.
26 | /// You may assume that `jsObject instanceof Self.constructor`
27 | init(unsafelyWrapping jsObject: JSObject)
28 | }
29 |
30 | extension JSBridgedClass {
31 | public var jsValue: JSValue { jsObject.jsValue }
32 |
33 | public init?(from value: JSValue) {
34 | guard let object = value.object else { return nil }
35 | self.init(from: object)
36 | }
37 |
38 | public init?(from object: JSObject) {
39 | guard let constructor = Self.constructor, object.isInstanceOf(constructor) else { return nil }
40 | self.init(unsafelyWrapping: object)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/JSException.swift:
--------------------------------------------------------------------------------
1 | /// `JSException` is a wrapper that handles exceptions thrown during JavaScript execution as Swift
2 | /// `Error` objects.
3 | /// When a JavaScript function throws an exception, it's wrapped as a `JSException` and propagated
4 | /// through Swift's error handling mechanism.
5 | ///
6 | /// Example:
7 | /// ```swift
8 | /// do {
9 | /// try jsFunction.throws()
10 | /// } catch let error as JSException {
11 | /// // Access the value thrown from JavaScript
12 | /// let jsErrorValue = error.thrownValue
13 | /// }
14 | /// ```
15 | public struct JSException: Error, Equatable, CustomStringConvertible {
16 | /// The value thrown from JavaScript.
17 | /// This can be any JavaScript value (error object, string, number, etc.).
18 | public var thrownValue: JSValue {
19 | return _thrownValue
20 | }
21 |
22 | /// The actual JavaScript value that was thrown.
23 | ///
24 | /// Marked as `nonisolated(unsafe)` to satisfy `Sendable` requirement
25 | /// from `Error` protocol.
26 | private nonisolated(unsafe) let _thrownValue: JSValue
27 |
28 | /// A description of the exception.
29 | public let description: String
30 |
31 | /// The stack trace of the exception.
32 | public let stack: String?
33 |
34 | /// Initializes a new JSException instance with a value thrown from JavaScript.
35 | ///
36 | /// Only available within the package. This must be called on the thread where the exception object created.
37 | package init(_ thrownValue: JSValue) {
38 | self._thrownValue = thrownValue
39 | // Capture the stringified representation on the object owner thread
40 | // to bring useful info to the catching thread even if they are different threads.
41 | if let errorObject = thrownValue.object, let stack = errorObject.stack.string {
42 | self.description = "JSException(\(stack))"
43 | self.stack = stack
44 | } else {
45 | self.description = "JSException(\(thrownValue))"
46 | self.stack = nil
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Macros.swift:
--------------------------------------------------------------------------------
1 | /// A macro that exposes Swift functions, classes, and methods to JavaScript.
2 | ///
3 | /// Apply this macro to Swift declarations that you want to make callable from JavaScript:
4 | ///
5 | /// ```swift
6 | /// // Export a function to JavaScript
7 | /// @JS public func greet(name: String) -> String {
8 | /// return "Hello, \(name)!"
9 | /// }
10 | ///
11 | /// // Export a class and its members
12 | /// @JS class Counter {
13 | /// private var count = 0
14 | ///
15 | /// @JS init() {}
16 | ///
17 | /// @JS func increment() {
18 | /// count += 1
19 | /// }
20 | ///
21 | /// @JS func getValue() -> Int {
22 | /// return count
23 | /// }
24 | /// }
25 | /// ```
26 | ///
27 | /// When you build your project with the BridgeJS plugin, these declarations will be
28 | /// accessible from JavaScript, and TypeScript declaration files (`.d.ts`) will be
29 | /// automatically generated to provide type safety.
30 | ///
31 | /// For detailed usage information, see the article .
32 | ///
33 | /// - Important: This feature is still experimental. No API stability is guaranteed, and the API may change in future releases.
34 | @attached(peer)
35 | public macro JS() = Builtin.ExternalMacro
36 |
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Runtime/index.d.ts:
--------------------------------------------------------------------------------
1 | ../../../Plugins/PackageToJS/Templates/runtime.d.ts
--------------------------------------------------------------------------------
/Sources/JavaScriptKit/Runtime/index.mjs:
--------------------------------------------------------------------------------
1 | ../../../Plugins/PackageToJS/Templates/runtime.mjs
--------------------------------------------------------------------------------
/Sources/_CJavaScriptBigIntSupport/_CJavaScriptKit+I64.c:
--------------------------------------------------------------------------------
1 | // empty file to appease build process
2 |
--------------------------------------------------------------------------------
/Sources/_CJavaScriptBigIntSupport/include/_CJavaScriptKit+I64.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef _CJavaScriptBigIntSupport_h
3 | #define _CJavaScriptBigIntSupport_h
4 |
5 | #include <_CJavaScriptKit.h>
6 |
7 | #if __wasm32__
8 | # define IMPORT_JS_FUNCTION(name, returns, args) \
9 | __attribute__((__import_module__("javascript_kit"), __import_name__(#name))) extern returns name args;
10 | #else
11 | # define IMPORT_JS_FUNCTION(name, returns, args) \
12 | static inline returns name args { \
13 | abort(); \
14 | }
15 | #endif
16 |
17 | /// Converts the provided Int64 or UInt64 to a BigInt.
18 | ///
19 | /// @param value The value to convert.
20 | /// @param is_signed Whether to treat the value as a signed integer or not.
21 | IMPORT_JS_FUNCTION(swjs_i64_to_bigint, JavaScriptObjectRef, (const long long value, bool is_signed))
22 |
23 | /// Converts the provided BigInt to an Int64 or UInt64.
24 | ///
25 | /// @param ref The target JavaScript object.
26 | /// @param is_signed Whether to treat the return value as a signed integer or not.
27 | IMPORT_JS_FUNCTION(swjs_bigint_to_i64, long long, (const JavaScriptObjectRef ref, bool is_signed))
28 |
29 | #endif /* _CJavaScriptBigIntSupport_h */
30 |
--------------------------------------------------------------------------------
/Sources/_CJavaScriptBigIntSupport/include/module.modulemap:
--------------------------------------------------------------------------------
1 | module _CJavaScriptBigIntSupport {
2 | header "_CJavaScriptKit+I64.h"
3 | export *
4 | }
5 |
--------------------------------------------------------------------------------
/Sources/_CJavaScriptEventLoop/_CJavaScriptEventLoop.c:
--------------------------------------------------------------------------------
1 | #include "_CJavaScriptEventLoop.h"
2 |
3 | _Thread_local void *swjs_thread_local_event_loop;
4 |
5 | _Thread_local void *swjs_thread_local_task_executor_worker;
6 |
--------------------------------------------------------------------------------
/Sources/_CJavaScriptEventLoop/include/module.modulemap:
--------------------------------------------------------------------------------
1 | module _CJavaScriptEventLoop {
2 | header "_CJavaScriptEventLoop.h"
3 | export *
4 | }
5 |
--------------------------------------------------------------------------------
/Sources/_CJavaScriptEventLoopTestSupport/_CJavaScriptEventLoopTestSupport.c:
--------------------------------------------------------------------------------
1 | // This 'ctor' function is called at startup time of this program.
2 | // It's invoked by '_start' of command-line or '_initialize' of reactor.
3 | // This ctor activate the event loop based global executor automatically
4 | // before running the test cases. For general applications, applications
5 | // have to activate the event loop manually on their responsibility.
6 | // However, XCTest framework doesn't provide a way to run arbitrary code
7 | // before running all of the test suites. So, we have to do it here.
8 | //
9 | // See also: https://github.com/WebAssembly/WASI/blob/main/legacy/application-abi.md#current-unstable-abi
10 |
11 | extern void swift_javascriptkit_activate_js_executor_impl(void);
12 |
13 | // priority 0~100 is reserved by wasi-libc
14 | // https://github.com/WebAssembly/wasi-libc/blob/30094b6ed05f19cee102115215863d185f2db4f0/libc-bottom-half/sources/environ.c#L20
15 | __attribute__((constructor(/* priority */ 200)))
16 | void swift_javascriptkit_activate_js_executor(void) {
17 | swift_javascriptkit_activate_js_executor_impl();
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/Sources/_CJavaScriptEventLoopTestSupport/include/dummy.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swiftwasm/JavaScriptKit/8563ff73cf05e97ba4a2be36f713aca8d8fd7974/Sources/_CJavaScriptEventLoopTestSupport/include/dummy.h
--------------------------------------------------------------------------------
/Sources/_CJavaScriptKit/_CJavaScriptKit.c:
--------------------------------------------------------------------------------
1 | #include "_CJavaScriptKit.h"
2 | #if __wasm32__
3 | # ifndef __wasi__
4 | # if __has_include("malloc.h")
5 | # include
6 | # endif
7 | extern void *malloc(size_t size);
8 | extern void free(void *ptr);
9 | extern void *memset (void *, int, size_t);
10 | extern void *memcpy (void *__restrict, const void *__restrict, size_t);
11 | # else
12 | # include
13 | # include
14 |
15 | # endif
16 | /// The compatibility runtime library version.
17 | /// Notes: If you change any interface of runtime library, please increment
18 | /// this and `SwiftRuntime.version` in `./Runtime/src/index.ts`.
19 | __attribute__((export_name("swjs_library_version")))
20 | int swjs_library_version(void) {
21 | return 708;
22 | }
23 |
24 | __attribute__((export_name("swjs_prepare_host_function_call")))
25 | void *swjs_prepare_host_function_call(const int argc) {
26 | return malloc(argc * sizeof(RawJSValue));
27 | }
28 |
29 | __attribute__((export_name("swjs_cleanup_host_function_call")))
30 | void swjs_cleanup_host_function_call(void *argv_buffer) {
31 | free(argv_buffer);
32 | }
33 |
34 | // NOTE: This __wasi__ check is a hack for Embedded compatibility (assuming that if __wasi__ is defined, we are not building for Embedded)
35 | // cdecls don't work in Embedded, but @_expose(wasm) can be used with Swift >=6.0
36 | // the previously used `#if __Embedded` did not play well with SwiftPM (defines needed to be on every target up the chain)
37 | # ifdef __wasi__
38 | bool _call_host_function_impl(const JavaScriptHostFuncRef host_func_ref,
39 | const RawJSValue *argv, const int argc,
40 | const JavaScriptObjectRef callback_func);
41 |
42 | __attribute__((export_name("swjs_call_host_function")))
43 | bool swjs_call_host_function(const JavaScriptHostFuncRef host_func_ref,
44 | const RawJSValue *argv, const int argc,
45 | const JavaScriptObjectRef callback_func) {
46 | return _call_host_function_impl(host_func_ref, argv, argc, callback_func);
47 | }
48 |
49 | void _free_host_function_impl(const JavaScriptHostFuncRef host_func_ref);
50 |
51 | __attribute__((export_name("swjs_free_host_function")))
52 | void swjs_free_host_function(const JavaScriptHostFuncRef host_func_ref) {
53 | _free_host_function_impl(host_func_ref);
54 | }
55 |
56 | int _library_features(void);
57 |
58 | __attribute__((export_name("swjs_library_features")))
59 | int swjs_library_features(void) {
60 | return _library_features();
61 | }
62 | # endif
63 | #endif
64 |
65 | int swjs_get_worker_thread_id_cached(void) {
66 | _Thread_local static int tid = 0;
67 | if (tid == 0) {
68 | tid = swjs_get_worker_thread_id();
69 | }
70 | return tid;
71 | }
72 |
--------------------------------------------------------------------------------
/Sources/_CJavaScriptKit/include/module.modulemap:
--------------------------------------------------------------------------------
1 | module _CJavaScriptKit {
2 | header "_CJavaScriptKit.h"
3 | export *
4 | }
5 |
--------------------------------------------------------------------------------
/Tests/BridgeJSRuntimeTests/ExportAPITests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import JavaScriptKit
3 |
4 | @_extern(wasm, module: "BridgeJSRuntimeTests", name: "runJsWorks")
5 | @_extern(c)
6 | func runJsWorks() -> Void
7 |
8 | @JS func roundTripVoid() -> Void {
9 | return
10 | }
11 |
12 | @JS func roundTripInt(v: Int) -> Int {
13 | return v
14 | }
15 | @JS func roundTripFloat(v: Float) -> Float {
16 | return v
17 | }
18 | @JS func roundTripDouble(v: Double) -> Double {
19 | return v
20 | }
21 | @JS func roundTripBool(v: Bool) -> Bool {
22 | return v
23 | }
24 | @JS func roundTripString(v: String) -> String {
25 | return v
26 | }
27 | @JS func roundTripSwiftHeapObject(v: Greeter) -> Greeter {
28 | return v
29 | }
30 |
31 | @JS class Greeter {
32 | var name: String
33 |
34 | nonisolated(unsafe) static var onDeinit: () -> Void = {}
35 |
36 | @JS init(name: String) {
37 | self.name = name
38 | }
39 |
40 | @JS func greet() -> String {
41 | return "Hello, \(name)!"
42 | }
43 | @JS func changeName(name: String) {
44 | self.name = name
45 | }
46 |
47 | deinit {
48 | Self.onDeinit()
49 | }
50 | }
51 |
52 | @JS func takeGreeter(g: Greeter, name: String) {
53 | g.changeName(name: name)
54 | }
55 |
56 | class ExportAPITests: XCTestCase {
57 | func testAll() {
58 | var hasDeinitGreeter = false
59 | Greeter.onDeinit = {
60 | hasDeinitGreeter = true
61 | }
62 | runJsWorks()
63 | XCTAssertTrue(hasDeinitGreeter)
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Tests/JavaScriptBigIntSupportTests/JavaScriptBigIntSupportTests.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptBigIntSupport
2 | import JavaScriptKit
3 | import XCTest
4 |
5 | class JavaScriptBigIntSupportTests: XCTestCase {
6 | func testBigIntSupport() {
7 | // Test signed values
8 | func testSignedValue(_ value: Int64, file: StaticString = #filePath, line: UInt = #line) {
9 | let bigInt = JSBigInt(value)
10 | XCTAssertEqual(bigInt.description, value.description, file: file, line: line)
11 | let bigInt2 = JSBigInt(_slowBridge: value)
12 | XCTAssertEqual(bigInt2.description, value.description, file: file, line: line)
13 | }
14 |
15 | // Test unsigned values
16 | func testUnsignedValue(_ value: UInt64, file: StaticString = #filePath, line: UInt = #line) {
17 | let bigInt = JSBigInt(unsigned: value)
18 | XCTAssertEqual(bigInt.description, value.description, file: file, line: line)
19 | let bigInt2 = JSBigInt(_slowBridge: value)
20 | XCTAssertEqual(bigInt2.description, value.description, file: file, line: line)
21 | }
22 |
23 | // Test specific signed values
24 | testSignedValue(0)
25 | testSignedValue(1 << 62)
26 | testSignedValue(-2305)
27 |
28 | // Test random signed values
29 | for _ in 0..<100 {
30 | testSignedValue(.random(in: .min ... .max))
31 | }
32 |
33 | // Test edge signed values
34 | testSignedValue(.min)
35 | testSignedValue(.max)
36 |
37 | // Test specific unsigned values
38 | testUnsignedValue(0)
39 | testUnsignedValue(1 << 62)
40 | testUnsignedValue(1 << 63)
41 | testUnsignedValue(.min)
42 | testUnsignedValue(.max)
43 | testUnsignedValue(~0)
44 |
45 | // Test random unsigned values
46 | for _ in 0..<100 {
47 | testUnsignedValue(.random(in: .min ... .max))
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Tests/JavaScriptEventLoopTestSupportTests/JavaScriptEventLoopTestSupportTests.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 | import XCTest
3 |
4 | final class JavaScriptEventLoopTestSupportTests: XCTestCase {
5 | func testAwaitMicrotask() async {
6 | let _: () = await withCheckedContinuation { cont in
7 | JSObject.global.queueMicrotask.function!(
8 | JSOneshotClosure { _ in
9 | cont.resume(returning: ())
10 | return .undefined
11 | }
12 | )
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Tests/JavaScriptEventLoopTests/JSTimerTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | @testable import JavaScriptKit
4 |
5 | final class JSTimerTests: XCTestCase {
6 |
7 | func testOneshotTimerCancelled() {
8 | let timeoutMilliseconds = 5.0
9 | var timeout: JSTimer!
10 | timeout = JSTimer(millisecondsDelay: timeoutMilliseconds, isRepeating: false) {
11 | XCTFail("timer should be cancelled")
12 | }
13 | _ = timeout
14 | timeout = nil
15 | }
16 |
17 | func testRepeatingTimerCancelled() async throws {
18 | var count = 0.0
19 | let maxCount = 5.0
20 | var interval: JSTimer?
21 | let start = JSDate().valueOf()
22 | let timeoutMilliseconds = 5.0
23 |
24 | await withCheckedContinuation { continuation in
25 | interval = JSTimer(millisecondsDelay: 5, isRepeating: true) {
26 | // ensure that JSTimer is living
27 | XCTAssertNotNil(interval)
28 | // verify that at least `timeoutMilliseconds * count` passed since the `timeout`
29 | // timer started
30 | XCTAssertTrue(start + timeoutMilliseconds * count <= JSDate().valueOf())
31 |
32 | guard count < maxCount else {
33 | // stop the timer after `maxCount` reached
34 | interval = nil
35 | continuation.resume()
36 | return
37 | }
38 |
39 | count += 1
40 | }
41 | }
42 | withExtendedLifetime(interval) {}
43 | }
44 |
45 | func testTimer() async throws {
46 | let timeoutMilliseconds = 5.0
47 | var timeout: JSTimer!
48 | await withCheckedContinuation { continuation in
49 | timeout = JSTimer(millisecondsDelay: timeoutMilliseconds, isRepeating: false) {
50 | continuation.resume()
51 | }
52 | }
53 | withExtendedLifetime(timeout) {}
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Tests/JavaScriptEventLoopTests/WebWorkerDedicatedExecutorTests.swift:
--------------------------------------------------------------------------------
1 | #if compiler(>=6.1) && _runtime(_multithreaded)
2 | import XCTest
3 | @testable import JavaScriptEventLoop
4 |
5 | final class WebWorkerDedicatedExecutorTests: XCTestCase {
6 | actor MyActor {
7 | let executor: WebWorkerDedicatedExecutor
8 | nonisolated var unownedExecutor: UnownedSerialExecutor {
9 | self.executor.asUnownedSerialExecutor()
10 | }
11 |
12 | init(executor: WebWorkerDedicatedExecutor) {
13 | self.executor = executor
14 | XCTAssertTrue(isMainThread())
15 | }
16 |
17 | func onWorkerThread() async {
18 | XCTAssertFalse(isMainThread())
19 | await Task.detached {}.value
20 | // Should keep on the thread after back from the other isolation domain
21 | XCTAssertFalse(isMainThread())
22 | }
23 | }
24 |
25 | func testEnqueue() async throws {
26 | let executor = try await WebWorkerDedicatedExecutor()
27 | defer { executor.terminate() }
28 | let actor = MyActor(executor: executor)
29 | XCTAssertTrue(isMainThread())
30 | await actor.onWorkerThread()
31 | XCTAssertTrue(isMainThread())
32 | }
33 | }
34 | #endif
35 |
--------------------------------------------------------------------------------
/Tests/JavaScriptKitTests/JSObjectTests.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 | import XCTest
3 |
4 | final class JSObjectTests: XCTestCase {
5 | func testEmptyObject() {
6 | let object = JSObject()
7 | let keys = JSObject.global.Object.function!.keys.function!(object)
8 | XCTAssertEqual(keys.array?.count, 0)
9 | }
10 |
11 | func testInitWithDictionaryLiteral() {
12 | let object: JSObject = [
13 | "key1": 1,
14 | "key2": "value2",
15 | "key3": .boolean(true),
16 | "key4": .object(JSObject()),
17 | "key5": [1, 2, 3].jsValue,
18 | "key6": ["key": "value"].jsValue,
19 | ]
20 | XCTAssertEqual(object.key1, .number(1))
21 | XCTAssertEqual(object.key2, "value2")
22 | XCTAssertEqual(object.key3, .boolean(true))
23 | let getKeys = JSObject.global.Object.function!.keys.function!
24 | XCTAssertEqual(getKeys(object.key4).array?.count, 0)
25 | XCTAssertEqual(object.key5.array.map(Array.init), [1, 2, 3])
26 | XCTAssertEqual(object.key6.object?.key, "value")
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Tests/JavaScriptKitTests/JSStringTests.swift:
--------------------------------------------------------------------------------
1 | import JavaScriptKit
2 | import XCTest
3 |
4 | final class JSStringTests: XCTestCase {
5 | func testEquatable() {
6 | let string1 = JSString("Hello, world!")
7 | let string2 = JSString("Hello, world!")
8 | let string3 = JSString("Hello, world")
9 | XCTAssertEqual(string1, string1)
10 | XCTAssertEqual(string1, string2)
11 | XCTAssertNotEqual(string1, string3)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Tests/JavaScriptKitTests/ThreadLocalTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | @testable import JavaScriptKit
4 |
5 | final class ThreadLocalTests: XCTestCase {
6 | class MyHeapObject {}
7 | struct MyStruct {
8 | var object: MyHeapObject
9 | }
10 |
11 | func testLeak() throws {
12 | struct Check {
13 | static let value = ThreadLocal()
14 | static let value2 = ThreadLocal(boxing: ())
15 | }
16 | weak var weakObject: MyHeapObject?
17 | do {
18 | let object = MyHeapObject()
19 | weakObject = object
20 | Check.value.wrappedValue = object
21 | XCTAssertNotNil(Check.value.wrappedValue)
22 | XCTAssertTrue(Check.value.wrappedValue === object)
23 | Check.value.wrappedValue = nil
24 | }
25 | XCTAssertNil(weakObject)
26 |
27 | weak var weakObject2: MyHeapObject?
28 | do {
29 | let object = MyHeapObject()
30 | weakObject2 = object
31 | Check.value2.wrappedValue = MyStruct(object: object)
32 | XCTAssertNotNil(Check.value2.wrappedValue)
33 | XCTAssertTrue(Check.value2.wrappedValue!.object === object)
34 | Check.value2.wrappedValue = nil
35 | }
36 | XCTAssertNil(weakObject2)
37 | }
38 |
39 | func testLazyThreadLocal() throws {
40 | struct Check {
41 | static let value = LazyThreadLocal(initialize: { MyHeapObject() })
42 | }
43 | let object1 = Check.value.wrappedValue
44 | let object2 = Check.value.wrappedValue
45 | XCTAssertTrue(object1 === object2)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "javascript-kit-swift",
3 | "version": "0.0.0",
4 | "description": "A runtime library of JavaScriptKit which is Swift framework to interact with JavaScript through WebAssembly.",
5 | "main": "Runtime/lib/index.js",
6 | "module": "Runtime/lib/index.mjs",
7 | "types": "Runtime/lib/index.d.ts",
8 | "files": [
9 | "Runtime/lib"
10 | ],
11 | "scripts": {
12 | "build": "npm run build:clean && npm run build:ts",
13 | "build:clean": "rm -rf Runtime/lib",
14 | "build:ts": "cd Runtime; rollup -c",
15 | "prepublishOnly": "npm run build",
16 | "format": "prettier --write Runtime/src"
17 | },
18 | "keywords": [
19 | "Swift",
20 | "WebAssembly",
21 | "wasm"
22 | ],
23 | "repository": {
24 | "type": "git",
25 | "url": "git+https://github.com/swiftwasm/JavaScriptKit.git"
26 | },
27 | "homepage": "https://github.com/swiftwasm/JavaScriptKit",
28 | "bugs": {
29 | "url": "https://github.com/swiftwasm/JavaScriptKit/issues"
30 | },
31 | "publishConfig": {
32 | "access": "public"
33 | },
34 | "author": "swiftwasm",
35 | "license": "MIT",
36 | "devDependencies": {
37 | "@bjorn3/browser_wasi_shim": "^0.4.1",
38 | "@rollup/plugin-typescript": "^12.1.2",
39 | "@types/node": "^22.13.14",
40 | "playwright": "^1.52.0",
41 | "prettier": "3.5.3",
42 | "rollup": "^4.37.0",
43 | "rollup-plugin-dts": "^6.2.1",
44 | "typescript": "^5.8.2"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------