diff --git a/.github/workflows/wasm-test.yaml b/.github/workflows/wasm-test.yaml index 3ce091b..93b2f12 100644 --- a/.github/workflows/wasm-test.yaml +++ b/.github/workflows/wasm-test.yaml @@ -37,7 +37,7 @@ jobs: run: npm install - name: Build - run: npm run compile + run: npm run build - name: Publish Dry Run if: "startsWith(github.ref, 'refs/tags/') && contains(github.ref, '-')" diff --git a/wasm/.gitignore b/wasm/.gitignore index a2b5be1..3b999bb 100644 --- a/wasm/.gitignore +++ b/wasm/.gitignore @@ -9,6 +9,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* +package-lock.json # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json @@ -121,7 +122,7 @@ dist .AppleDouble .LSOverride -# Icon must end with two +# Icon must end with two Icon diff --git a/wasm/README.md b/wasm/README.md index 8fec646..9618f4b 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -9,7 +9,7 @@ npm install @kcl-lang/wasm-lib ``` ```typescript -import { load, invokeKCLRun } from '@kcl-lang/wasm-lib' +import { load, invokeKCLRun } from "@kcl-lang/wasm-lib"; async function main() { const inst = await load(); @@ -21,10 +21,10 @@ schema Person: p = Person {name = "Alice"}`, }); - console.log(result) + console.log(result); } -main() +main(); ``` ### Rust diff --git a/wasm/examples/browser/.gitignore b/wasm/examples/browser/.gitignore new file mode 100644 index 0000000..3b999bb --- /dev/null +++ b/wasm/examples/browser/.gitignore @@ -0,0 +1,198 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node +# Edit at https://www.toptal.com/developers/gitignore?templates=node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +package-lock.json + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# End of https://www.toptal.com/developers/gitignore/api/node + +# Created by https://www.toptal.com/developers/gitignore/api/macos +# Edit at https://www.toptal.com/developers/gitignore?templates=macos + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +# End of https://www.toptal.com/developers/gitignore/api/macos + +# Created by https://www.toptal.com/developers/gitignore/api/windows +# Edit at https://www.toptal.com/developers/gitignore?templates=windows + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/windows + +#Added by cargo + +/target +Cargo.lock + +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +*.node diff --git a/wasm/examples/browser/kcl.wasm b/wasm/examples/browser/kcl.wasm new file mode 100644 index 0000000..77e7cae Binary files /dev/null and b/wasm/examples/browser/kcl.wasm differ diff --git a/wasm/examples/browser/package.json b/wasm/examples/browser/package.json new file mode 100644 index 0000000..d7d1ed7 --- /dev/null +++ b/wasm/examples/browser/package.json @@ -0,0 +1,35 @@ +{ + "name": "browser-kcl-wasm-example", + "version": "1.0.0", + "description": "", + "scripts": { + "serve": "webpack serve --config webpack.config.js", + "build": "webpack --mode=production", + "build:dev": "webpack --watch", + "format": "prettier --write ." + }, + "main": "./dist/main.js", + "types": "./dist/main.d.ts", + "files": [ + "dist/" + ], + "dependencies": { + "@kcl-lang/wasm-lib": "file:../..", + "@wasmer/wasi": "^1.2.2" + }, + "devDependencies": { + "copy-webpack-plugin": "^8.1.1", + "css-loader": "^5.2.4", + "cssnano": "^5.0.1", + "html-webpack-plugin": "^5.3.1", + "mini-css-extract-plugin": "^1.5.0", + "postcss": "^8.2.10", + "postcss-import": "^14.0.1", + "postcss-loader": "^5.2.0", + "prettier": "^2.8.4", + "typescript": "^5.3.3", + "webpack": "^5.34.0", + "webpack-cli": "^4.6.0", + "webpack-dev-server": "^3.11.2" + } +} diff --git a/wasm/examples/browser/src/index.html b/wasm/examples/browser/src/index.html new file mode 100644 index 0000000..2a4d837 --- /dev/null +++ b/wasm/examples/browser/src/index.html @@ -0,0 +1,18 @@ + + + + Button Click + + + + + + + diff --git a/wasm/examples/browser/src/main.ts b/wasm/examples/browser/src/main.ts new file mode 100644 index 0000000..5eb162c --- /dev/null +++ b/wasm/examples/browser/src/main.ts @@ -0,0 +1,16 @@ +import { load, invokeKCLRun } from "@kcl-lang/wasm-lib"; + +async function main() { + const inst = await load(); + const result = invokeKCLRun(inst, { + filename: "test.k", + source: ` +schema Person: + name: str + +p = Person {name = "Alice"}`, + }); + console.log(result); +} + +main(); diff --git a/wasm/examples/browser/tsconfig.json b/wasm/examples/browser/tsconfig.json new file mode 100644 index 0000000..9c7495e --- /dev/null +++ b/wasm/examples/browser/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "commonjs", + "moduleResolution": "node", + "lib": ["es2022", "dom"], + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "declaration": true, + "baseUrl": ".", + "esModuleInterop": true + }, + "exclude": ["node_modules"] +} diff --git a/wasm/examples/browser/webpack.config.js b/wasm/examples/browser/webpack.config.js new file mode 100644 index 0000000..e4087b2 --- /dev/null +++ b/wasm/examples/browser/webpack.config.js @@ -0,0 +1,71 @@ +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const path = require("path"); +const webpack = require("webpack"); + +const dist = path.resolve("./dist"); +const isProduction = process.argv.some((x) => x === "--mode=production"); +const hash = isProduction ? ".[contenthash]" : ""; + +module.exports = { + mode: "development", + entry: { + main: "./src/main.ts", + }, + target: "web", + output: { + path: dist, + filename: `[name]${hash}.js`, + clean: true, + }, + devServer: { + hot: true, + port: 9000, + }, + module: { + rules: [ + { + test: /\.css$/, + use: [MiniCssExtractPlugin.loader, "css-loader"], + }, + { + test: /\.m?js$/, + resourceQuery: { not: [/(raw|wasm)/] }, + }, + { + resourceQuery: /raw/, + type: "asset/source", + }, + { + resourceQuery: /wasm/, + type: "asset/resource", + generator: { + filename: "wasm/[name][ext]", + }, + }, + ], + }, + plugins: [ + new MiniCssExtractPlugin(), + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, "./src/index.html"), + }), + new webpack.IgnorePlugin({ + resourceRegExp: /^(path|ws|crypto|fs|os|util|node-fetch)$/, + }), + // needed by @wasmer/wasi + new webpack.ProvidePlugin({ + Buffer: ["buffer", "Buffer"], + }), + ], + externals: { + // needed by @wasmer/wasi + "wasmer_wasi_js_bg.wasm": true, + }, + resolve: { + fallback: { + // needed by @wasmer/wasi + buffer: require.resolve("buffer/"), + }, + }, +}; diff --git a/wasm/examples/node/.gitignore b/wasm/examples/node/.gitignore index a2b5be1..3b999bb 100644 --- a/wasm/examples/node/.gitignore +++ b/wasm/examples/node/.gitignore @@ -9,6 +9,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* +package-lock.json # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json @@ -121,7 +122,7 @@ dist .AppleDouble .LSOverride -# Icon must end with two +# Icon must end with two Icon diff --git a/wasm/examples/node/package-lock.json b/wasm/examples/node/package-lock.json deleted file mode 100644 index e7a2762..0000000 --- a/wasm/examples/node/package-lock.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "name": "run-kcl-wasm", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "run-kcl-wasm", - "version": "1.0.0", - "dependencies": { - "@kcl-lang/wasm-lib": "0.10.0-beta.2" - } - }, - "node_modules/.pnpm/@protobufjs+aspromise@1.1.2/node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@protobufjs+base64@1.1.2/node_modules/@protobufjs/base64": { - "version": "1.1.2", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@protobufjs+codegen@2.0.4/node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "extraneous": true, - "license": "BSD-3-Clause" - }, - "node_modules/.pnpm/@protobufjs+eventemitter@1.1.0/node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@protobufjs+fetch@1.1.0": { - "extraneous": true - }, - "node_modules/.pnpm/@protobufjs+float@1.0.2/node_modules/@protobufjs/float": { - "version": "1.0.2", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "benchmark": "^2.1.4", - "chalk": "^1.1.3", - "ieee754": "^1.1.8", - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@protobufjs+inquire@1.1.0/node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@protobufjs+path@1.1.2/node_modules/@protobufjs/path": { - "version": "1.1.2", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@protobufjs+pool@1.1.0/node_modules/@protobufjs/pool": { - "version": "1.1.0", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@protobufjs+utf8@1.1.0/node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "extraneous": true, - "license": "BSD-3-Clause", - "devDependencies": { - "istanbul": "^0.4.5", - "tape": "^4.6.3" - } - }, - "node_modules/.pnpm/@types+node@20.12.7": { - "extraneous": true - }, - "node_modules/.pnpm/kcl-lib@0.8.6-rc.1": { - "extraneous": true - }, - "node_modules/.pnpm/long@5.2.3/node_modules/long": { - "version": "5.2.3", - "extraneous": true, - "license": "Apache-2.0", - "devDependencies": { - "esm2umd": "^0.2.1" - } - }, - "node_modules/.pnpm/protobufjs@7.2.6": { - "extraneous": true - }, - "node_modules/.pnpm/undici-types@5.26.5/node_modules/undici-types": { - "version": "5.26.5", - "extraneous": true, - "license": "MIT" - }, - "node_modules/@kcl-lang/wasm-lib": { - "version": "0.10.0-beta.2", - "resolved": "https://registry.npmjs.org/@kcl-lang/wasm-lib/-/wasm-lib-0.10.0-beta.2.tgz", - "integrity": "sha512-+ExBvutGtt2MBJNUQv+gLArOeM2eGq/meJG+nd8jBn5W4zQpF/V/gq2fcsHgydNU5dHu6ilBI0mgbO1L3Gsu3w==", - "bundleDependencies": [ - "wasi-js" - ], - "dependencies": { - "wasi-js": "^1.7.3" - } - } - } -} diff --git a/wasm/examples/node/package.json b/wasm/examples/node/package.json index 687aa08..71528ff 100644 --- a/wasm/examples/node/package.json +++ b/wasm/examples/node/package.json @@ -3,8 +3,9 @@ "version": "1.0.0", "description": "", "scripts": { - "build": "tsc", - "dev": "node ./dist/main.js" + "build": "tsc --build", + "dev": "node ./dist/main.js", + "format": "prettier --write ." }, "main": "./dist/main.js", "types": "./dist/main.d.ts", @@ -12,6 +13,10 @@ "dist/" ], "dependencies": { - "@kcl-lang/wasm-lib": "0.10.0-beta.2" + "@kcl-lang/wasm-lib": "file:../.." + }, + "devDependencies": { + "prettier": "^2.8.4", + "typescript": "^5.3.3" } } diff --git a/wasm/examples/node/src/main.ts b/wasm/examples/node/src/main.ts index ef989ba..5eb162c 100644 --- a/wasm/examples/node/src/main.ts +++ b/wasm/examples/node/src/main.ts @@ -1,4 +1,4 @@ -import { load, invokeKCLRun } from '@kcl-lang/wasm-lib' +import { load, invokeKCLRun } from "@kcl-lang/wasm-lib"; async function main() { const inst = await load(); @@ -10,7 +10,7 @@ schema Person: p = Person {name = "Alice"}`, }); - console.log(result) + console.log(result); } -main() +main(); diff --git a/wasm/package-lock.json b/wasm/package-lock.json deleted file mode 100644 index 7e3e69e..0000000 --- a/wasm/package-lock.json +++ /dev/null @@ -1,228 +0,0 @@ -{ - "name": "@kcl-lang/wasm-lib", - "version": "0.10.0-beta.2", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@kcl-lang/wasm-lib", - "version": "0.10.0-beta.2", - "bundleDependencies": [ - "wasi-js" - ], - "license": "Apache-2.0", - "dependencies": { - "prettier": "^2.8.4", - "wasi-js": "^1.7.3" - }, - "devDependencies": { - "@types/node": "^20.11.0", - "prettier": "^2.8.4", - "typescript": "^5.3.3", - "wasi-js": "^1.7.3" - } - }, - "node_modules/@cowasm/memfs": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@cowasm/memfs/-/memfs-3.5.1.tgz", - "integrity": "sha512-TSz00K+BdLxAYFQvwHmKgM/eAK6h9OYSQhPTcv/9XSyOF0Q90EtMkJvtwirwAXunfTsZw8R9YMu1UU213ooVKw==", - "dev": true, - "inBundle": true, - "dependencies": { - "fs-monkey": "^1.0.3" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@cowasm/memfs/node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true, - "inBundle": true - }, - "node_modules/@types/node": { - "version": "20.12.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz", - "integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@wapython/unionfs": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@wapython/unionfs/-/unionfs-4.5.7.tgz", - "integrity": "sha512-7809nAVelP9TqXCq5c1yCwymPreTXrK4n4q/zxOlQOIIz4PNmoQmIKiLnwkKk39GDnLmP1MvP9ZkBDyXCCmTfg==", - "dev": true, - "inBundle": true, - "dependencies": { - "fs-monkey": "^1.0.0" - } - }, - "node_modules/@wapython/unionfs/node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true, - "inBundle": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "inBundle": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/fflate": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", - "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", - "dev": true, - "inBundle": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "inBundle": true - }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true, - "inBundle": true - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "inBundle": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "inBundle": true, - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true - }, - "node_modules/typedarray-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", - "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/wasi-js": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wasi-js/-/wasi-js-1.7.3.tgz", - "integrity": "sha512-4oq6iVdY4nlsqFviS98ltEdWnhYQoeZwz3/5AxQ3bs0fd/YBzBMS162p/n0DHEIJFev1Jvk3gnJwck1s4a8mVQ==", - "dev": true, - "hasInstallScript": true, - "inBundle": true, - "dependencies": { - "@cowasm/memfs": "^3.5.1", - "@wapython/unionfs": "^4.5.7", - "debug": "^4.3.4", - "fflate": "^0.7.3", - "path-browserify": "^1.0.0", - "randomfill": "^1.0.4", - "typedarray-to-buffer": "^4.0.0" - }, - "bin": { - "wasi-run": "bin/run.js" - } - } - } -} diff --git a/wasm/package.json b/wasm/package.json index 9041b41..ccccd58 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -13,19 +13,18 @@ "url": "git+https://github.com/kcl-lang/lib.git" }, "scripts": { - "compile": "tsc", + "build": "tsc --build", "format": "prettier --write ." }, "license": "Apache-2.0", "dependencies": { - "wasi-js": "^1.7.3", + "@wasmer/wasi": "^1.2.2", "prettier": "^2.8.4" }, "devDependencies": { "@types/node": "^20.11.0", "prettier": "^2.8.4", - "typescript": "^5.3.3", - "wasi-js": "^1.7.3" + "typescript": "^5.3.3" }, "bundleDependencies": [ "wasi-js" diff --git a/wasm/src/index.ts b/wasm/src/index.ts index 81b9d84..d6e95a7 100644 --- a/wasm/src/index.ts +++ b/wasm/src/index.ts @@ -1,8 +1,6 @@ -import WASI from "wasi-js"; -import wasiBindings from "wasi-js/dist/bindings/node"; -import { resolve } from "path"; - +import { init, WASI, MemFS } from "@wasmer/wasi"; const RUN_FUNCTION_NAME = "kcl_run"; +const FMT_FUNCTION_NAME = "kcl_fmt"; export interface KCLWasmLoadOptions { /** @@ -32,7 +30,8 @@ export interface KCLWasmLoadOptions { * * @default - The `fs` module from Node.js */ - fs?: typeof import("fs"); + fs?: MemFS; + /** * The bytes of the `kcl.wasm` data loaded into memory. * @@ -54,72 +53,70 @@ export interface RunOptions { source: string; } +export interface FmtOptions { + /** + * KCL code source + */ + source: string; +} + /** - * load a WASM + * load the KCL WASM * @param options * @returns */ export async function load(opts?: KCLWasmLoadOptions) { + await init(); const options = opts ?? {}; - const fs: typeof import("fs") = options.fs ?? require("fs"); - - let preopens: Record = {}; - // preopen everything - preopens["/"] = "/"; - preopens["."] = resolve("."); - - // add provided preopens - preopens = { - ...preopens, - ...(options.preopens ?? {}), + let preopens: Record = { + "/": "/", }; - // check if running in browser - const bindings = { - ...wasiBindings, - fs, - }; - - const wasi = new WASI({ - bindings, - env: { - ...process.env, - ...(options.env ?? {}), - }, - preopens, + const w = new WASI({ + env: options.env ?? {}, + preopens: preopens, + fs: options.fs, }); - const env = { - kclvm_plugin_invoke_json_wasm: ( - _method: number, - _args: number, - _kwargs: number - ) => { - // TODO - return 0; + let bytes: BufferSource; + if (options.data) { + bytes = options.data; + } else { + if (typeof window !== "undefined") { + const response = await fetch("../kcl.wasm"); + bytes = await response.arrayBuffer(); + } else if (typeof process !== "undefined") { + const fs = require("fs"); + const path = require("path"); + const wasmPath = path.resolve(__dirname, "../kcl.wasm"); + bytes = fs.readFileSync(wasmPath); + } else { + throw new Error("Unsupported environment"); + } + } + const imports = { + env: { + kclvm_plugin_invoke_json_wasm: ( + _method: number, + _args: number, + _kwargs: number + ) => { + // TODO: KCL WASM plugin impl + return 0; + }, }, - }; - - const importObject = { - wasi_snapshot_preview1: wasi.wasiImport, - env: env, ...(options.imports ?? {}), - } as any; - - const binary = - options.data ?? - new Uint8Array( - await fs.promises.readFile(resolve(__dirname, "../kcl.wasm")) - ); - const mod = new WebAssembly.Module(binary); - - const instance = new WebAssembly.Instance(mod, importObject); - wasi.start(instance); + } as object; - return instance; + const module = await WebAssembly.compile(bytes); + // Instantiate the WASI module + return w.instantiate(module, imports); } +/** + * Exported function to invoke the KCL run operation. + */ export function invokeKCLRun( instance: WebAssembly.Instance, opts: RunOptions @@ -144,6 +141,28 @@ export function invokeKCLRun( return resultStr; } +/** + * Exported function to invoke the KCL format operation. + */ +export function invokeKCLFmt( + instance: WebAssembly.Instance, + opts: FmtOptions +): string { + const exports = instance.exports as any; + const [sourcePtr, sourcePtrLength] = copyStringToWasmMemory( + instance, + opts.source + ); + const resultPtr = exports[FMT_FUNCTION_NAME](sourcePtr); + const [resultStr, resultPtrLength] = copyCStrFromWasmMemory( + instance, + resultPtr + ); + exports.kcl_free(sourcePtr, sourcePtrLength); + exports.kcl_free(resultPtr, resultPtrLength); + return resultStr; +} + function copyStringToWasmMemory( instance: WebAssembly.Instance, str: string diff --git a/wasm/tsconfig.json b/wasm/tsconfig.json index a1143ac..81f8964 100644 --- a/wasm/tsconfig.json +++ b/wasm/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "es2020", + "target": "es2022", "module": "commonjs", "moduleResolution": "node", - "lib": ["es2020", "dom"], + "lib": ["es2022", "dom"], "sourceMap": true, "outDir": "./dist", "rootDir": "./src",