├── .eslintrc.json ├── .github ├── dependabot.yml └── workflows │ ├── release.yml │ └── tests.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs └── vscode-container-wasm-gcc.png ├── package-lock.json ├── package.json ├── src ├── vendor │ └── wasm-wasi-core │ │ ├── .eslintignore │ │ ├── .eslintrc.json │ │ ├── .vscode-test-workspace │ │ └── dummy.txt │ │ ├── .vscodeignore │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── SECURITY.md │ │ ├── ThirdPartyNotices.txt │ │ ├── bin │ │ ├── esbuild.js │ │ └── updateVersion.mjs │ │ ├── build │ │ ├── pre-release.yml │ │ └── release.yml │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ ├── common │ │ │ ├── api.d.ts │ │ │ ├── api.ts │ │ │ ├── baseTypes.d.ts │ │ │ ├── baseTypes.ts │ │ │ ├── connection.d.ts │ │ │ ├── connection.ts │ │ │ ├── consoleDriver.d.ts │ │ │ ├── consoleDriver.ts │ │ │ ├── converter.d.ts │ │ │ ├── converter.ts │ │ │ ├── deviceDriver.d.ts │ │ │ ├── deviceDriver.ts │ │ │ ├── extLocFileSystemDriver.d.ts │ │ │ ├── extLocFileSystemDriver.ts │ │ │ ├── fileDescriptor.d.ts │ │ │ ├── fileDescriptor.ts │ │ │ ├── fileSystem.d.ts │ │ │ ├── fileSystem.ts │ │ │ ├── host.d.ts │ │ │ ├── host.ts │ │ │ ├── kernel.d.ts │ │ │ ├── kernel.ts │ │ │ ├── linkedMap.d.ts │ │ │ ├── linkedMap.ts │ │ │ ├── memoryFileSystemDriver.d.ts │ │ │ ├── memoryFileSystemDriver.ts │ │ │ ├── pipeDriver.d.ts │ │ │ ├── pipeDriver.ts │ │ │ ├── process.d.ts │ │ │ ├── process.ts │ │ │ ├── promises.d.ts │ │ │ ├── promises.ts │ │ │ ├── ral.d.ts │ │ │ ├── ral.ts │ │ │ ├── rootFileSystemDriver.d.ts │ │ │ ├── rootFileSystemDriver.ts │ │ │ ├── service.d.ts │ │ │ ├── service.ts │ │ │ ├── streams.d.ts │ │ │ ├── streams.ts │ │ │ ├── terminal.d.ts │ │ │ ├── terminal.ts │ │ │ ├── terminalDriver.d.ts │ │ │ ├── terminalDriver.ts │ │ │ ├── trace.d.ts │ │ │ ├── trace.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.publish.json │ │ │ ├── tsconfig.watch.json │ │ │ ├── version.d.ts │ │ │ ├── version.ts │ │ │ ├── vscodeFileSystemDriver.d.ts │ │ │ ├── vscodeFileSystemDriver.ts │ │ │ ├── wasi.d.ts │ │ │ ├── wasi.ts │ │ │ ├── wasiMeta.d.ts │ │ │ └── wasiMeta.ts │ │ └── web │ │ │ ├── connection.ts │ │ │ ├── extension.ts │ │ │ ├── mainWorker.ts │ │ │ ├── path.ts │ │ │ ├── process.ts │ │ │ ├── ril.ts │ │ │ ├── threadWorker.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.publish.json │ │ │ └── tsconfig.watch.json │ │ ├── tsconfig.json │ │ ├── tsconfig.publish.json │ │ ├── tsconfig.watch.json │ │ └── typings │ │ ├── webAssemblyCommon.d.ts │ │ └── webAssemblyNode.d.ts └── web │ ├── extension.d.ts │ ├── extension.ts │ ├── net │ ├── stack-worker.js │ ├── stack.js │ └── wasi-util.js │ └── test │ └── suite │ ├── extension.test.d.ts │ ├── extension.test.ts │ ├── index.d.ts │ └── index.ts ├── tsconfig.json └── webpack.config.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | }, 19 | "ignorePatterns": [ 20 | "**/*.d.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | # Automatic upgrade for Github Actions 5 | - package-ecosystem: "github-actions" 6 | directory: "/" # means ".github/workflows" 7 | schedule: 8 | interval: "daily" 9 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-22.04 10 | name: Build 11 | env: 12 | OUTPUT_DIR: ${{ github.workspace }}/release-out 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Setup vsce 16 | run: | 17 | npm install -g @vscode/vsce 18 | - name: Build package 19 | run: | 20 | mkdir ${OUTPUT_DIR} 21 | RELEASE_TAG="${GITHUB_REF##*/}" 22 | FILE_NAME="vscode-container-wasm-${RELEASE_TAG}.vsix" 23 | SHA256SUM_FILE_NAME="${FILE_NAME}.sha256sum" 24 | npm install 25 | vsce package -o "${OUTPUT_DIR}/${FILE_NAME}" 26 | ( cd ${OUTPUT_DIR}; sha256sum ${FILE_NAME} ) > "${OUTPUT_DIR}/${SHA256SUM_FILE_NAME}" 27 | - name: Save package 28 | uses: actions/upload-artifact@v4 29 | with: 30 | name: builds-package 31 | path: ${{ env.OUTPUT_DIR }}/* 32 | 33 | release: 34 | runs-on: ubuntu-22.04 35 | name: Release 36 | needs: [build] 37 | env: 38 | OUTPUT_DIR: ${{ github.workspace }}/builds 39 | steps: 40 | - uses: actions/checkout@v4 41 | - name: Download Builds 42 | uses: actions/download-artifact@v4 43 | with: 44 | path: ${{ env.OUTPUT_DIR }} 45 | - name: Create Release 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | run: | 49 | RELEASE_TAG="${GITHUB_REF##*/}" 50 | cat < ${GITHUB_WORKSPACE}/release-note.txt 51 | ${RELEASE_TAG} 52 | 53 | (TBD) 54 | EOF 55 | ASSET_ARGS=() 56 | ls -al ${OUTPUT_DIR}/ 57 | for F in ${OUTPUT_DIR}/builds-package/* ; do 58 | ASSET_ARGS+=("$F") 59 | done 60 | gh release create -F ${GITHUB_WORKSPACE}/release-note.txt --draft --title "${RELEASE_TAG}" "${RELEASE_TAG}" ${ASSET_ARGS[@]} 61 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-20.04 11 | name: Build 12 | strategy: 13 | matrix: 14 | node: [ 18, 20 ] 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version: ${{ matrix.node }} 20 | - name: Build 21 | run: | 22 | npm install 23 | npm run compile-web 24 | - name: Packaging 25 | run: | 26 | npm install -g @vscode/vsce 27 | vsce package 28 | 29 | project: 30 | name: Project Checks 31 | runs-on: ubuntu-20.04 32 | steps: 33 | - uses: actions/setup-go@v5 34 | with: 35 | go-version: 1.18.x 36 | - uses: actions/checkout@v4 37 | with: 38 | fetch-depth: 100 39 | - name: "Check DCO sign" 40 | run: | 41 | go install github.com/vbatts/git-validation@v1.1.0 42 | git-validation -v -run DCO 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | .vscode-test-web 6 | *.vsix 7 | 8 | src/vendor/wasm-wasi-core/dist 9 | src/vendor/wasm-wasi-core/node_modules 10 | src/vendor/wasm-wasi-core/.vscode-test-workspace/**/* 11 | !src/vendor/wasm-wasi-core/.vscode-test-workspace/dummy.txt 12 | src/vendor/wasm-wasi-core/lib -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Web Extension ", 10 | "type": "pwa-extensionHost", 11 | "debugWebWorkerHost": true, 12 | "request": "launch", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}", 15 | "--extensionDevelopmentKind=web" 16 | ], 17 | "outFiles": [ 18 | "${workspaceFolder}/dist/web/**/*.js" 19 | ], 20 | "preLaunchTask": "npm: watch-web" 21 | }, 22 | { 23 | "name": "Extension Tests", 24 | "type": "extensionHost", 25 | "debugWebWorkerHost": true, 26 | "request": "launch", 27 | "args": [ 28 | "--extensionDevelopmentPath=${workspaceFolder}", 29 | "--extensionDevelopmentKind=web", 30 | "--extensionTestsPath=${workspaceFolder}/dist/web/test/suite/index" 31 | ], 32 | "outFiles": [ 33 | "${workspaceFolder}/dist/web/**/*.js" 34 | ], 35 | "preLaunchTask": "npm: watch-web" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off", 11 | 12 | // "container.imageLocation": "out.wasm", 13 | "container.workspaceMountpoint": "/workspace", 14 | "container.networkingMode": "fetch" 15 | "container.imageLocation": "https://ktock.github.io/container2wasm-demo/containers/amd64-debian-wasi-container", 16 | "container.imageChunks": 5 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "compile-web", 9 | "group": { 10 | "kind": "build", 11 | "isDefault": true 12 | }, 13 | "problemMatcher": [ 14 | "$ts-webpack", 15 | "$tslint-webpack" 16 | ] 17 | }, 18 | { 19 | "type": "npm", 20 | "script": "watch-web", 21 | "group": "build", 22 | "isBackground": true, 23 | "problemMatcher": [ 24 | "$ts-webpack-watch", 25 | "$tslint-webpack-watch" 26 | ] 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test-web/** 3 | src/** 4 | out/** 5 | node_modules/** 6 | .gitignore 7 | vsc-extension-quickstart.md 8 | webpack.config.js 9 | .yarnrc 10 | **/tsconfig.json 11 | **/.eslintrc.json 12 | **/*.map 13 | **/*.ts 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 0.0.3 4 | 5 | - Add APIs used by imagemounter (#20) 6 | - Fix workspace mapping issues (#19) 7 | 8 | ## 0.0.2 9 | 10 | - Refactor + container image support (#14) 11 | 12 | ## 0.0.1 13 | 14 | - Initial release 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 vscode-container-wasm authors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-container-wasm: Containers on VSCode for the Web 2 | 3 | A VSCode extension for running containers on VSCode for the Web, relying on [`container2wasm`](https://github.com/ktock/container2wasm) for container to wasm conversion. 4 | 5 | This is an experimental software. 6 | 7 | ## Features 8 | 9 | This extension runs containers on VSCode for the Web and provides Terminal to interact to it. 10 | 11 | The containers run in the WebAssembly VM **on browser** so you don't need prepare remote containers. 12 | 13 | HTTP(S) networking is also available in the container with restrictions by the browser (CORS-restricted and no control over [Forbidden headers](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name)) (see also "Limitation" section). 14 | 15 | ### Quick Start 16 | 17 | 1. Open `ktock/vscode-container-wasm-gcc-example` on `github.dev` : https://github.dev/ktock/vscode-container-wasm-gcc-example?vscode-coi=on (you need `?vscode-coi=on` query in the URL) 18 | 2. Install `ktock.container-wasm` extension. 19 | 3. Run `> Run Container On Browser` in the command pallete. Then the container will be launched with the Terminal (can take some time to start the container). 20 | 21 | ![Container on browser](./docs/vscode-container-wasm-gcc.png) 22 | 23 | ## How to use 24 | 25 | - For repository visitors: 26 | - Open `github.dev` for the repo (if using `.` shortcut key, `?vscode-coi=on` needs to be manually added to the URL (this extension relies on SharedArrayBuffer)) 27 | - Install this extension 28 | - Launch a container by invoking `> Run Container On Browser` 29 | 30 | - For repository maintainers: 31 | - Option A: 32 | - Convert a container image to Wasm format using [`container2wasm`](https://github.com/ktock/container2wasm) converter. (e.g. `c2w ubuntu:22.04 out.wasm`) 33 | - Upload that Wasm image to a HTTP(S) server accessible from VSCode for the Web. 34 | - Set `container.imageLocation` (in `.vscode/settings.json`) to the URL of that image. 35 | - Option B: 36 | - Upload container image in [OCI Image Layout](https://github.com/opencontainers/image-spec/blob/v1.0.2/image-layout.md) to a HTTP(S) server accessible from the browser. Or you can use registry configured to allow CORS access. 37 | - Set `container.containerImage` (in `.vscode/settings.json`) to the URL of that image. Or if you used the registry as the server, write the image reference (i.e. `/:`) there. 38 | 39 | Example repos: 40 | - `gcc`: https://github.com/ktock/vscode-container-wasm-gcc-example 41 | - Debian + `curl`: https://github.com/ktock/vscode-container-wasm-debian-example 42 | 43 | ## Extension Settings 44 | 45 | - `container.imageLocation` *string* : Specify the URI of the Wasm-formatted container image (or the prefix if the Wasm image is chunked) 46 | - `container.imageChunks` *number* : Specify non zero value if the image is chunked with suffix (< 99) (default:0) 47 | - `container.imageWithDecompression` *bool* : Set true if the image needs gzip decompression (default: false) 48 | - `container.workspaceMountpoint` *string* : Specify path to mount the workspace in container (set "" to disable mount) (default: "/workspace") 49 | - `container.networkingMode` *string* : Networking mode (enum: `["none", "fetch"]`) (default: "fetch") 50 | - `container.containerImage` *string* : Address of container image 51 | - `container.helperImageLocation` *string* : Specify the URI of the Wasm-formatted networking helper image. 52 | - `container.helperImageWithDecompression` *bool* : Set true if the helper image needs decompression 53 | 54 | ## Limitation 55 | 56 | - This extension relies on SharedArrayBuffer. `?vscode-coi=on` query is needed for `github.dev` to make this extension work. 57 | - Networking from the container is limited to HTTP(S) and restricted by the browser's security rule (CORS-restricted, no control over [Forbidden headers](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name)). Please see also [the docs in container2wasm](https://github.com/ktock/container2wasm/tree/v0.5.1/examples/networking/fetch). 58 | 59 | ## Known Issues 60 | 61 | - Issue tracker of vscode-container-wasm: https://github.com/ktock/vscode-container-wasm/issues 62 | - Issue tracker of container2wasm: https://github.com/ktock/container2wasm/issues 63 | 64 | ## How it works 65 | 66 | - Image format: Container is converted to Wasm image using [container2wasm](https://github.com/ktock/container2wasm) to make it runnable on browser. 67 | - Wasi host: [`vscode-wasm`](https://github.com/microsoft/vscode-wasm) is used for the container image. It's patched to support containers and networking. 68 | - Networking: NW stack running on browser and it uses the browser's Fetch API for performing HTTP(S) networking. Please see also [the docs in container2wasm](https://github.com/ktock/container2wasm/tree/v0.5.1/examples/networking/fetch). 69 | 70 | ## FAQ 71 | 72 | ### "SharedArrayBuffer is not defined" error occurs when launching the container 73 | 74 | To make SharedArrayBuffer available, please add `?vscode-coi=on` query to the URL and reload. 75 | 76 | ## Release Notes 77 | 78 | See https://github.com/ktock/vscode-container-wasm/releases 79 | 80 | ## Acknowledgement 81 | 82 | This extension based on the following projects. 83 | They are included to this project and patched for our usecase (stored at [`./src/vendor/`](./src/vendor/)). 84 | 85 | - `vscode-wasm` (`wasm-wasi-core`) ([MIT License](https://github.com/microsoft/vscode-wasm/blob/main/LICENSE)) https://github.com/microsoft/vscode-wasm 86 | - `browser_wasi_shim` (either of [MIT License](https://github.com/bjorn3/browser_wasi_shim/blob/main/LICENSE-MIT) and [Apache License 2.0](https://github.com/bjorn3/browser_wasi_shim/blob/main/LICENSE-APACHE)): https://github.com/bjorn3/browser_wasi_shim 87 | -------------------------------------------------------------------------------- /docs/vscode-container-wasm-gcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktock/vscode-container-wasm/bc30c414e2476a51dbb9256ebc4f27a285372ed4/docs/vscode-container-wasm-gcc.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "container-wasm", 3 | "displayName": "container-wasm", 4 | "publisher": "ktock", 5 | "description": "Run Container On VSCode for the Web", 6 | "author": "ktock", 7 | "version": "0.0.3", 8 | "engines": { 9 | "vscode": "^1.83.0" 10 | }, 11 | "categories": [ 12 | "Other" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/ktock/vscode-container-wasm.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/ktock/vscode-container-wasm/issues" 20 | }, 21 | "browser": "./dist/web/extension.js", 22 | "activationEvents": [], 23 | "contributes": { 24 | "commands": [ 25 | { 26 | "command": "container-wasm.run", 27 | "title": "Run Container On Browser" 28 | } 29 | ], 30 | "configuration": { 31 | "title": "Container", 32 | "properties": { 33 | "container.imageLocation": { 34 | "type": "string", 35 | "default": "", 36 | "description": "Specifies the URI of the Wasm-formatted container image." 37 | }, 38 | "container.imageChunks": { 39 | "type": "number", 40 | "default": 0, 41 | "description": "Specify non zero value if the image is chunked with suffix (< 99)" 42 | }, 43 | "container.imageWithDecompression": { 44 | "type": "bool", 45 | "default": false, 46 | "description": "Set true if the image needs decompression" 47 | }, 48 | "container.workspaceMountpoint": { 49 | "type": "string", 50 | "default": "/workspace", 51 | "description": "Specify path to mount the workspace in container (set \"\" to disable mount)" 52 | }, 53 | "container.networkingMode": { 54 | "type": "string", 55 | "default": "fetch", 56 | "enum": [ 57 | "none", 58 | "fetch" 59 | ], 60 | "description": "Networking mode" 61 | }, 62 | "container.containerImage": { 63 | "type": "string", 64 | "default": "", 65 | "description": "Address of container image" 66 | }, 67 | "container.helperImageLocation": { 68 | "type": "string", 69 | "default": "", 70 | "description": "Specifies the URI of the Wasm-formatted networking helper image." 71 | }, 72 | "container.helperImageWithDecompression": { 73 | "type": "bool", 74 | "default": false, 75 | "description": "Set true if the helper image needs decompression" 76 | } 77 | } 78 | } 79 | }, 80 | "scripts": { 81 | "test": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=. --extensionTestsPath=dist/web/test/suite/index.js", 82 | "pretest": "npm run compile-web", 83 | "vscode:prepublish": "npm run package-web", 84 | "compile-web": "webpack", 85 | "watch-web": "webpack --watch", 86 | "package-web": "webpack --mode production --devtool hidden-source-map", 87 | "lint": "eslint src --ext ts", 88 | "run-in-browser": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=. ." 89 | }, 90 | "dependencies": { 91 | "uuid": "^9.0.0" 92 | }, 93 | "devDependencies": { 94 | "@bjorn3/browser_wasi_shim": "^0.2.17", 95 | "@types/mocha": "^10.0.2", 96 | "@types/uuid": "^9.0.1", 97 | "@types/vscode": "^1.83.0", 98 | "@types/webpack-env": "^1.18.2", 99 | "@typescript-eslint/eslint-plugin": "^6.7.3", 100 | "@typescript-eslint/parser": "^6.7.3", 101 | "@vscode/test-web": "^0.0.46", 102 | "assert": "^2.1.0", 103 | "eslint": "^8.50.0", 104 | "mocha": "^10.2.0", 105 | "process": "^0.11.10", 106 | "ts-loader": "^9.4.4", 107 | "typescript": "^5.2.2", 108 | "webpack": "^5.88.2", 109 | "webpack-cli": "^5.1.4" 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/.eslintignore: -------------------------------------------------------------------------------- 1 | lib 2 | dist -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.eslintrc.base.json", 3 | "root": true, 4 | "parserOptions": { 5 | "project": ["src/common/tsconfig.json", "src/common/test/tsconfig.json", "src/web/tsconfig.json", "src/web/test/tsconfig.json", "src/desktop/tsconfig.json", "src/desktop/test/tsconfig.json"] 6 | }, 7 | "rules": { 8 | "no-console": "error", 9 | "@typescript-eslint/no-floating-promises": "error" 10 | } 11 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/.vscode-test-workspace/dummy.txt: -------------------------------------------------------------------------------- 1 | // Dummy file. Please don't delete -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode-test/** 2 | .vscode-test-web/** 3 | .vscode-test-workspace/** 4 | bin/** 5 | build/** 6 | lib/** 7 | src/** 8 | typings/** 9 | .gitignore 10 | contributing.md 11 | **/*.ts 12 | **/*.map 13 | **/tsconfig.json 14 | **/tsconfig.base.json 15 | **/tsconfig.publish.json 16 | **/tsconfig.watch.json 17 | **/.eslintignore 18 | **/.eslintrc.json 19 | **/test/**/* 20 | .azure-pipelines.yml 21 | .lsifrc.json 22 | *.zip 23 | *.vsix 24 | *.lsif -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 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 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/README.md: -------------------------------------------------------------------------------- 1 | # WASM WASI Core Extension 2 | 3 | [![Build Status](https://dev.azure.com/vscode/vscode-wasm/_apis/build/status/microsoft.vscode-wasm?branchName=main)](https://dev.azure.com/vscode/vscode-wasm/_build/latest?definitionId=47&branchName=main) 4 | 5 | This VS Code library extension provides API to run [WASM](https://webassembly.org/) binaries in VS Code's extension host both in the desktop and the Web. The WASM file needs to be created with a [WASI](https://github.com/WebAssembly/WASI) compliant tool chain like the [WASI-SDK](https://github.com/WebAssembly/wasi-sdk) or [Rust](https://www.rust-lang.org/) using the `wasm32-wasi` target. 6 | 7 | The library extension supports the following WASI specifications: 8 | 9 | - [wasi_snapshot_preview1](https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md) 10 | - [thread support](https://github.com/WebAssembly/wasi-threads) 11 | 12 | Please note that WASI is work in progress. As a result, newer versions of this extension might not be backwards compatible with older WASI standards. 13 | 14 | There is also an additional npm module `@vscode/wasm-wasi` that eases the API access to the extension. 15 | 16 | ## Example 17 | 18 | The source code of the example can be found [here](https://github.com/microsoft/vscode-wasi/blob/dbaeumer/expected-baboon-red/wasm-wasi/example/package.json) 19 | 20 | First we need to define a `package.json` for the extension that wants to execute a WASM process: 21 | 22 | ```jsonc 23 | { 24 | "name": "...", 25 | ... 26 | // depend on the wasm-wasi-core extension 27 | "extensionDependencies": [ 28 | "ms-vscode.wasm-wasi-core" 29 | ], 30 | // Depend on the wasm-wasi facade npm module to get easier API access to the 31 | // core extension. 32 | "dependencies": { 33 | "@vscode/wasm-wasi": "..." 34 | }, 35 | } 36 | ``` 37 | 38 | The actual source code to execute a WASM process looks like this 39 | 40 | ```typescript 41 | // Load the WASM API 42 | const wasm: Wasm = await Wasm.load(); 43 | 44 | const pty = wasm.createPseudoterminal(); 45 | const terminal = window.createTerminal({ name: 'My Example', pty, isTransient: true }); 46 | terminal.show(true); 47 | const module = await WebAssembly.compile(await fs.readFile(...); 48 | const process = await wasm.createProcess('hello', module, { stdio: pty.stdio }); 49 | await process.run(); 50 | ``` -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/ThirdPartyNotices.txt: -------------------------------------------------------------------------------- 1 | NOTICES AND INFORMATION 2 | Do Not Translate or Localize 3 | 4 | This software incorporates material from third parties. 5 | Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com, 6 | or you may send a check or money order for US $5.00, including the product name, 7 | the open source component name, platform, and version number, to: 8 | 9 | Source Code Compliance Team 10 | Microsoft Corporation 11 | One Microsoft Way 12 | Redmond, WA 98052 13 | USA 14 | 15 | Notwithstanding any other terms, you may reverse engineer this software to the extent 16 | required to debug changes to any libraries licensed under the GNU Lesser General Public License. 17 | 18 | 19 | 20 | --------------------------------------------------------- 21 | 22 | uuid 9.0.0 - MIT 23 | https://github.com/uuidjs/uuid 24 | 25 | The MIT License (MIT) 26 | 27 | Copyright (c) 2010-2020 Robert Kieffer and other contributors 28 | 29 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 30 | 31 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 | --------------------------------------------------------- 35 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/bin/esbuild.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | //@ts-check 6 | const esbuild = require('esbuild'); 7 | const path = require('path'); 8 | const browser_assert = path.resolve(__dirname, '../node_modules/assert/build/assert.js'); 9 | 10 | /** @type esbuild.Plugin */ 11 | const assertResolvePlugin = { 12 | name: 'Assert Resolve', 13 | setup(build) { 14 | build.onResolve({ filter: /^assert$/g }, args => { 15 | if (args.kind === 'require-call' || args.kind === 'import-statement') { 16 | return { path: browser_assert }; 17 | } 18 | return { path: args.path }; 19 | }); 20 | }, 21 | }; 22 | 23 | 24 | /** 25 | * @typedef {import('esbuild').BuildOptions} BuildOptions 26 | */ 27 | 28 | /** @type BuildOptions */ 29 | const sharedWebOptions = { 30 | bundle: true, 31 | external: ['vscode'], 32 | target: 'es2020', 33 | platform: 'browser', 34 | sourcemap: true, 35 | }; 36 | 37 | /** @type BuildOptions */ 38 | const webOptions = { 39 | entryPoints: ['src/web/extension.ts'], 40 | outfile: 'dist/web/extension.js', 41 | format: 'cjs', 42 | ...sharedWebOptions, 43 | }; 44 | 45 | /** @type BuildOptions */ 46 | const webMainWorkerOptions = { 47 | entryPoints: ['src/web/mainWorker.ts'], 48 | outfile: 'dist/web/mainWorker.js', 49 | format: 'iife', 50 | ...sharedWebOptions, 51 | }; 52 | 53 | /** @type BuildOptions */ 54 | const webThreadWorkerOptions = { 55 | entryPoints: ['src/web/threadWorker.ts'], 56 | outfile: 'dist/web/threadWorker.js', 57 | format: 'iife', 58 | ...sharedWebOptions, 59 | }; 60 | 61 | /** @type BuildOptions */ 62 | const webTestsIndexOptions = { 63 | entryPoints: ['src/web/test/index.ts'], 64 | outfile: 'dist/web/test/index.js', 65 | define: { 66 | process: '{"env":{}}' 67 | }, 68 | plugins: [ assertResolvePlugin ], 69 | format: 'cjs', 70 | ...sharedWebOptions 71 | } 72 | 73 | /** @type BuildOptions */ 74 | const webTestWorkerOptions = { 75 | entryPoints: ['src/web/test/testWorker.ts'], 76 | outfile: 'dist/web/test/testWorker.js', 77 | define: { 78 | process: '{"env":{}}' 79 | }, 80 | plugins: [ assertResolvePlugin ], 81 | format: 'iife', 82 | ...sharedWebOptions 83 | } 84 | 85 | /** @type BuildOptions */ 86 | const sharedDesktopOptions = { 87 | bundle: true, 88 | external: ['vscode'], 89 | target: 'es2020', 90 | platform: 'node', 91 | sourcemap: true, 92 | }; 93 | 94 | /** @type BuildOptions */ 95 | const desktopOptions = { 96 | entryPoints: ['src/desktop/extension.ts'], 97 | outfile: 'dist/desktop/extension.js', 98 | format: 'cjs', 99 | ...sharedDesktopOptions, 100 | }; 101 | 102 | /** @type BuildOptions */ 103 | const desktopMainWorkerOptions = { 104 | entryPoints: ['src/desktop/mainWorker.ts'], 105 | outfile: 'dist/desktop/mainWorker.js', 106 | format: 'iife', 107 | ...sharedDesktopOptions, 108 | }; 109 | 110 | /** @type BuildOptions */ 111 | const desktopThreadWorkerOptions = { 112 | entryPoints: ['src/desktop/threadWorker.ts'], 113 | outfile: 'dist/desktop/threadWorker.js', 114 | format: 'iife', 115 | ...sharedDesktopOptions, 116 | }; 117 | 118 | function createContexts() { 119 | return Promise.all([ 120 | esbuild.context(webOptions), 121 | esbuild.context(webMainWorkerOptions), 122 | esbuild.context(webThreadWorkerOptions), 123 | esbuild.context(webTestsIndexOptions), 124 | esbuild.context(webTestWorkerOptions), 125 | esbuild.context(desktopOptions), 126 | esbuild.context(desktopMainWorkerOptions), 127 | esbuild.context(desktopThreadWorkerOptions) 128 | ]); 129 | } 130 | 131 | createContexts().then(contexts => { 132 | if (process.argv[2] === '--watch') { 133 | const promises = []; 134 | for (const context of contexts) { 135 | promises.push(context.watch()); 136 | } 137 | return Promise.all(promises).then(() => { return undefined; }); 138 | } else { 139 | const promises = []; 140 | for (const context of contexts) { 141 | promises.push(context.rebuild()); 142 | } 143 | Promise.all(promises).then(() => { 144 | for (const context of contexts) { 145 | context.dispose(); 146 | } 147 | }).then(() => { return undefined; }); 148 | } 149 | }).catch(console.error); 150 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/bin/updateVersion.mjs: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as fs from 'fs/promises'; 7 | 8 | import packJson from '../package.json' assert { type: 'json' }; 9 | 10 | const file = new URL('../src/common/version.ts', import.meta.url); 11 | const content = await fs.readFile(file, 'utf8') 12 | await fs.writeFile(file, content.replace(/const version = '.*?';/, `const version = '${packJson.version}';`)); -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/build/pre-release.yml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd)$(Rev:.r) 2 | 3 | trigger: none 4 | pr: none 5 | 6 | resources: 7 | repositories: 8 | - repository: templates 9 | type: github 10 | name: microsoft/vscode-engineering 11 | ref: main 12 | endpoint: Monaco 13 | 14 | parameters: 15 | - name: publishExtension 16 | displayName: 🚀 Publish Extension 17 | type: boolean 18 | default: false 19 | 20 | extends: 21 | template: azure-pipelines/extension/pre-release.yml@templates 22 | parameters: 23 | nodeVersion: 16.17.1 24 | buildSteps: 25 | - script: | 26 | npm ci 27 | workingDirectory: $(Build.SourcesDirectory) 28 | displayName: "Install dependencies" 29 | 30 | - script: | 31 | npm run compile 32 | npm run lint 33 | npm run esbuild 34 | workingDirectory: $(Build.SourcesDirectory)/wasm-wasi-core 35 | displayName: "Lint & Compile" 36 | 37 | ghCreateTag: true 38 | ghTagPrefix: pre-release/wasm-wasi-core/ 39 | 40 | publishExtension: ${{ parameters.publishExtension }} 41 | workingDirectory: $(Build.SourcesDirectory)/wasm-wasi-core -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/build/release.yml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd)$(Rev:.r) 2 | 3 | trigger: 4 | branches: 5 | include: 6 | - main 7 | pr: none 8 | 9 | resources: 10 | repositories: 11 | - repository: templates 12 | type: github 13 | name: microsoft/vscode-engineering 14 | ref: main 15 | endpoint: Monaco 16 | 17 | parameters: 18 | - name: publishExtension 19 | displayName: 🚀 Publish Extension 20 | type: boolean 21 | default: false 22 | 23 | extends: 24 | template: azure-pipelines/extension/stable.yml@templates 25 | parameters: 26 | nodeVersion: 16.17.1 27 | buildSteps: 28 | - script: | 29 | npm ci 30 | workingDirectory: $(Build.SourcesDirectory) 31 | displayName: 'Install dependencies' 32 | 33 | - script: | 34 | npm run compile 35 | npm run lint 36 | npm run esbuild 37 | workingDirectory: $(Build.SourcesDirectory)/wasm-wasi-core 38 | displayName: 'Lint & Compile' 39 | 40 | ghCreateTag: true 41 | ghTagPrefix: release/wasm-wasi-core/ 42 | 43 | tsa: 44 | enabled: true 45 | options: 46 | codebaseName: 'devdiv_$(Build.Repository.Name)' 47 | serviceTreeID: 'c4cd3983-4977-4bcd-931f-a9822d2e950c' 48 | instanceUrl: 'https://devdiv.visualstudio.com/defaultcollection' 49 | projectName: 'DevDiv' 50 | areaPath: 'DevDiv\\VS Code (compliance tracking only)\\Visual Studio Code Language Extensions' 51 | notificationAliases: 52 | - 'stbatt@microsoft.com' 53 | - 'lszomoru@microsoft.com' 54 | - 'dirkb@microsoft.com' 55 | 56 | publishExtension: ${{ parameters.publishExtension }} 57 | workingDirectory: $(Build.SourcesDirectory)/wasm-wasi-core -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wasm-wasi-core", 3 | "private": "true", 4 | "publisher": "ms-vscode", 5 | "version": "0.13.2", 6 | "displayName": "Experimental - WebAssembly Execution Engine", 7 | "description": "Experimental support to execute WebAssemblies on top of the VS Code API.", 8 | "author": "MS", 9 | "license": "MIT", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/microsoft/vscode-wasm.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/microsoft/vscode-wasm/issues" 16 | }, 17 | "homepage": "https://github.com/microsoft/vscode-wasm/blob/main/wasm-wasi-core/README.md", 18 | "keywords": [ 19 | "vscode", 20 | "webassembly", 21 | "wasm", 22 | "wasi" 23 | ], 24 | "engines": { 25 | "vscode": "^1.78.0" 26 | }, 27 | "main": "./dist/desktop/extension.js", 28 | "browser": "./dist/web/extension.js", 29 | "activationEvents": [], 30 | "dependencies": { 31 | "uuid": "^9.0.0" 32 | }, 33 | "devDependencies": { 34 | "@types/vscode": "1.78.0", 35 | "@types/uuid": "^9.0.1", 36 | "@types/assert": "^1.5.6", 37 | "assert": "^2.0.0", 38 | "find-process": "^1.4.7" 39 | }, 40 | "scripts": { 41 | "vscode:prepublish": "git clean -xfd . && npm install && npm run compile && npm run lint && npm run update:version && npm run esbuild", 42 | "build": "npm run compile", 43 | "compile": "node ../node_modules/typescript/lib/tsc.js -b tsconfig.json", 44 | "watch": "node ../node_modules/typescript/lib/tsc.js -b tsconfig.json -w", 45 | "clean": "node ../node_modules/rimraf/bin.js lib && node ../node_modules/rimraf/bin.js dist", 46 | "lint": "node ../node_modules/eslint/bin/eslint.js --ext ts src", 47 | "esbuild": "node ./bin/esbuild.js", 48 | "esbuild:watch": "node ./bin/esbuild.js --watch", 49 | "test": "npm run test:desktop && npm run test:web", 50 | "test:desktop": "node ./lib/desktop/test/runTests.js", 51 | "test:web": "npm run esbuild && node ./lib/web/test/runTests.js", 52 | "update:version": "node ./bin/updateVersion.mjs" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/baseTypes.d.ts: -------------------------------------------------------------------------------- 1 | export type u8 = number; 2 | export type u16 = number; 3 | export type u32 = number; 4 | export type u64 = bigint; 5 | export type s64 = bigint; 6 | export type ptr<_type = u8> = number; 7 | export type size = u32; 8 | export type byte = u8; 9 | export type bytes = byte[]; 10 | export type cstring = byte[]; 11 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/baseTypes.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | export type u8 = number; 7 | export type u16 = number; 8 | export type u32 = number; 9 | export type u64 = bigint; 10 | export type s64 = bigint; 11 | export type ptr<_type = u8> = number; 12 | 13 | export type size = u32; 14 | export type byte = u8; 15 | export type bytes = byte[]; 16 | // a \0 terminated string (e.g. C format) 17 | export type cstring = byte[]; -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/connection.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { ptr, u32 } from './baseTypes'; 3 | export declare namespace Offsets { 4 | const lock_size = 4; 5 | const lock_index = 0; 6 | const method_size = 4; 7 | const method_index: number; 8 | const errno_size = 2; 9 | const errno_index: number; 10 | const params_index: number; 11 | const header_size: number; 12 | } 13 | export interface StartMainMessage { 14 | readonly method: 'startMain'; 15 | readonly module: WebAssembly.Module; 16 | readonly memory?: WebAssembly.Memory; 17 | readonly trace?: boolean; 18 | } 19 | export declare namespace StartMainMessage { 20 | function is(message: ServiceMessage): message is StartMainMessage; 21 | } 22 | export interface StartThreadMessage { 23 | readonly method: 'startThread'; 24 | readonly module: WebAssembly.Module; 25 | readonly memory: WebAssembly.Memory; 26 | readonly tid: u32; 27 | readonly start_arg: ptr; 28 | readonly trace?: boolean; 29 | } 30 | export declare namespace StartThreadMessage { 31 | function is(message: ServiceMessage): message is StartThreadMessage; 32 | } 33 | export type ServiceMessage = StartMainMessage | StartThreadMessage | { 34 | method: string; 35 | }; 36 | export interface WorkerReadyMessage { 37 | readonly method: 'workerReady'; 38 | } 39 | export declare namespace WorkerReadyMessage { 40 | function is(message: WorkerMessage): message is WorkerReadyMessage; 41 | } 42 | export interface WorkerDoneMessage { 43 | readonly method: 'workerDone'; 44 | } 45 | export declare namespace WorkerDoneMessage { 46 | function is(message: WorkerMessage): message is WorkerReadyMessage; 47 | } 48 | export interface TraceMessage { 49 | readonly method: 'trace'; 50 | readonly message: string; 51 | readonly timeTaken: number; 52 | } 53 | export declare namespace TraceMessage { 54 | function is(message: WorkerMessage): message is TraceMessage; 55 | } 56 | export interface TraceSummaryMessage { 57 | readonly method: 'traceSummary'; 58 | readonly summary: string[]; 59 | } 60 | export declare namespace TraceSummaryMessage { 61 | function is(message: WorkerMessage): message is TraceSummaryMessage; 62 | } 63 | export type WasiCallMessage = [SharedArrayBuffer, SharedArrayBuffer]; 64 | export declare namespace WasiCallMessage { 65 | function is(message: WorkerMessage): message is WasiCallMessage; 66 | } 67 | export type WorkerMessage = WasiCallMessage | WorkerReadyMessage | WorkerDoneMessage | TraceMessage | TraceSummaryMessage | { 68 | method: string; 69 | }; 70 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/connection.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | /// 6 | 7 | import { ptr, u32 } from './baseTypes'; 8 | 9 | export namespace Offsets { 10 | export const lock_size = 4; 11 | export const lock_index = 0; 12 | // Method to call. 13 | export const method_size = 4; 14 | export const method_index = lock_index + lock_size; 15 | // Errno 16 | export const errno_size = 2; 17 | export const errno_index = method_index + method_size; 18 | // params 19 | export const params_index = errno_index + errno_size + 2; // 4 bytes alignment 20 | export const header_size = params_index; 21 | } 22 | 23 | export interface StartMainMessage { 24 | readonly method: 'startMain'; 25 | readonly module: WebAssembly.Module; 26 | readonly memory?: WebAssembly.Memory; 27 | readonly trace?: boolean; 28 | } 29 | export namespace StartMainMessage { 30 | export function is(message: ServiceMessage): message is StartMainMessage { 31 | const candidate = message as StartMainMessage; 32 | return candidate && candidate.method === 'startMain'; 33 | } 34 | } 35 | 36 | export interface StartThreadMessage { 37 | readonly method: 'startThread'; 38 | readonly module: WebAssembly.Module; 39 | readonly memory: WebAssembly.Memory; 40 | readonly tid: u32; 41 | readonly start_arg: ptr; 42 | readonly trace?: boolean; 43 | } 44 | export namespace StartThreadMessage { 45 | export function is(message: ServiceMessage): message is StartThreadMessage { 46 | const candidate = message as StartThreadMessage; 47 | return candidate && candidate.method === 'startThread'; 48 | } 49 | } 50 | 51 | export type ServiceMessage = StartMainMessage | StartThreadMessage | { method: string }; 52 | 53 | export interface WorkerReadyMessage { 54 | readonly method: 'workerReady'; 55 | } 56 | export namespace WorkerReadyMessage { 57 | export function is(message: WorkerMessage): message is WorkerReadyMessage { 58 | const candidate = message as WorkerReadyMessage; 59 | return candidate && candidate.method === 'workerReady'; 60 | } 61 | } 62 | 63 | export interface WorkerDoneMessage { 64 | readonly method: 'workerDone'; 65 | } 66 | export namespace WorkerDoneMessage { 67 | export function is(message: WorkerMessage): message is WorkerReadyMessage { 68 | const candidate = message as WorkerDoneMessage; 69 | return candidate && candidate.method === 'workerDone'; 70 | } 71 | } 72 | 73 | export interface TraceMessage { 74 | readonly method: 'trace'; 75 | readonly message: string; 76 | readonly timeTaken: number; 77 | } 78 | export namespace TraceMessage { 79 | export function is(message: WorkerMessage): message is TraceMessage { 80 | const candidate = message as TraceMessage; 81 | return candidate && candidate.method === 'trace'; 82 | } 83 | } 84 | 85 | export interface TraceSummaryMessage { 86 | readonly method: 'traceSummary'; 87 | readonly summary: string[]; 88 | } 89 | export namespace TraceSummaryMessage { 90 | export function is(message: WorkerMessage): message is TraceSummaryMessage { 91 | const candidate = message as TraceSummaryMessage; 92 | return candidate && candidate.method === 'traceSummary'; 93 | } 94 | } 95 | 96 | export type WasiCallMessage = [SharedArrayBuffer, SharedArrayBuffer]; 97 | export namespace WasiCallMessage { 98 | export function is(message: WorkerMessage): message is WasiCallMessage { 99 | return Array.isArray(message) && message.length === 2 && message[0] instanceof SharedArrayBuffer && message[1] instanceof SharedArrayBuffer; 100 | } 101 | } 102 | 103 | export type WorkerMessage = WasiCallMessage | WorkerReadyMessage | WorkerDoneMessage | TraceMessage | TraceSummaryMessage | { method: string }; -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/consoleDriver.d.ts: -------------------------------------------------------------------------------- 1 | import { CharacterDeviceDriver, DeviceId } from './deviceDriver'; 2 | import { Uri } from 'vscode'; 3 | export declare const uri: Uri; 4 | export declare function create(deviceId: DeviceId): CharacterDeviceDriver; 5 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/consoleDriver.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import { size } from './baseTypes'; 6 | import { fd, fdflags, fdstat, filestat, Filetype, Rights, rights } from './wasi'; 7 | import { CharacterDeviceDriver, DeviceDriverKind, DeviceId, NoSysDeviceDriver } from './deviceDriver'; 8 | import { BaseFileDescriptor, FileDescriptor } from './fileDescriptor'; 9 | import RAL from './ral'; 10 | import { Uri } from 'vscode'; 11 | 12 | const ConsoleBaseRights: rights = Rights.fd_read | Rights.fd_fdstat_set_flags | Rights.fd_write | 13 | Rights.fd_filestat_get | Rights.poll_fd_readwrite; 14 | 15 | const ConsoleInheritingRights = 0n; 16 | 17 | class ConsoleFileDescriptor extends BaseFileDescriptor { 18 | constructor(deviceId: bigint, fd: fd, rights_base: rights, rights_inheriting: rights, fdflags: fdflags, inode: bigint) { 19 | super(deviceId, fd, Filetype.character_device, rights_base, rights_inheriting, fdflags, inode); 20 | } 21 | 22 | public with(change: { fd: number }): FileDescriptor { 23 | return new ConsoleFileDescriptor(this.deviceId, change.fd, this.rights_base, this.rights_inheriting, this.fdflags, this.inode); 24 | } 25 | } 26 | 27 | export const uri: Uri = Uri.from({ scheme: 'wasi-console', authority: 'f36f1dd6-913a-417f-a53c-360730fde485' }); 28 | export function create(deviceId: DeviceId): CharacterDeviceDriver { 29 | 30 | let inodeCounter: bigint = 0n; 31 | const decoder = RAL().TextDecoder.create(); 32 | 33 | function createConsoleFileDescriptor(fd: 0 | 1 | 2): ConsoleFileDescriptor { 34 | return new ConsoleFileDescriptor(deviceId, fd, ConsoleBaseRights, ConsoleInheritingRights, 0, inodeCounter++); 35 | } 36 | 37 | const deviceDriver: Pick = { 38 | kind: DeviceDriverKind.character, 39 | id: deviceId, 40 | uri: uri, 41 | createStdioFileDescriptor(fd: 0 | 1 | 2): FileDescriptor { 42 | return createConsoleFileDescriptor(fd); 43 | }, 44 | fd_fdstat_get(fileDescriptor: FileDescriptor, result: fdstat): Promise { 45 | result.fs_filetype = fileDescriptor.fileType; 46 | result.fs_flags = fileDescriptor.fdflags; 47 | result.fs_rights_base = fileDescriptor.rights_base; 48 | result.fs_rights_inheriting = fileDescriptor.rights_inheriting; 49 | return Promise.resolve(); 50 | }, 51 | fd_filestat_get(fileDescriptor: FileDescriptor, result: filestat): Promise { 52 | result.dev = fileDescriptor.deviceId; 53 | result.ino = fileDescriptor.inode; 54 | result.filetype = Filetype.character_device; 55 | result.nlink = 0n; 56 | result.size = 101n; 57 | const now = BigInt(Date.now()); 58 | result.atim = now; 59 | result.ctim = now; 60 | result.mtim = now; 61 | return Promise.resolve(); 62 | }, 63 | fd_write(_fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise { 64 | let buffer: Uint8Array; 65 | if (buffers.length === 1) { 66 | buffer = buffers[0]; 67 | } else { 68 | const byteLength: number = buffers.reduce((prev, current) => prev + current.length, 0); 69 | buffer = new Uint8Array(byteLength); 70 | let offset = 0; 71 | for (const item of buffers) { 72 | buffer.set(item, offset); 73 | offset = item.byteLength; 74 | } 75 | } 76 | RAL().console.log(decoder.decode(buffer)); 77 | return Promise.resolve(buffer.byteLength); 78 | } 79 | }; 80 | 81 | return Object.assign({}, NoSysDeviceDriver, deviceDriver); 82 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/converter.d.ts: -------------------------------------------------------------------------------- 1 | import * as code from 'vscode'; 2 | import * as wasi from './wasi'; 3 | export declare namespace code2Wasi { 4 | function asFileType(fileType: code.FileType): wasi.filetype; 5 | function asErrno(code: string): wasi.errno; 6 | } 7 | export declare namespace BigInts { 8 | function asNumber(value: bigint): number; 9 | function max(...args: bigint[]): bigint; 10 | function min(...args: bigint[]): bigint; 11 | } 12 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/converter.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as code from 'vscode'; 7 | import * as wasi from './wasi'; 8 | 9 | export namespace code2Wasi { 10 | export function asFileType(fileType: code.FileType): wasi.filetype { 11 | switch (fileType) { 12 | case code.FileType.File: 13 | return wasi.Filetype.regular_file; 14 | case code.FileType.Directory: 15 | return wasi.Filetype.directory; 16 | case code.FileType.SymbolicLink: 17 | return wasi.Filetype.symbolic_link; 18 | default: 19 | return wasi.Filetype.unknown; 20 | } 21 | } 22 | export function asErrno(code: string): wasi.errno { 23 | switch (code) { 24 | case 'FileNotFound': 25 | return wasi.Errno.noent; 26 | case 'FileExists': 27 | return wasi.Errno.exist; 28 | case 'FileNotADirectory': 29 | return wasi.Errno.notdir; 30 | case 'FileIsADirectory': 31 | return wasi.Errno.isdir; 32 | case 'NoPermissions': 33 | return wasi.Errno.perm; 34 | case 'Unavailable': 35 | return wasi.Errno.busy; 36 | default: 37 | return wasi.Errno.inval; 38 | } 39 | } 40 | } 41 | 42 | export namespace BigInts { 43 | const MAX_VALUE_AS_BIGINT = BigInt(Number.MAX_VALUE); 44 | export function asNumber(value: bigint): number { 45 | if (value > MAX_VALUE_AS_BIGINT) { 46 | throw new wasi.WasiError(wasi.Errno.fbig); 47 | } 48 | return Number(value); 49 | } 50 | export function max(...args: bigint[]): bigint { 51 | return args.reduce((m, e) => e > m ? e : m); 52 | } 53 | 54 | export function min(...args: bigint[]): bigint { 55 | return args.reduce((m, e) => e < m ? e : m); 56 | } 57 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/deviceDriver.d.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import { size, u64 } from './baseTypes'; 3 | import { FdProvider, FileDescriptor } from './fileDescriptor'; 4 | import { advise, fd, fdflags, fdstat, filedelta, filesize, filestat, filetype, fstflags, lookupflags, oflags, rights, timestamp, whence } from './wasi'; 5 | export type DeviceId = bigint; 6 | export type ReaddirEntry = { 7 | d_ino: bigint; 8 | d_type: filetype; 9 | d_name: string; 10 | }; 11 | export declare enum DeviceDriverKind { 12 | character = "character", 13 | fileSystem = "fileSystem" 14 | } 15 | export interface DeviceDriver { 16 | /** 17 | * The kind of device driver. 18 | */ 19 | readonly kind: DeviceDriverKind; 20 | readonly uri: Uri; 21 | readonly id: DeviceId; 22 | fd_advise(fileDescriptor: FileDescriptor, offset: filesize, length: filesize, advise: advise): Promise; 23 | fd_allocate(fileDescriptor: FileDescriptor, offset: filesize, len: filesize): Promise; 24 | fd_close(fileDescriptor: FileDescriptor): Promise; 25 | fd_datasync(fileDescriptor: FileDescriptor): Promise; 26 | fd_fdstat_get(fileDescriptor: FileDescriptor, result: fdstat): Promise; 27 | fd_fdstat_set_flags(fileDescriptor: FileDescriptor, fdflags: fdflags): Promise; 28 | fd_filestat_get(fileDescriptor: FileDescriptor, result: filestat): Promise; 29 | fd_filestat_set_size(fileDescriptor: FileDescriptor, size: filesize): Promise; 30 | fd_filestat_set_times(fileDescriptor: FileDescriptor, atim: timestamp, mtim: timestamp, fst_flags: fstflags): Promise; 31 | fd_pread(fileDescriptor: FileDescriptor, offset: filesize, buffers: Uint8Array[]): Promise; 32 | fd_pwrite(fileDescriptor: FileDescriptor, offset: filesize, buffers: Uint8Array[]): Promise; 33 | fd_read(fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise; 34 | fd_readdir(fileDescriptor: FileDescriptor): Promise; 35 | fd_seek(fileDescriptor: FileDescriptor, offset: filedelta, whence: whence): Promise; 36 | fd_renumber(fileDescriptor: FileDescriptor, to: fd): Promise; 37 | fd_sync(fileDescriptor: FileDescriptor): Promise; 38 | fd_tell(fileDescriptor: FileDescriptor): Promise; 39 | fd_write(fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise; 40 | path_create_directory(fileDescriptor: FileDescriptor, path: string): Promise; 41 | path_filestat_get(fileDescriptor: FileDescriptor, flags: lookupflags, path: string, result: filestat): Promise; 42 | path_filestat_set_times(fileDescriptor: FileDescriptor, flags: lookupflags, path: string, atim: timestamp, mtim: timestamp, fst_flags: fstflags): Promise; 43 | path_link(old_fd: FileDescriptor, old_flags: lookupflags, old_path: string, new_fd: FileDescriptor, new_path: string): Promise; 44 | path_open(fileDescriptor: FileDescriptor, dirflags: lookupflags, path: string, oflags: oflags, fs_rights_base: rights, fs_rights_inheriting: rights, fdflags: fdflags, fdProvider: FdProvider): Promise; 45 | path_readlink(fileDescriptor: FileDescriptor, path: string): Promise; 46 | path_remove_directory(fileDescriptor: FileDescriptor, path: string): Promise; 47 | path_rename(oldFileDescriptor: FileDescriptor, old_path: string, newFileDescriptor: FileDescriptor, new_path: string): Promise; 48 | path_symlink(old_path: string, fileDescriptor: FileDescriptor, new_path: string): Promise; 49 | path_unlink_file(fileDescriptor: FileDescriptor, path: string): Promise; 50 | fd_create_prestat_fd(fd: fd): Promise; 51 | fd_bytesAvailable(fileDescriptor: FileDescriptor): Promise; 52 | } 53 | export interface FileSystemDeviceDriver extends DeviceDriver { 54 | kind: DeviceDriverKind.fileSystem; 55 | joinPath(...pathSegments: string[]): Uri | undefined; 56 | createStdioFileDescriptor(dirflags: lookupflags | undefined, path: string, oflags: oflags | undefined, fs_rights_base: rights | undefined, fdflags: fdflags | undefined, fd: 0 | 1 | 2): Promise; 57 | } 58 | export declare namespace FileSystemDeviceDriver { 59 | function is(value: DeviceDriver): value is FileSystemDeviceDriver; 60 | } 61 | export interface CharacterDeviceDriver extends DeviceDriver { 62 | kind: DeviceDriverKind.character; 63 | createStdioFileDescriptor(fd: 0 | 1 | 2): FileDescriptor; 64 | } 65 | export interface ReadonlyFileSystemDeviceDriver extends Pick { 66 | kind: DeviceDriverKind.fileSystem; 67 | } 68 | export declare const NoSysDeviceDriver: Omit; 69 | export declare const WritePermDeniedDeviceDriver: Pick; 70 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/deviceDriver.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { Uri } from 'vscode'; 7 | import { size, u64 } from './baseTypes'; 8 | import { FdProvider, FileDescriptor } from './fileDescriptor'; 9 | import { 10 | advise, Errno, fd, fdflags, fdstat,filedelta, filesize, filestat, filetype, 11 | fstflags, lookupflags, oflags, rights, timestamp, WasiError, whence 12 | } from './wasi'; 13 | 14 | export type DeviceId = bigint; 15 | 16 | export type ReaddirEntry = { d_ino: bigint; d_type: filetype; d_name: string }; 17 | 18 | export enum DeviceDriverKind { 19 | character = 'character', 20 | fileSystem = 'fileSystem' 21 | } 22 | 23 | export interface DeviceDriver { 24 | 25 | /** 26 | * The kind of device driver. 27 | */ 28 | readonly kind: DeviceDriverKind; 29 | 30 | // A VS Code URI to identify the device. This is for example the root URI 31 | // of a VS Code file system. 32 | readonly uri: Uri; 33 | 34 | // The unique device id. 35 | readonly id: DeviceId; 36 | 37 | fd_advise(fileDescriptor: FileDescriptor, offset: filesize, length: filesize, advise: advise): Promise; 38 | fd_allocate(fileDescriptor: FileDescriptor, offset: filesize, len: filesize): Promise; 39 | fd_close(fileDescriptor: FileDescriptor): Promise; 40 | fd_datasync(fileDescriptor: FileDescriptor): Promise; 41 | fd_fdstat_get(fileDescriptor: FileDescriptor, result: fdstat): Promise; 42 | fd_fdstat_set_flags(fileDescriptor: FileDescriptor, fdflags: fdflags): Promise; 43 | fd_filestat_get(fileDescriptor: FileDescriptor, result: filestat): Promise; 44 | fd_filestat_set_size(fileDescriptor: FileDescriptor, size: filesize): Promise; 45 | fd_filestat_set_times(fileDescriptor: FileDescriptor, atim: timestamp, mtim: timestamp, fst_flags: fstflags): Promise; 46 | fd_pread(fileDescriptor: FileDescriptor, offset: filesize, buffers: Uint8Array[]): Promise; 47 | fd_pwrite(fileDescriptor: FileDescriptor, offset: filesize, buffers: Uint8Array[]): Promise; 48 | fd_read(fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise; 49 | fd_readdir(fileDescriptor: FileDescriptor): Promise; 50 | fd_seek(fileDescriptor: FileDescriptor, offset: filedelta, whence: whence): Promise; 51 | fd_renumber(fileDescriptor: FileDescriptor, to: fd): Promise; 52 | fd_sync(fileDescriptor: FileDescriptor): Promise; 53 | fd_tell(fileDescriptor: FileDescriptor): Promise; 54 | fd_write(fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise; 55 | 56 | path_create_directory(fileDescriptor: FileDescriptor, path: string): Promise; 57 | path_filestat_get(fileDescriptor: FileDescriptor, flags: lookupflags, path: string, result: filestat): Promise; 58 | path_filestat_set_times(fileDescriptor: FileDescriptor, flags: lookupflags, path: string, atim: timestamp, mtim: timestamp, fst_flags: fstflags): Promise; 59 | path_link(old_fd: FileDescriptor, old_flags: lookupflags, old_path: string, new_fd: FileDescriptor, new_path: string): Promise; 60 | path_open(fileDescriptor: FileDescriptor, dirflags: lookupflags, path: string, oflags: oflags, fs_rights_base: rights, fs_rights_inheriting: rights, fdflags: fdflags, fdProvider: FdProvider): Promise; 61 | path_readlink(fileDescriptor: FileDescriptor, path: string): Promise; 62 | path_remove_directory(fileDescriptor: FileDescriptor, path: string): Promise; 63 | path_rename(oldFileDescriptor: FileDescriptor, old_path: string, newFileDescriptor: FileDescriptor, new_path: string): Promise; 64 | path_symlink(old_path: string, fileDescriptor: FileDescriptor, new_path: string): Promise; 65 | path_unlink_file(fileDescriptor: FileDescriptor, path: string): Promise; 66 | 67 | fd_create_prestat_fd(fd: fd): Promise; 68 | fd_bytesAvailable(fileDescriptor: FileDescriptor): Promise; 69 | } 70 | 71 | export interface FileSystemDeviceDriver extends DeviceDriver { 72 | kind: DeviceDriverKind.fileSystem; 73 | joinPath( ...pathSegments: string[]): Uri | undefined; 74 | createStdioFileDescriptor(dirflags: lookupflags | undefined, path: string, oflags: oflags | undefined, fs_rights_base: rights | undefined, fdflags: fdflags | undefined, fd: 0 | 1 | 2): Promise; 75 | } 76 | 77 | export namespace FileSystemDeviceDriver { 78 | export function is(value: DeviceDriver): value is FileSystemDeviceDriver { 79 | const candidate: FileSystemDeviceDriver = value as FileSystemDeviceDriver; 80 | return candidate.kind === DeviceDriverKind.fileSystem; 81 | } 82 | } 83 | 84 | export interface CharacterDeviceDriver extends DeviceDriver { 85 | kind: DeviceDriverKind.character; 86 | createStdioFileDescriptor(fd: 0 | 1 | 2): FileDescriptor; 87 | } 88 | 89 | export interface ReadonlyFileSystemDeviceDriver extends Pick< 90 | FileSystemDeviceDriver, 'kind' | 'joinPath' | 'createStdioFileDescriptor' | 'uri' | 'id' | 91 | 'fd_advise' | 'fd_close' | 'fd_fdstat_get' | 'fd_filestat_get' | 'fd_pread' | 'fd_read' | 'fd_readdir' | 'fd_seek' | 92 | 'fd_renumber' | 'fd_tell' | 'path_filestat_get' | 'path_open' | 'path_readlink' | 'fd_create_prestat_fd' | 'fd_bytesAvailable' 93 | > { 94 | kind: DeviceDriverKind.fileSystem; 95 | } 96 | 97 | export const NoSysDeviceDriver: Omit = { 98 | fd_advise(): Promise { 99 | throw new WasiError(Errno.nosys); 100 | }, 101 | fd_allocate(): Promise { 102 | throw new WasiError(Errno.nosys); 103 | }, 104 | fd_close(): Promise { 105 | throw new WasiError(Errno.nosys); 106 | }, 107 | fd_datasync(): Promise { 108 | throw new WasiError(Errno.nosys); 109 | }, 110 | fd_fdstat_get(): Promise { 111 | throw new WasiError(Errno.nosys); 112 | }, 113 | fd_fdstat_set_flags(): Promise { 114 | throw new WasiError(Errno.nosys); 115 | }, 116 | fd_filestat_get(): Promise { 117 | throw new WasiError(Errno.nosys); 118 | }, 119 | fd_filestat_set_size(): Promise { 120 | throw new WasiError(Errno.nosys); 121 | }, 122 | fd_filestat_set_times(): Promise { 123 | throw new WasiError(Errno.nosys); 124 | }, 125 | fd_pread(): Promise { 126 | throw new WasiError(Errno.nosys); 127 | }, 128 | fd_pwrite(): Promise { 129 | throw new WasiError(Errno.nosys); 130 | }, 131 | fd_read(): Promise { 132 | throw new WasiError(Errno.nosys); 133 | }, 134 | fd_readdir(): Promise { 135 | throw new WasiError(Errno.nosys); 136 | }, 137 | fd_seek(): Promise { 138 | throw new WasiError(Errno.nosys); 139 | }, 140 | fd_renumber(): Promise { 141 | throw new WasiError(Errno.nosys); 142 | }, 143 | fd_sync(): Promise { 144 | throw new WasiError(Errno.nosys); 145 | }, 146 | fd_tell(): Promise { 147 | throw new WasiError(Errno.nosys); 148 | }, 149 | fd_write(): Promise { 150 | throw new WasiError(Errno.nosys); 151 | }, 152 | path_create_directory(): Promise { 153 | throw new WasiError(Errno.nosys); 154 | }, 155 | path_filestat_get(): Promise { 156 | throw new WasiError(Errno.nosys); 157 | }, 158 | path_filestat_set_times(): Promise { 159 | throw new WasiError(Errno.nosys); 160 | }, 161 | path_link(): Promise { 162 | throw new WasiError(Errno.nosys); 163 | }, 164 | path_open(): Promise { 165 | throw new WasiError(Errno.nosys); 166 | }, 167 | path_readlink(): Promise { 168 | throw new WasiError(Errno.nosys); 169 | }, 170 | path_remove_directory(): Promise { 171 | throw new WasiError(Errno.nosys); 172 | }, 173 | path_rename(): Promise { 174 | throw new WasiError(Errno.nosys); 175 | }, 176 | path_symlink(): Promise { 177 | throw new WasiError(Errno.nosys); 178 | }, 179 | path_unlink_file(): Promise { 180 | throw new WasiError(Errno.nosys); 181 | }, 182 | fd_create_prestat_fd(): Promise { 183 | throw new WasiError(Errno.nosys); 184 | }, 185 | fd_bytesAvailable(): Promise { 186 | throw new WasiError(Errno.nosys); 187 | } 188 | }; 189 | 190 | export const WritePermDeniedDeviceDriver: Pick = { 195 | fd_allocate(): Promise { 196 | throw new WasiError(Errno.perm); 197 | }, 198 | fd_datasync(): Promise { 199 | throw new WasiError(Errno.perm); 200 | }, 201 | fd_fdstat_set_flags(): Promise { 202 | throw new WasiError(Errno.perm); 203 | }, 204 | fd_filestat_set_size(): Promise { 205 | throw new WasiError(Errno.perm); 206 | }, 207 | fd_filestat_set_times(): Promise { 208 | throw new WasiError(Errno.perm); 209 | }, 210 | fd_pwrite(): Promise { 211 | throw new WasiError(Errno.perm); 212 | }, 213 | fd_renumber(): Promise { 214 | throw new WasiError(Errno.perm); 215 | }, 216 | fd_sync(): Promise { 217 | throw new WasiError(Errno.perm); 218 | }, 219 | fd_write(): Promise { 220 | throw new WasiError(Errno.perm); 221 | }, 222 | path_create_directory(): Promise { 223 | throw new WasiError(Errno.perm); 224 | }, 225 | path_filestat_set_times(): Promise { 226 | throw new WasiError(Errno.perm); 227 | }, 228 | path_link(): Promise { 229 | throw new WasiError(Errno.perm); 230 | }, 231 | path_remove_directory(): Promise { 232 | throw new WasiError(Errno.perm); 233 | }, 234 | path_rename(): Promise { 235 | throw new WasiError(Errno.perm); 236 | }, 237 | path_symlink(): Promise { 238 | throw new WasiError(Errno.perm); 239 | }, 240 | path_unlink_file(): Promise { 241 | throw new WasiError(Errno.nosys); 242 | } 243 | }; -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/extLocFileSystemDriver.d.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import { DeviceId, FileSystemDeviceDriver } from '../common/deviceDriver'; 3 | declare namespace Dump { 4 | type FileNode = { 5 | kind: 'file'; 6 | name: string; 7 | size: string; 8 | ctime: string; 9 | atime: string; 10 | mtime: string; 11 | }; 12 | type DirectoryNode = { 13 | kind: 'directory'; 14 | name: string; 15 | size: string; 16 | ctime: string; 17 | atime: string; 18 | mtime: string; 19 | children: { 20 | [key: string]: Node; 21 | }; 22 | }; 23 | type Node = FileNode | DirectoryNode; 24 | } 25 | export declare function create(deviceId: DeviceId, baseUri: Uri, dump: Dump.DirectoryNode): FileSystemDeviceDriver; 26 | export {}; 27 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/fileDescriptor.d.ts: -------------------------------------------------------------------------------- 1 | import { DeviceDriver } from './deviceDriver'; 2 | import { fd, fdflags, filetype, oflags, rights } from './wasi'; 3 | type DeviceId = bigint; 4 | export interface FileDescriptor { 5 | readonly deviceId: DeviceId; 6 | /** 7 | * The WASI file descriptor id 8 | */ 9 | readonly fd: fd; 10 | /** 11 | * The file type 12 | */ 13 | readonly fileType: filetype; 14 | /** 15 | * The base rights. 16 | */ 17 | readonly rights_base: rights; 18 | /** 19 | * The inheriting rights 20 | */ 21 | readonly rights_inheriting: rights; 22 | /** 23 | * The file descriptor flags. 24 | */ 25 | fdflags: fdflags; 26 | /** 27 | * The inode the file descriptor is pointing to. 28 | */ 29 | readonly inode: bigint; 30 | /** 31 | * Dispose resource associated with this file descriptor. 32 | */ 33 | dispose?(): Promise; 34 | /** 35 | * Create a new file descriptor with the given changes. 36 | * 37 | * @param change The changes to apply to the file descriptor. 38 | */ 39 | with(change: { 40 | fd: fd; 41 | }): FileDescriptor; 42 | /** 43 | * Check if the base rights contain the given rights. 44 | * 45 | * @param rights The rights to check. 46 | */ 47 | containsBaseRights(rights: rights): boolean; 48 | /** 49 | * Asserts the given rights. 50 | * 51 | * @param right the rights to assert. 52 | */ 53 | assertRights(rights: rights): void; 54 | /** 55 | * Asserts the given base rights. 56 | * 57 | * @param right the rights to assert. 58 | */ 59 | assertBaseRights(rights: rights): void; 60 | /** 61 | * Asserts the given base rights. 62 | * 63 | * @param right the rights to assert. 64 | */ 65 | assertInheritingRights(rights: rights): void; 66 | /** 67 | * Asserts the given fdflags. 68 | * 69 | * @param fdflags The fdflags to assert. 70 | */ 71 | assertFdflags(fdflags: fdflags): void; 72 | /** 73 | * Asserts the given oflags. 74 | * 75 | * @param oflags The oflags to assert. 76 | */ 77 | assertOflags(oflags: oflags): void; 78 | /** 79 | * Asserts that the file descriptor points to a directory. 80 | */ 81 | assertIsDirectory(): void; 82 | } 83 | export declare abstract class BaseFileDescriptor implements FileDescriptor { 84 | readonly deviceId: bigint; 85 | readonly fd: fd; 86 | readonly fileType: filetype; 87 | readonly rights_base: rights; 88 | readonly rights_inheriting: rights; 89 | fdflags: fdflags; 90 | readonly inode: bigint; 91 | constructor(deviceId: bigint, fd: fd, fileType: filetype, rights_base: rights, rights_inheriting: rights, fdflags: fdflags, inode: bigint); 92 | dispose?(): Promise; 93 | abstract with(change: { 94 | fd: fd; 95 | }): FileDescriptor; 96 | containsBaseRights(rights: rights): boolean; 97 | assertRights(rights: rights): void; 98 | assertBaseRights(rights: rights): void; 99 | assertInheritingRights(rights: rights): void; 100 | assertFdflags(fdflags: fdflags): void; 101 | assertOflags(oflags: oflags): void; 102 | assertIsDirectory(): void; 103 | } 104 | export interface FdProvider { 105 | next(): fd; 106 | } 107 | export declare class FileDescriptors implements FdProvider { 108 | private readonly descriptors; 109 | private readonly rootDescriptors; 110 | private mode; 111 | private counter; 112 | private firstReal; 113 | constructor(); 114 | get firstRealFileDescriptor(): fd; 115 | next(): fd; 116 | switchToRunning(start: fd): void; 117 | add(descriptor: FileDescriptor): void; 118 | get(fd: fd): FileDescriptor; 119 | has(fd: fd): boolean; 120 | delete(descriptor: FileDescriptor): boolean; 121 | setRoot(driver: DeviceDriver, descriptor: FileDescriptor): void; 122 | getRoot(driver: DeviceDriver): FileDescriptor | undefined; 123 | entries(): IterableIterator<[number, FileDescriptor]>; 124 | keys(): IterableIterator; 125 | values(): IterableIterator; 126 | [Symbol.iterator](): IterableIterator<[number, FileDescriptor]>; 127 | } 128 | export {}; 129 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/fileDescriptor.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { DeviceDriver } from './deviceDriver'; 7 | import { 8 | Errno, fd, fdflags, Filetype, filetype, oflags, Rights, rights, WasiError 9 | } from './wasi'; 10 | 11 | type DeviceId = bigint; 12 | 13 | export interface FileDescriptor { 14 | 15 | readonly deviceId: DeviceId; 16 | 17 | /** 18 | * The WASI file descriptor id 19 | */ 20 | readonly fd: fd; 21 | 22 | /** 23 | * The file type 24 | */ 25 | readonly fileType: filetype; 26 | 27 | /** 28 | * The base rights. 29 | */ 30 | readonly rights_base: rights; 31 | 32 | /** 33 | * The inheriting rights 34 | */ 35 | readonly rights_inheriting: rights; 36 | 37 | /** 38 | * The file descriptor flags. 39 | */ 40 | fdflags: fdflags; 41 | 42 | /** 43 | * The inode the file descriptor is pointing to. 44 | */ 45 | readonly inode: bigint; 46 | 47 | /** 48 | * Dispose resource associated with this file descriptor. 49 | */ 50 | dispose?(): Promise; 51 | 52 | /** 53 | * Create a new file descriptor with the given changes. 54 | * 55 | * @param change The changes to apply to the file descriptor. 56 | */ 57 | with(change: { fd: fd }): FileDescriptor; 58 | 59 | /** 60 | * Check if the base rights contain the given rights. 61 | * 62 | * @param rights The rights to check. 63 | */ 64 | containsBaseRights(rights: rights): boolean; 65 | 66 | /** 67 | * Asserts the given rights. 68 | * 69 | * @param right the rights to assert. 70 | */ 71 | assertRights(rights: rights): void; 72 | 73 | /** 74 | * Asserts the given base rights. 75 | * 76 | * @param right the rights to assert. 77 | */ 78 | assertBaseRights(rights: rights): void; 79 | 80 | /** 81 | * Asserts the given base rights. 82 | * 83 | * @param right the rights to assert. 84 | */ 85 | assertInheritingRights(rights: rights): void; 86 | 87 | /** 88 | * Asserts the given fdflags. 89 | * 90 | * @param fdflags The fdflags to assert. 91 | */ 92 | assertFdflags(fdflags: fdflags): void; 93 | 94 | /** 95 | * Asserts the given oflags. 96 | * 97 | * @param oflags The oflags to assert. 98 | */ 99 | assertOflags(oflags: oflags): void; 100 | 101 | /** 102 | * Asserts that the file descriptor points to a directory. 103 | */ 104 | assertIsDirectory(): void; 105 | } 106 | 107 | export abstract class BaseFileDescriptor implements FileDescriptor { 108 | 109 | public readonly deviceId: bigint; 110 | 111 | public readonly fd: fd; 112 | 113 | public readonly fileType: filetype; 114 | 115 | public readonly rights_base: rights; 116 | 117 | public readonly rights_inheriting: rights; 118 | 119 | public fdflags: fdflags; 120 | 121 | public readonly inode: bigint; 122 | 123 | constructor(deviceId: bigint, fd: fd, fileType: filetype, rights_base: rights, rights_inheriting: rights, fdflags: fdflags, inode: bigint) { 124 | this.deviceId = deviceId; 125 | this.fd = fd; 126 | this.fileType = fileType; 127 | this.rights_base = rights_base; 128 | this.rights_inheriting = rights_inheriting; 129 | this.fdflags = fdflags; 130 | this.inode = inode; 131 | } 132 | 133 | dispose?(): Promise; 134 | 135 | abstract with(change: { fd: fd }): FileDescriptor; 136 | 137 | public containsBaseRights(rights: rights): boolean { 138 | return (this.rights_base & rights) === rights; 139 | } 140 | 141 | public assertRights(rights: rights): void { 142 | if (((this.rights_base | this.rights_inheriting) & rights) === rights) { 143 | return; 144 | } 145 | throw new WasiError(Errno.perm); 146 | } 147 | 148 | public assertBaseRights(rights: rights): void { 149 | if ((this.rights_base & rights) === rights) { 150 | return; 151 | } 152 | throw new WasiError(Errno.perm); 153 | } 154 | 155 | public assertInheritingRights(rights: rights): void { 156 | if ((this.rights_inheriting & rights) === rights) { 157 | return; 158 | } 159 | throw new WasiError(Errno.perm); 160 | } 161 | 162 | 163 | public assertFdflags(fdflags: fdflags): void { 164 | if (!Rights.supportFdflags(this.rights_base, fdflags)) { 165 | throw new WasiError(Errno.perm); 166 | } 167 | } 168 | 169 | public assertOflags(oflags: oflags): void { 170 | if (!Rights.supportOflags(this.rights_base, oflags)) { 171 | throw new WasiError(Errno.perm); 172 | } 173 | } 174 | 175 | public assertIsDirectory(): void { 176 | if (this.fileType !== Filetype.directory) { 177 | throw new WasiError(Errno.notdir); 178 | } 179 | } 180 | } 181 | 182 | export interface FdProvider { 183 | next(): fd; 184 | } 185 | 186 | export class FileDescriptors implements FdProvider { 187 | 188 | private readonly descriptors: Map = new Map(); 189 | private readonly rootDescriptors: Map = new Map(); 190 | 191 | private mode: 'init' | 'running' = 'init'; 192 | private counter: fd = 0; 193 | private firstReal: fd = 3; 194 | 195 | constructor() { 196 | } 197 | 198 | public get firstRealFileDescriptor(): fd { 199 | return this.firstReal; 200 | } 201 | 202 | public next(): fd { 203 | if (this.mode === 'init') { 204 | throw new WasiError(Errno.inval); 205 | } 206 | return this.counter++; 207 | } 208 | 209 | public switchToRunning(start: fd): void { 210 | if (this.mode === 'running') { 211 | throw new WasiError(Errno.inval); 212 | } 213 | this.mode = 'running'; 214 | this.counter = start; 215 | this.firstReal = start; 216 | } 217 | 218 | public add(descriptor: FileDescriptor): void { 219 | this.descriptors.set(descriptor.fd, descriptor); 220 | } 221 | 222 | public get(fd: fd): FileDescriptor { 223 | const descriptor = this.descriptors.get(fd); 224 | if (!descriptor) { 225 | throw new WasiError(Errno.badf); 226 | } 227 | return descriptor; 228 | } 229 | 230 | public has(fd: fd): boolean { 231 | return this.descriptors.has(fd); 232 | } 233 | 234 | public delete(descriptor: FileDescriptor): boolean { 235 | return this.descriptors.delete(descriptor.fd); 236 | } 237 | 238 | public setRoot(driver: DeviceDriver, descriptor: FileDescriptor): void { 239 | this.rootDescriptors.set(driver.id, descriptor); 240 | } 241 | 242 | public getRoot(driver: DeviceDriver): FileDescriptor | undefined { 243 | return this.rootDescriptors.get(driver.id); 244 | } 245 | 246 | public entries(): IterableIterator<[number, FileDescriptor]> { 247 | return this.descriptors.entries(); 248 | } 249 | 250 | public keys(): IterableIterator { 251 | return this.descriptors.keys(); 252 | } 253 | 254 | public values(): IterableIterator { 255 | return this.descriptors.values(); 256 | } 257 | 258 | public [Symbol.iterator](): IterableIterator<[number, FileDescriptor]> { 259 | return this.entries(); 260 | } 261 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/fileSystem.d.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import { Filetype as ApiFiletype, RootFileSystem } from './api'; 3 | import { Filetype as WasiFiletype, fd, fdflags, filetype, inode, rights } from './wasi'; 4 | import { RootFileSystemDeviceDriver } from './rootFileSystemDriver'; 5 | import { RootFileSystemInfo } from './kernel'; 6 | import { DeviceDriver, FileSystemDeviceDriver } from './deviceDriver'; 7 | import { BaseFileDescriptor, FileDescriptor, FileDescriptors } from './fileDescriptor'; 8 | export declare namespace Filetypes { 9 | function from(filetype: filetype): ApiFiletype; 10 | function to(filetype: ApiFiletype): filetype; 11 | } 12 | export interface BaseNode { 13 | readonly filetype: filetype; 14 | /** 15 | * The inode id. 16 | */ 17 | readonly inode: inode; 18 | /** 19 | * The name of the file. 20 | */ 21 | readonly name: string; 22 | /** 23 | * How often the node is referenced via a file descriptor 24 | */ 25 | refs: number; 26 | } 27 | export interface FileNode extends BaseNode { 28 | readonly filetype: typeof WasiFiletype.regular_file; 29 | /** 30 | * The parent node 31 | */ 32 | readonly parent: DirectoryNode; 33 | } 34 | export interface CharacterDeviceNode extends BaseNode { 35 | readonly filetype: typeof WasiFiletype.character_device; 36 | /** 37 | * The parent node 38 | */ 39 | readonly parent: DirectoryNode; 40 | } 41 | export interface DirectoryNode extends BaseNode { 42 | readonly filetype: typeof WasiFiletype.directory; 43 | /** 44 | * The parent node 45 | */ 46 | readonly parent: DirectoryNode | undefined; 47 | /** 48 | * The directory entries. 49 | */ 50 | readonly entries: Map; 51 | } 52 | type Node = FileNode | DirectoryNode | CharacterDeviceNode; 53 | export declare abstract class BaseFileSystem { 54 | private inodeCounter; 55 | private readonly root; 56 | constructor(root: D); 57 | protected nextInode(): inode; 58 | getRoot(): D; 59 | findNode(path: string): D | F | C | undefined; 60 | findNode(parent: D, path: string): D | F | C | undefined; 61 | private getSegmentsFromPath; 62 | } 63 | declare abstract class NodeDescriptor extends BaseFileDescriptor { 64 | readonly node: N; 65 | constructor(deviceId: bigint, fd: fd, filetype: filetype, rights_base: rights, rights_inheriting: rights, fdflags: fdflags, inode: bigint, node: N); 66 | dispose(): Promise; 67 | } 68 | export declare class FileNodeDescriptor extends NodeDescriptor { 69 | private _cursor; 70 | constructor(deviceId: bigint, fd: fd, rights_base: rights, fdflags: fdflags, inode: bigint, node: F); 71 | with(change: { 72 | fd: fd; 73 | }): FileDescriptor; 74 | get cursor(): bigint; 75 | set cursor(value: bigint); 76 | } 77 | export declare class CharacterDeviceNodeDescriptor extends NodeDescriptor { 78 | constructor(deviceId: bigint, fd: fd, rights_base: rights, fdflags: fdflags, inode: bigint, node: C); 79 | with(change: { 80 | fd: fd; 81 | }): FileDescriptor; 82 | } 83 | export declare class DirectoryNodeDescriptor extends NodeDescriptor { 84 | constructor(deviceId: bigint, fd: fd, rights_base: rights, rights_inheriting: rights, fdflags: fdflags, inode: bigint, node: D); 85 | with(change: { 86 | fd: fd; 87 | }): FileDescriptor; 88 | childDirectoryRights(requested_rights: rights, fileOnlyBaseRights: rights): rights; 89 | childFileRights(requested_rights: rights, directoryOnlyBaseRights: rights): rights; 90 | } 91 | export declare class WasmRootFileSystemImpl implements RootFileSystem { 92 | private readonly deviceDrivers; 93 | private readonly preOpens; 94 | private readonly fileDescriptors; 95 | private readonly service; 96 | private virtualFileSystem; 97 | private singleFileSystem; 98 | constructor(info: RootFileSystemInfo, fileDescriptors: FileDescriptors); 99 | initialize(): Promise; 100 | getDeviceDrivers(): DeviceDriver[]; 101 | getPreOpenDirectories(): Map; 102 | getVirtualRootFileSystem(): RootFileSystemDeviceDriver | undefined; 103 | toVSCode(path: string): Promise; 104 | toWasm(uri: Uri): Promise; 105 | stat(path: string): Promise<{ 106 | filetype: ApiFiletype; 107 | }>; 108 | private getFileDescriptor; 109 | private getDeviceDriver; 110 | private getMountPoint; 111 | } 112 | export {}; 113 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/host.d.ts: -------------------------------------------------------------------------------- 1 | import { u32 } from './baseTypes'; 2 | import { errno } from './wasi'; 3 | import { WasiFunction, MemoryTransfer } from './wasiMeta'; 4 | import { WorkerMessage } from './connection'; 5 | import { WASI } from './wasi'; 6 | export declare abstract class HostConnection { 7 | private readonly timeout; 8 | constructor(timeout?: number); 9 | abstract postMessage(message: WorkerMessage): any; 10 | abstract destroy(): void; 11 | call(func: WasiFunction, args: (number | bigint)[], wasmMemory: ArrayBuffer, transfers?: MemoryTransfer): errno; 12 | private doCall; 13 | private createCallArrays; 14 | } 15 | declare namespace WebAssembly { 16 | interface Global { 17 | value: any; 18 | valueOf(): any; 19 | } 20 | interface Table { 21 | readonly length: number; 22 | get(index: number): any; 23 | grow(delta: number, value?: any): number; 24 | set(index: number, value?: any): void; 25 | } 26 | interface Memory { 27 | readonly buffer: ArrayBuffer; 28 | grow(delta: number): number; 29 | } 30 | type ExportValue = Function | Global | Memory | Table; 31 | interface Instance { 32 | readonly exports: Record; 33 | } 34 | var Instance: { 35 | prototype: Instance; 36 | new (): Instance; 37 | }; 38 | } 39 | export interface WasiHost extends WASI { 40 | initialize: (instOrMemory: WebAssembly.Instance | WebAssembly.Memory) => void; 41 | memory: () => ArrayBuffer; 42 | thread_exit: (tid: u32) => void; 43 | } 44 | export declare namespace WasiHost { 45 | function create(connection: HostConnection): WasiHost; 46 | } 47 | export interface Tracer { 48 | tracer: WasiHost; 49 | printSummary(): void; 50 | } 51 | export declare namespace TraceWasiHost { 52 | function create(connection: HostConnection, host: WasiHost): Tracer; 53 | } 54 | export {}; 55 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/kernel.d.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import type { ExtensionLocationDescriptor, MemoryFileSystemDescriptor, VSCodeFileSystemDescriptor, MountPointDescriptor } from './api'; 3 | import type { DeviceDriver, DeviceId, FileSystemDeviceDriver } from './deviceDriver'; 4 | import type { FileDescriptors } from './fileDescriptor'; 5 | import * as vrfs from './rootFileSystemDriver'; 6 | export interface DeviceDrivers { 7 | add(driver: DeviceDriver): void; 8 | has(id: DeviceId): boolean; 9 | hasByUri(uri: Uri): boolean; 10 | get(id: DeviceId): DeviceDriver; 11 | getByUri(uri: Uri): DeviceDriver; 12 | remove(id: DeviceId): void; 13 | removeByUri(uri: Uri): void; 14 | size: number; 15 | values(): IterableIterator; 16 | entries(): IterableIterator<[bigint, DeviceDriver]>; 17 | [Symbol.iterator](): IterableIterator<[bigint, DeviceDriver]>; 18 | } 19 | declare class DeviceDriversImpl { 20 | private readonly devices; 21 | private readonly devicesByUri; 22 | constructor(); 23 | add(driver: DeviceDriver): void; 24 | has(id: DeviceId): boolean; 25 | hasByUri(uri: Uri): boolean; 26 | get(id: DeviceId): DeviceDriver; 27 | getByUri(uri: Uri): DeviceDriver; 28 | remove(id: DeviceId): void; 29 | removeByUri(uri: Uri): void; 30 | get size(): number; 31 | values(): IterableIterator; 32 | entries(): IterableIterator<[bigint, DeviceDriver]>; 33 | [Symbol.iterator](): IterableIterator<[bigint, DeviceDriver]>; 34 | } 35 | export declare enum ManageKind { 36 | no = 1, 37 | yes = 2, 38 | default = 3 39 | } 40 | export interface SingleFileSystemInfo { 41 | kind: 'single'; 42 | fileSystem: FileSystemDeviceDriver; 43 | deviceDrivers: DeviceDrivers; 44 | preOpens: Map; 45 | } 46 | export interface VirtualFileSystemInfo { 47 | kind: 'virtual'; 48 | fileSystem: vrfs.RootFileSystemDeviceDriver; 49 | deviceDrivers: DeviceDrivers; 50 | preOpens: Map; 51 | } 52 | export type RootFileSystemInfo = SingleFileSystemInfo | VirtualFileSystemInfo; 53 | declare namespace WasiKernel { 54 | function nextDeviceId(): bigint; 55 | function getOrCreateFileSystemByDescriptor(deviceDrivers: DeviceDrivers, descriptor: VSCodeFileSystemDescriptor | ExtensionLocationDescriptor | MemoryFileSystemDescriptor): Promise; 56 | function createRootFileSystem(fileDescriptors: FileDescriptors, descriptors: MountPointDescriptor[]): Promise; 57 | const deviceDrivers: DeviceDriversImpl; 58 | const console: import("./deviceDriver").CharacterDeviceDriver; 59 | function createLocalDeviceDrivers(): DeviceDrivers; 60 | } 61 | export default WasiKernel; 62 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/linkedMap.d.ts: -------------------------------------------------------------------------------- 1 | export declare namespace Touch { 2 | const None: 0; 3 | const First: 1; 4 | const AsOld: 1; 5 | const Last: 2; 6 | const AsNew: 2; 7 | } 8 | export type Touch = 0 | 1 | 2; 9 | export declare class LinkedMap implements Map { 10 | readonly [Symbol.toStringTag] = "LinkedMap"; 11 | private _map; 12 | private _head; 13 | private _tail; 14 | private _size; 15 | private _state; 16 | constructor(); 17 | clear(): void; 18 | isEmpty(): boolean; 19 | get size(): number; 20 | get first(): V | undefined; 21 | get last(): V | undefined; 22 | has(key: K): boolean; 23 | get(key: K, touch?: Touch): V | undefined; 24 | set(key: K, value: V, touch?: Touch): this; 25 | delete(key: K): boolean; 26 | remove(key: K): V | undefined; 27 | shift(): V | undefined; 28 | forEach(callbackfn: (value: V, key: K, map: LinkedMap) => void, thisArg?: any): void; 29 | keys(): IterableIterator; 30 | values(): IterableIterator; 31 | entries(): IterableIterator<[K, V]>; 32 | [Symbol.iterator](): IterableIterator<[K, V]>; 33 | protected trimOld(newSize: number): void; 34 | private addItemFirst; 35 | private addItemLast; 36 | private removeItem; 37 | private touch; 38 | toJSON(): [K, V][]; 39 | fromJSON(data: [K, V][]): void; 40 | } 41 | export declare class LRUCache extends LinkedMap { 42 | private _limit; 43 | private _ratio; 44 | constructor(limit: number, ratio?: number); 45 | get limit(): number; 46 | set limit(limit: number); 47 | get ratio(): number; 48 | set ratio(ratio: number); 49 | get(key: K, touch?: Touch): V | undefined; 50 | peek(key: K): V | undefined; 51 | set(key: K, value: V): this; 52 | private checkTrim; 53 | } 54 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/memoryFileSystemDriver.d.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import { MemoryFileSystem as ApiMemoryFileSystem, Readable, Writable } from './api'; 3 | import { DeviceId, FileSystemDeviceDriver } from './deviceDriver'; 4 | import { inode } from './wasi'; 5 | import { size } from './baseTypes'; 6 | import * as fs from './fileSystem'; 7 | import { ReadableStream, WritableStream } from './streams'; 8 | interface BaseNode { 9 | readonly ctime: bigint; 10 | readonly mtime: bigint; 11 | readonly atime: bigint; 12 | } 13 | interface FileNode extends fs.FileNode, BaseNode { 14 | readonly parent: DirectoryNode; 15 | content: Uint8Array | { 16 | size: bigint; 17 | reader: () => Promise; 18 | }; 19 | } 20 | declare namespace FileNode { 21 | function create(parent: DirectoryNode, inode: inode, name: string, time: bigint, content: Uint8Array | { 22 | size: bigint; 23 | reader: () => Promise; 24 | }): FileNode; 25 | function size(node: FileNode): bigint; 26 | } 27 | interface DirectoryNode extends BaseNode, fs.DirectoryNode { 28 | readonly parent: DirectoryNode | undefined; 29 | readonly entries: Map; 30 | } 31 | declare namespace DirectoryNode { 32 | function create(parent: DirectoryNode | undefined, id: inode, name: string, time: bigint): DirectoryNode; 33 | function size(node: DirectoryNode): bigint; 34 | } 35 | interface CharacterDeviceNode extends fs.CharacterDeviceNode, BaseNode { 36 | readonly readable: ReadableStream | undefined; 37 | readonly writable: WritableStream | undefined; 38 | } 39 | declare namespace CharacterDeviceNode { 40 | function create(parent: DirectoryNode, inode: inode, name: string, time: bigint, readable: ReadableStream | undefined, writable: WritableStream | undefined): CharacterDeviceNode; 41 | } 42 | type Node = FileNode | DirectoryNode | CharacterDeviceNode; 43 | export declare class MemoryFileSystem extends fs.BaseFileSystem implements ApiMemoryFileSystem { 44 | readonly uri: Uri; 45 | constructor(); 46 | createDirectory(path: string): void; 47 | createFile(path: string, content: Uint8Array | { 48 | size: bigint; 49 | reader: () => Promise; 50 | }): void; 51 | createReadable(path: string): Readable; 52 | createWritable(path: string, encoding?: 'utf-8'): Writable; 53 | private getDirectoryNode; 54 | readFile(node: FileNode, offset: bigint, buffers: Uint8Array[]): Promise; 55 | readCharacterDevice(node: CharacterDeviceNode & { 56 | writable: WritableStream; 57 | }, buffers: Uint8Array[]): Promise; 58 | writeFile(node: FileNode, offset: bigint, buffers: Uint8Array[]): Promise; 59 | writeCharacterDevice(node: CharacterDeviceNode & { 60 | readable: ReadableStream; 61 | }, buffers: Uint8Array[]): Promise; 62 | getContent(node: FileNode): Promise; 63 | private read; 64 | private write; 65 | } 66 | export declare function create(deviceId: DeviceId, memfs: MemoryFileSystem): FileSystemDeviceDriver; 67 | export {}; 68 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/pipeDriver.d.ts: -------------------------------------------------------------------------------- 1 | import { size } from './baseTypes'; 2 | import { CharacterDeviceDriver, DeviceId } from './deviceDriver'; 3 | interface Stdin { 4 | read(maxBytesToRead: size): Promise; 5 | } 6 | interface Stdout { 7 | write(chunk: Uint8Array): Promise; 8 | } 9 | export declare function create(deviceId: DeviceId, stdin: Stdin | undefined, stdout: Stdout | undefined, stderr: Stdout | undefined): CharacterDeviceDriver; 10 | export {}; 11 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/pipeDriver.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { size } from './baseTypes'; 7 | import { Errno, fd, fdflags, fdstat, filestat, Filetype, Rights, rights, WasiError } from './wasi'; 8 | import { CharacterDeviceDriver, DeviceDriverKind, DeviceId, NoSysDeviceDriver } from './deviceDriver'; 9 | import { BaseFileDescriptor, FileDescriptor } from './fileDescriptor'; 10 | import { Uri } from 'vscode'; 11 | 12 | const PipeBaseRights: rights = Rights.fd_read | Rights.fd_fdstat_set_flags | Rights.fd_write | 13 | Rights.fd_filestat_get | Rights.poll_fd_readwrite; 14 | 15 | const PipeInheritingRights = 0n; 16 | 17 | class PipeFileDescriptor extends BaseFileDescriptor { 18 | constructor(deviceId: bigint, fd: fd, rights_base: rights, rights_inheriting: rights, fdflags: fdflags, inode: bigint) { 19 | super(deviceId, fd, Filetype.character_device, rights_base, rights_inheriting, fdflags, inode); 20 | } 21 | 22 | public with(change: { fd: number }): FileDescriptor { 23 | return new PipeFileDescriptor(this.deviceId, change.fd, this.rights_base, this.rights_inheriting, this.fdflags, this.inode); 24 | } 25 | } 26 | 27 | interface Stdin { 28 | read(maxBytesToRead: size): Promise; 29 | } 30 | 31 | interface Stdout { 32 | write(chunk: Uint8Array): Promise; 33 | } 34 | 35 | export function create(deviceId: DeviceId, stdin: Stdin | undefined, stdout: Stdout | undefined, stderr: Stdout | undefined): CharacterDeviceDriver { 36 | 37 | let inodeCounter: bigint = 0n; 38 | 39 | function createPipeFileDescriptor(fd: 0 | 1 | 2): PipeFileDescriptor { 40 | return new PipeFileDescriptor(deviceId, fd, PipeBaseRights, PipeInheritingRights, 0, inodeCounter++); 41 | } 42 | 43 | const deviceDriver: Pick = { 44 | kind: DeviceDriverKind.character, 45 | id: deviceId, 46 | uri: Uri.from({ scheme: 'wasi-pipe', authority: deviceId.toString() }), 47 | createStdioFileDescriptor(fd: 0 | 1 | 2): FileDescriptor { 48 | if (fd === 0 && stdin !== undefined) { 49 | return createPipeFileDescriptor(fd); 50 | } else if (fd === 1 && stdout !== undefined) { 51 | return createPipeFileDescriptor(fd); 52 | } else if (fd === 2 && stderr !== undefined) { 53 | return createPipeFileDescriptor(fd); 54 | } 55 | throw new WasiError(Errno.badf); 56 | }, 57 | fd_fdstat_get(fileDescriptor: FileDescriptor, result: fdstat): Promise { 58 | result.fs_filetype = fileDescriptor.fileType; 59 | result.fs_flags = fileDescriptor.fdflags; 60 | result.fs_rights_base = fileDescriptor.rights_base; 61 | result.fs_rights_inheriting = fileDescriptor.rights_inheriting; 62 | return Promise.resolve(); 63 | }, 64 | fd_filestat_get(fileDescriptor: FileDescriptor, result: filestat): Promise { 65 | result.dev = fileDescriptor.deviceId; 66 | result.ino = fileDescriptor.inode; 67 | result.filetype = Filetype.character_device; 68 | result.nlink = 0n; 69 | result.size = 101n; 70 | const now = BigInt(Date.now()); 71 | result.atim = now; 72 | result.ctim = now; 73 | result.mtim = now; 74 | return Promise.resolve(); 75 | }, 76 | async fd_read(_fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise { 77 | if (buffers.length === 0) { 78 | return 0; 79 | } 80 | if (stdin === undefined) { 81 | throw new WasiError(Errno.badf); 82 | } 83 | 84 | const maxBytesToRead = buffers.reduce((prev, current) => prev + current.length, 0); 85 | const result = await stdin.read(maxBytesToRead); 86 | let offset = 0; 87 | let totalBytesRead = 0; 88 | for (const buffer of buffers) { 89 | const toCopy = Math.min(buffer.length, result.length - offset); 90 | buffer.set(result.subarray(offset, offset + toCopy)); 91 | offset += toCopy; 92 | totalBytesRead += toCopy; 93 | if (toCopy < buffer.length) { 94 | break; 95 | } 96 | } 97 | return totalBytesRead; 98 | }, 99 | async fd_write(fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise { 100 | let buffer: Uint8Array; 101 | if (buffers.length === 1) { 102 | buffer = buffers[0]; 103 | } else { 104 | const byteLength: number = buffers.reduce((prev, current) => prev + current.length, 0); 105 | buffer = new Uint8Array(byteLength); 106 | let offset = 0; 107 | for (const item of buffers) { 108 | buffer.set(item, offset); 109 | offset = item.byteLength; 110 | } 111 | } 112 | if (fileDescriptor.fd === 1 && stdout !== undefined) { 113 | await stdout.write(buffer); 114 | return Promise.resolve(buffer.byteLength); 115 | } else if (fileDescriptor.fd === 2 && stderr !== undefined) { 116 | await stderr.write(buffer); 117 | return Promise.resolve(buffer.byteLength); 118 | } 119 | throw new WasiError(Errno.badf); 120 | } 121 | }; 122 | 123 | return Object.assign({}, NoSysDeviceDriver, deviceDriver); 124 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/process.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { LogOutputChannel } from 'vscode'; 3 | import type { ProcessOptions, Readable, Writable } from './api'; 4 | import type { ptr, u32 } from './baseTypes'; 5 | import { WasiService } from './service'; 6 | import { exitcode } from './wasi'; 7 | export declare abstract class WasiProcess { 8 | private _state; 9 | private readonly programName; 10 | protected readonly options: Omit & { 11 | trace: LogOutputChannel | undefined; 12 | }; 13 | private localDeviceDrivers; 14 | private resolveCallback; 15 | private threadIdCounter; 16 | private readonly fileDescriptors; 17 | private environmentService; 18 | private processService; 19 | private readonly preOpenDirectories; 20 | private virtualRootFileSystem; 21 | private _stdin; 22 | private _stdout; 23 | private _stderr; 24 | constructor(programName: string, options?: ProcessOptions); 25 | get stdin(): Writable | undefined; 26 | get stdout(): Readable | undefined; 27 | get stderr(): Readable | undefined; 28 | protected get state(): typeof this._state; 29 | initialize(): Promise; 30 | run(): Promise; 31 | protected abstract procExit(): Promise; 32 | abstract terminate(): Promise; 33 | protected destroyStreams(): Promise; 34 | protected cleanupFileDescriptors(): Promise; 35 | protected resolveRunPromise(exitCode: exitcode): void; 36 | protected abstract startMain(wasiService: WasiService): Promise; 37 | protected abstract startThread(wasiService: WasiService, tid: u32, start_arg: ptr): Promise; 38 | protected abstract threadEnded(tid: u32): Promise; 39 | private mapWorkspaceFolder; 40 | private mapDirEntry; 41 | private handleConsole; 42 | private handleTerminal; 43 | private getTerminalDevice; 44 | private handleFiles; 45 | private handleFileDescriptor; 46 | private handlePipes; 47 | } 48 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/promises.d.ts: -------------------------------------------------------------------------------- 1 | export interface CapturedPromise { 2 | promise: Promise; 3 | resolve: (value: T | PromiseLike) => void; 4 | reject: (reason?: any) => void; 5 | } 6 | export declare namespace CapturedPromise { 7 | function create(): CapturedPromise; 8 | } 9 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/promises.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | export interface CapturedPromise { 7 | promise: Promise; 8 | resolve: (value: T | PromiseLike) => void; 9 | reject: (reason?: any) => void; 10 | } 11 | 12 | export namespace CapturedPromise { 13 | export function create(): CapturedPromise { 14 | let _resolve!: (value: T | PromiseLike) => void; 15 | let _reject!: (reason?: any) => void; 16 | const promise: Promise = new Promise((resolve, reject) => { 17 | _resolve = resolve; 18 | _reject = reject; 19 | }); 20 | return { 21 | promise, resolve: _resolve, reject: _reject 22 | }; 23 | } 24 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/ral.d.ts: -------------------------------------------------------------------------------- 1 | import type { Disposable } from 'vscode'; 2 | interface _TextEncoder { 3 | encode(input?: string): Uint8Array; 4 | } 5 | interface _TextDecoder { 6 | decode(input?: Uint8Array): string; 7 | } 8 | interface RAL { 9 | readonly TextEncoder: { 10 | create(encoding?: string): _TextEncoder; 11 | }; 12 | readonly TextDecoder: { 13 | create(encoding?: string): _TextDecoder; 14 | }; 15 | readonly console: { 16 | info(message?: any, ...optionalParams: any[]): void; 17 | log(message?: any, ...optionalParams: any[]): void; 18 | warn(message?: any, ...optionalParams: any[]): void; 19 | error(message?: any, ...optionalParams: any[]): void; 20 | }; 21 | readonly timer: { 22 | setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable; 23 | setImmediate(callback: (...args: any[]) => void, ...args: any[]): Disposable; 24 | setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable; 25 | }; 26 | readonly clock: { 27 | /** 28 | * Real time (since epoch) in nanoseconds 29 | */ 30 | realtime(): bigint; 31 | /** 32 | * Monotonic time in nanoseconds. 33 | */ 34 | monotonic(): bigint; 35 | }; 36 | readonly crypto: { 37 | randomGet(size: number): Uint8Array; 38 | }; 39 | readonly path: { 40 | readonly sep: string; 41 | basename(path: string): string; 42 | dirname(path: string): string; 43 | join(...paths: string[]): string; 44 | normalize(path: string): string; 45 | isAbsolute(path: string): boolean; 46 | }; 47 | } 48 | declare function RAL(): RAL; 49 | declare namespace RAL { 50 | type TextEncoder = _TextEncoder; 51 | type TextDecoder = _TextDecoder; 52 | function install(ral: RAL): void; 53 | function isInstalled(): boolean; 54 | } 55 | export default RAL; 56 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/ral.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | 6 | import type { Disposable } from 'vscode'; 7 | 8 | interface _TextEncoder { 9 | encode(input?: string): Uint8Array; 10 | } 11 | 12 | interface _TextDecoder { 13 | decode(input?: Uint8Array): string; 14 | } 15 | 16 | interface RAL { 17 | 18 | readonly TextEncoder: { 19 | create(encoding?: string): _TextEncoder; 20 | }; 21 | 22 | readonly TextDecoder: { 23 | create(encoding?: string): _TextDecoder; 24 | }; 25 | 26 | readonly console: { 27 | info(message?: any, ...optionalParams: any[]): void; 28 | log(message?: any, ...optionalParams: any[]): void; 29 | warn(message?: any, ...optionalParams: any[]): void; 30 | error(message?: any, ...optionalParams: any[]): void; 31 | }; 32 | 33 | readonly timer: { 34 | setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable; 35 | setImmediate(callback: (...args: any[]) => void, ...args: any[]): Disposable; 36 | setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable; 37 | }; 38 | 39 | readonly clock: { 40 | /** 41 | * Real time (since epoch) in nanoseconds 42 | */ 43 | realtime(): bigint; 44 | 45 | /** 46 | * Monotonic time in nanoseconds. 47 | */ 48 | monotonic(): bigint; 49 | }; 50 | 51 | readonly crypto: { 52 | randomGet(size: number): Uint8Array; 53 | }; 54 | 55 | readonly path: { 56 | readonly sep: string; 57 | basename(path: string): string; 58 | dirname(path: string): string; 59 | join(...paths: string[]): string; 60 | normalize(path: string): string; 61 | isAbsolute(path: string): boolean; 62 | }; 63 | } 64 | 65 | let _ral: RAL | undefined; 66 | 67 | function RAL(): RAL { 68 | if (_ral === undefined) { 69 | throw new Error(`No runtime abstraction layer installed`); 70 | } 71 | return _ral; 72 | } 73 | 74 | namespace RAL { 75 | export type TextEncoder = _TextEncoder; 76 | export type TextDecoder = _TextDecoder; 77 | export function install(ral: RAL): void { 78 | if (ral === undefined) { 79 | throw new Error(`No runtime abstraction layer provided`); 80 | } 81 | _ral = ral; 82 | } 83 | export function isInstalled(): boolean { 84 | return _ral !== undefined; 85 | } 86 | } 87 | 88 | export default RAL; -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/rootFileSystemDriver.d.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import { DeviceDriver, DeviceId, FileSystemDeviceDriver } from './deviceDriver'; 3 | import { FileDescriptor } from './fileDescriptor'; 4 | export interface RootFileSystemDeviceDriver extends FileSystemDeviceDriver { 5 | makeVirtualPath(deviceDriver: FileSystemDeviceDriver, filepath: string): string | undefined; 6 | getDeviceDriver(path: string): [FileSystemDeviceDriver | undefined, string]; 7 | getMountPoint(uri: Uri): [string | undefined, Uri]; 8 | } 9 | export declare function create(deviceId: DeviceId, rootFileDescriptors: { 10 | getRoot(device: DeviceDriver): FileDescriptor | undefined; 11 | }, mountPoints: Map): RootFileSystemDeviceDriver; 12 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/service.d.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { args_get, args_sizes_get, clockid, clock_res_get, clock_time_get, environ_get, environ_sizes_get, errno, fd_advise, fd_allocate, fd_close, fd_datasync, fd_fdstat_get, fd_fdstat_set_flags, fd_filestat_get, fd_filestat_set_size, fd_filestat_set_times, fd_pread, fd_prestat_dir_name, fd_prestat_get, fd_pwrite, fd_read, fd_readdir, fd_renumber, fd_seek, fd_sync, fd_tell, fd_write, path_create_directory, path_filestat_get, path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory, path_rename, path_symlink, path_unlink_file, poll_oneoff, proc_exit, random_get, sched_yield, sock_accept, thread_spawn, timestamp, thread_exit, tid, sock_shutdown, sock_send, sock_recv } from './wasi'; 3 | import { WorkerMessage } from './connection'; 4 | import { FileDescriptors } from './fileDescriptor'; 5 | import { DeviceDriver, FileSystemDeviceDriver } from './deviceDriver'; 6 | import { ProcessOptions } from './api'; 7 | import { DeviceDrivers } from './kernel'; 8 | import { RootFileSystemDeviceDriver } from './rootFileSystemDriver'; 9 | export declare abstract class ServiceConnection { 10 | private readonly wasiService; 11 | private readonly logChannel; 12 | private readonly _workerReady; 13 | private readonly _workerDone; 14 | constructor(wasiService: WasiService, logChannel?: vscode.LogOutputChannel | undefined); 15 | workerReady(): Promise; 16 | workerDone(): Promise; 17 | protected handleMessage(message: WorkerMessage): Promise; 18 | private handleWasiCallMessage; 19 | private getParams; 20 | } 21 | export interface EnvironmentWasiService { 22 | args_sizes_get: args_sizes_get.ServiceSignature; 23 | args_get: args_get.ServiceSignature; 24 | environ_sizes_get: environ_sizes_get.ServiceSignature; 25 | environ_get: environ_get.ServiceSignature; 26 | fd_prestat_get: fd_prestat_get.ServiceSignature; 27 | fd_prestat_dir_name: fd_prestat_dir_name.ServiceSignature; 28 | [name: string]: (memory: ArrayBuffer, ...args: (number & bigint)[]) => Promise; 29 | } 30 | export interface ClockWasiService { 31 | clock_res_get: clock_res_get.ServiceSignature; 32 | clock_time_get: clock_time_get.ServiceSignature; 33 | [name: string]: (memory: ArrayBuffer, ...args: (number & bigint)[]) => Promise; 34 | } 35 | interface DeviceWasiService { 36 | fd_advise: fd_advise.ServiceSignature; 37 | fd_allocate: fd_allocate.ServiceSignature; 38 | fd_close: fd_close.ServiceSignature; 39 | fd_datasync: fd_datasync.ServiceSignature; 40 | fd_fdstat_get: fd_fdstat_get.ServiceSignature; 41 | fd_fdstat_set_flags: fd_fdstat_set_flags.ServiceSignature; 42 | fd_filestat_get: fd_filestat_get.ServiceSignature; 43 | fd_filestat_set_size: fd_filestat_set_size.ServiceSignature; 44 | fd_filestat_set_times: fd_filestat_set_times.ServiceSignature; 45 | fd_pread: fd_pread.ServiceSignature; 46 | fd_pwrite: fd_pwrite.ServiceSignature; 47 | fd_read: fd_read.ServiceSignature; 48 | fd_readdir: fd_readdir.ServiceSignature; 49 | fd_seek: fd_seek.ServiceSignature; 50 | fd_renumber: fd_renumber.ServiceSignature; 51 | fd_sync: fd_sync.ServiceSignature; 52 | fd_tell: fd_tell.ServiceSignature; 53 | fd_write: fd_write.ServiceSignature; 54 | path_create_directory: path_create_directory.ServiceSignature; 55 | path_filestat_get: path_filestat_get.ServiceSignature; 56 | path_filestat_set_times: path_filestat_set_times.ServiceSignature; 57 | path_link: path_link.ServiceSignature; 58 | path_open: path_open.ServiceSignature; 59 | path_readlink: path_readlink.ServiceSignature; 60 | path_remove_directory: path_remove_directory.ServiceSignature; 61 | path_rename: path_rename.ServiceSignature; 62 | path_symlink: path_symlink.ServiceSignature; 63 | path_unlink_file: path_unlink_file.ServiceSignature; 64 | poll_oneoff: poll_oneoff.ServiceSignature; 65 | sched_yield: sched_yield.ServiceSignature; 66 | random_get: random_get.ServiceSignature; 67 | sock_accept: sock_accept.ServiceSignature; 68 | sock_recv: sock_recv.ServiceSignature; 69 | sock_send: sock_send.ServiceSignature; 70 | sock_shutdown: sock_shutdown.ServiceSignature; 71 | [name: string]: (memory: ArrayBuffer, ...args: (number & bigint)[]) => Promise; 72 | } 73 | export interface ProcessWasiService { 74 | proc_exit: proc_exit.ServiceSignature; 75 | thread_exit: thread_exit.ServiceSignature; 76 | 'thread-spawn': thread_spawn.ServiceSignature; 77 | [name: string]: (memory: ArrayBuffer, ...args: (number & bigint)[]) => Promise; 78 | } 79 | export interface WasiService extends EnvironmentWasiService, ClockWasiService, DeviceWasiService, ProcessWasiService { 80 | } 81 | export interface FileSystemService extends Pick, DeviceWasiService { 82 | } 83 | export interface EnvironmentOptions extends Omit { 84 | args?: string[]; 85 | } 86 | export declare namespace EnvironmentWasiService { 87 | function create(fileDescriptors: FileDescriptors, programName: string, preStats: IterableIterator<[string, DeviceDriver]>, options: EnvironmentOptions): EnvironmentWasiService; 88 | } 89 | export interface Clock { 90 | now(id: clockid, _precision: timestamp): bigint; 91 | } 92 | export declare namespace Clock { 93 | function create(): Clock; 94 | } 95 | export declare namespace ClockWasiService { 96 | function create(clock: Clock): ClockWasiService; 97 | } 98 | export interface DeviceOptions extends Pick { 99 | } 100 | export declare namespace DeviceWasiService { 101 | function create(deviceDrivers: DeviceDrivers, fileDescriptors: FileDescriptors, clock: Clock, virtualRootFileSystem: RootFileSystemDeviceDriver | undefined, options: DeviceOptions): DeviceWasiService; 102 | } 103 | export interface FileSystemService extends Pick, DeviceWasiService { 104 | } 105 | export declare namespace FileSystemService { 106 | function create(deviceDrivers: DeviceDrivers, fileDescriptors: FileDescriptors, virtualRootFileSystem: RootFileSystemDeviceDriver | undefined, preOpens: Map, options: DeviceOptions): FileSystemService; 107 | } 108 | export declare const NoSysWasiService: WasiService; 109 | export {}; 110 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/streams.d.ts: -------------------------------------------------------------------------------- 1 | import { Event } from 'vscode'; 2 | import type { Readable, Writable } from './api'; 3 | export declare class DestroyError extends Error { 4 | constructor(); 5 | } 6 | export declare abstract class Stream { 7 | private static BufferSize; 8 | protected chunks: Uint8Array[]; 9 | protected fillLevel: number; 10 | private awaitForFillLevel; 11 | private awaitForData; 12 | constructor(); 13 | write(chunk: Uint8Array): Promise; 14 | read(): Promise; 15 | read(mode: 'max', size: number): Promise; 16 | end(): void; 17 | destroy(): void; 18 | private awaitFillLevel; 19 | private awaitData; 20 | protected signalSpace(): void; 21 | protected signalData(): void; 22 | } 23 | export declare class WritableStream extends Stream implements Writable { 24 | private readonly encoding; 25 | private readonly encoder; 26 | constructor(encoding?: 'utf-8'); 27 | write(chunk: Uint8Array | string): Promise; 28 | end(): void; 29 | } 30 | export declare class ReadableStream extends Stream implements Readable { 31 | private mode; 32 | private readonly _onData; 33 | private readonly _onDataEvent; 34 | private timer; 35 | constructor(); 36 | get onData(): Event; 37 | pause(flush?: boolean): void; 38 | resume(): void; 39 | read(mode?: 'max', size?: number): Promise; 40 | end(): void; 41 | protected signalData(): void; 42 | private emitAll; 43 | private triggerData; 44 | } 45 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/streams.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import { Disposable, Event, EventEmitter } from 'vscode'; 6 | 7 | import RAL from './ral'; 8 | import type { Readable, Writable } from './api'; 9 | import { CapturedPromise } from './promises'; 10 | 11 | export class DestroyError extends Error { 12 | constructor() { 13 | super('Pipe got destroyed'); 14 | } 15 | } 16 | 17 | export abstract class Stream { 18 | 19 | private static BufferSize = 16384; 20 | 21 | protected chunks: Uint8Array[]; 22 | protected fillLevel: number; 23 | 24 | private awaitForFillLevel: { fillLevel: number; promise: CapturedPromise }[]; 25 | private awaitForData: CapturedPromise[]; 26 | 27 | constructor() { 28 | this.chunks = []; 29 | this.fillLevel = 0; 30 | this.awaitForFillLevel = []; 31 | this.awaitForData = []; 32 | } 33 | 34 | public async write(chunk: Uint8Array): Promise { 35 | // We have enough space 36 | if (this.fillLevel + chunk.byteLength <= Stream.BufferSize) { 37 | this.chunks.push(chunk); 38 | this.fillLevel += chunk.byteLength; 39 | this.signalData(); 40 | return; 41 | } 42 | // Wait for the necessary space. 43 | const targetFillLevel = Math.max(0, Stream.BufferSize - chunk.byteLength); 44 | try { 45 | await this.awaitFillLevel(targetFillLevel); 46 | if (this.fillLevel > targetFillLevel) { 47 | throw new Error(`Invalid state: fillLevel should be <= ${targetFillLevel}`); 48 | } 49 | this.chunks.push(chunk); 50 | this.fillLevel += chunk.byteLength; 51 | this.signalData(); 52 | return; 53 | } catch (error) { 54 | if (error instanceof DestroyError) { 55 | return; 56 | } 57 | throw error; 58 | } 59 | } 60 | 61 | public async read(): Promise; 62 | public async read(mode: 'max', size: number): Promise; 63 | public async read(mode?: 'max', size?: number): Promise { 64 | const maxBytes = mode === 'max' ? size : undefined; 65 | if (this.chunks.length === 0) { 66 | try { 67 | await this.awaitData(); 68 | } catch (error) { 69 | if (error instanceof DestroyError) { 70 | return new Uint8Array(0); 71 | } 72 | throw error; 73 | } 74 | } 75 | if (this.chunks.length === 0) { 76 | throw new Error('Invalid state: no bytes available after awaiting data'); 77 | } 78 | // No max bytes or all data fits into the result. 79 | if (maxBytes === undefined || maxBytes > this.fillLevel) { 80 | const result = new Uint8Array(this.fillLevel); 81 | let offset = 0; 82 | for (const chunk of this.chunks) { 83 | result.set(chunk, offset); 84 | offset += chunk.byteLength; 85 | } 86 | this.chunks = []; 87 | this.fillLevel = 0; 88 | this.signalSpace(); 89 | return result; 90 | } 91 | 92 | const chunk = this.chunks[0]; 93 | // The first chunk is bigger than the maxBytes. Although not optimal we need 94 | // to split it up 95 | if (chunk.byteLength > maxBytes) { 96 | const result = chunk.subarray(0, maxBytes); 97 | this.chunks[0] = chunk.subarray(maxBytes); 98 | this.fillLevel -= maxBytes; 99 | this.signalSpace(); 100 | return result; 101 | } else { 102 | let resultSize = chunk.byteLength; 103 | for (let i = 1; i < this.chunks.length; i++) { 104 | if (resultSize + this.chunks[i].byteLength > maxBytes) { 105 | break; 106 | } 107 | } 108 | const result = new Uint8Array(resultSize); 109 | let offset = 0; 110 | for (let i = 0; i < this.chunks.length; i++) { 111 | const chunk = this.chunks.shift()!; 112 | if (offset + chunk.byteLength > maxBytes) { 113 | break; 114 | } 115 | result.set(chunk, offset); 116 | offset += chunk.byteLength; 117 | this.fillLevel -= chunk.byteLength; 118 | } 119 | this.signalSpace(); 120 | return result; 121 | } 122 | } 123 | 124 | public end(): void { 125 | } 126 | 127 | public destroy(): void { 128 | this.chunks = []; 129 | this.fillLevel = 0; 130 | const error = new DestroyError(); 131 | for (const { promise } of this.awaitForFillLevel) { 132 | promise.reject(error); 133 | } 134 | this.awaitForFillLevel = []; 135 | for (const promise of this.awaitForData) { 136 | promise.reject(error); 137 | } 138 | } 139 | 140 | private awaitFillLevel(targetFillLevel: number): Promise { 141 | const result = CapturedPromise.create(); 142 | this.awaitForFillLevel.push({ fillLevel: targetFillLevel, promise: result }); 143 | return result.promise; 144 | } 145 | 146 | private awaitData(): Promise { 147 | const result = CapturedPromise.create(); 148 | this.awaitForData.push(result); 149 | return result.promise; 150 | } 151 | 152 | protected signalSpace(): void { 153 | if (this.awaitForFillLevel.length === 0) { 154 | return; 155 | } 156 | const { fillLevel, promise } = this.awaitForFillLevel[0]; 157 | // Not enough space. 158 | if (this.fillLevel > fillLevel) { 159 | return; 160 | } 161 | this.awaitForFillLevel.shift(); 162 | promise.resolve(); 163 | } 164 | 165 | protected signalData(): void { 166 | if (this.awaitForData.length === 0) { 167 | return; 168 | } 169 | const promise = this.awaitForData.shift()!; 170 | promise.resolve(); 171 | } 172 | 173 | } 174 | 175 | export class WritableStream extends Stream implements Writable { 176 | 177 | private readonly encoding: 'utf-8'; 178 | private readonly encoder: RAL.TextEncoder; 179 | 180 | constructor(encoding?: 'utf-8') { 181 | super(); 182 | this.encoding = encoding ?? 'utf-8'; 183 | this.encoder = RAL().TextEncoder.create(this.encoding); 184 | } 185 | 186 | public async write(chunk: Uint8Array | string): Promise { 187 | return super.write(typeof chunk === 'string' ? this.encoder.encode(chunk) : chunk); 188 | } 189 | 190 | public end(): void { 191 | } 192 | } 193 | 194 | enum ReadableStreamMode { 195 | initial, 196 | flowing, 197 | paused 198 | } 199 | 200 | export class ReadableStream extends Stream implements Readable { 201 | 202 | private mode: ReadableStreamMode; 203 | private readonly _onData: EventEmitter; 204 | private readonly _onDataEvent: Event; 205 | private timer: Disposable | undefined; 206 | 207 | constructor() { 208 | super(); 209 | this.mode = ReadableStreamMode.initial; 210 | this._onData = new EventEmitter(); 211 | this._onDataEvent = (listener, thisArgs?, disposables?) => { 212 | if (this.mode === ReadableStreamMode.initial) { 213 | this.mode = ReadableStreamMode.flowing; 214 | } 215 | return this._onData.event(listener, thisArgs, disposables); 216 | }; 217 | } 218 | 219 | public get onData(): Event { 220 | return this._onDataEvent; 221 | } 222 | 223 | public pause(flush: boolean = false): void { 224 | // When we are in flowing mode emit all chunks as data events 225 | // before switching to paused mode. 226 | if (this.mode === ReadableStreamMode.flowing) { 227 | if (this.timer !== undefined) { 228 | this.timer.dispose(); 229 | this.timer = undefined; 230 | } 231 | if (flush) { 232 | this.emitAll(); 233 | } 234 | } 235 | this.mode = ReadableStreamMode.paused; 236 | } 237 | 238 | public resume(): void { 239 | this.mode = ReadableStreamMode.flowing; 240 | if (this.chunks.length > 0) { 241 | this.signalData(); 242 | } 243 | } 244 | 245 | public async read(mode?: 'max', size?: number): Promise { 246 | if (this.mode === ReadableStreamMode.flowing) { 247 | throw new Error('Cannot read from stream in flowing mode'); 248 | } 249 | return mode === undefined ? super.read() : super.read(mode, size!); 250 | } 251 | 252 | public end(): void { 253 | if (this.mode === ReadableStreamMode.flowing) { 254 | this.emitAll(); 255 | } 256 | return super.destroy(); 257 | } 258 | 259 | protected signalData(): void { 260 | if (this.mode === ReadableStreamMode.flowing) { 261 | if (this.timer !== undefined) { 262 | return; 263 | } 264 | this.timer = RAL().timer.setImmediate(() => this.triggerData()); 265 | } else { 266 | super.signalData(); 267 | } 268 | } 269 | 270 | private emitAll(): void { 271 | if (this.chunks.length > 0) { 272 | for (const chunk of this.chunks) { 273 | try { 274 | this._onData.fire(chunk); 275 | } catch (error) { 276 | RAL().console.error(`[ReadableStream]: Error while emitting data event: ${error}`); 277 | } 278 | } 279 | this.chunks = []; 280 | } 281 | } 282 | 283 | private triggerData() { 284 | this.timer = undefined; 285 | if (this.chunks.length === 0) { 286 | return; 287 | } 288 | const chunk = this.chunks.shift()!; 289 | this.fillLevel -= chunk.byteLength; 290 | this._onData.fire(chunk); 291 | this.signalSpace(); 292 | if (this.chunks.length > 0) { 293 | this.timer = RAL().timer.setImmediate(() => this.triggerData()); 294 | } 295 | } 296 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/terminal.d.ts: -------------------------------------------------------------------------------- 1 | import { Event } from 'vscode'; 2 | import { Stdio, WasmPseudoterminal, PseudoterminalState } from './api'; 3 | export interface Options { 4 | history?: boolean; 5 | } 6 | export declare class WasmPseudoterminalImpl implements WasmPseudoterminal { 7 | private readonly options; 8 | private readonly commandHistory; 9 | private state; 10 | private readonly _onDidClose; 11 | readonly onDidClose: Event; 12 | private readonly _onDidWrite; 13 | readonly onDidWrite: Event; 14 | private readonly _onDidChangeName; 15 | readonly onDidChangeName: Event; 16 | private readonly _onDidCtrlC; 17 | readonly onDidCtrlC: Event; 18 | private readonly _onAnyKey; 19 | readonly onAnyKey: Event; 20 | private readonly _onDidChangeState; 21 | readonly onDidChangeState: Event<{ 22 | old: PseudoterminalState; 23 | new: PseudoterminalState; 24 | }>; 25 | private readonly _onDidCloseTerminal; 26 | readonly onDidCloseTerminal: Event; 27 | private lineBuffer; 28 | private readlineCallback; 29 | private isOpen; 30 | private nameBuffer; 31 | private writeBuffer; 32 | private encoder; 33 | private decoder; 34 | constructor(options?: Options); 35 | get stdio(): Stdio; 36 | setState(state: PseudoterminalState): void; 37 | getState(): PseudoterminalState; 38 | setName(name: string): void; 39 | open(): void; 40 | close(): void; 41 | read(maxBytesToRead: number): Promise; 42 | bytesAvailable(): number; 43 | write(content: string): Promise; 44 | write(content: Uint8Array, encoding?: 'utf-8'): Promise; 45 | private writeString; 46 | handleInput(data: string): void; 47 | } 48 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/terminal.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | import { Event, EventEmitter } from 'vscode'; 6 | 7 | import RAL from './ral'; 8 | import { Stdio, WasmPseudoterminal, PseudoterminalState } from './api'; 9 | 10 | class LineBuffer { 11 | 12 | private offset: number; 13 | private cursor: number; 14 | private content: string[]; 15 | constructor() { 16 | this.offset = 0; 17 | this.cursor = 0; 18 | this.content = []; 19 | } 20 | 21 | public clear(): void { 22 | this.offset = 0; 23 | this.cursor = 0; 24 | this.content = []; 25 | } 26 | 27 | public setContent(content: string): void { 28 | this.content = content.split(''); 29 | this.cursor = this.content.length; 30 | } 31 | 32 | public getOffset(): number { 33 | return this.offset; 34 | } 35 | 36 | public setOffset(offset: number): void { 37 | this.offset = offset; 38 | } 39 | 40 | public getLine(): string { 41 | return this.content.join(''); 42 | } 43 | 44 | public getCursor(): number { 45 | return this.cursor; 46 | } 47 | 48 | public isCursorAtEnd(): boolean { 49 | return this.cursor === this.content.length; 50 | } 51 | 52 | public isCursorAtBeginning(): boolean { 53 | return this.cursor === 0; 54 | } 55 | 56 | public insert(value: String) { 57 | for (const char of value) { 58 | this.content.splice(this.cursor, 0, char); 59 | this.cursor++; 60 | } 61 | } 62 | 63 | public del(): boolean { 64 | if (this.cursor === this.content.length) { 65 | return false; 66 | } 67 | this.content.splice(this.cursor, 1); 68 | return true; 69 | } 70 | 71 | public backspace(): boolean { 72 | if (this.cursor === 0) { 73 | return false; 74 | } 75 | this.cursor -= 1; 76 | this.content.splice(this.cursor, 1); 77 | return true; 78 | } 79 | 80 | public moveCursorRelative(characters: number): boolean { 81 | const newValue = this.cursor + characters; 82 | if (newValue < 0 || newValue > this.content.length) { 83 | return false; 84 | } 85 | this.cursor = newValue; 86 | return true; 87 | } 88 | 89 | public moveCursorStartOfLine(): boolean { 90 | if (this.cursor === 0) { 91 | return false; 92 | } 93 | this.cursor = 0; 94 | return true; 95 | } 96 | 97 | public moveCursorEndOfLine(): boolean { 98 | if (this.cursor === this.content.length) { 99 | return false; 100 | } 101 | this.cursor = this.content.length; 102 | return true; 103 | } 104 | 105 | public moveCursorWordLeft(): boolean { 106 | if (this.cursor === 0) { 107 | return false; 108 | } 109 | let index: number; 110 | // check if we are at the beginning of a word 111 | if (this.content[this.cursor - 1] === ' ') { 112 | index = this.cursor - 2; 113 | while (index > 0) { 114 | if (this.content[index] === ' ') { 115 | index--; 116 | } else { 117 | break; 118 | } 119 | } 120 | } else { 121 | index = this.cursor; 122 | } 123 | if (index === 0) { 124 | this.cursor = index; 125 | return true; 126 | } 127 | // On the first character that is not space 128 | while (index > 0) { 129 | if (this.content[index] === ' ') { 130 | index++; 131 | break; 132 | } else { 133 | index--; 134 | } 135 | } 136 | this.cursor = index; 137 | return true; 138 | } 139 | 140 | public moveCursorWordRight(): boolean { 141 | if (this.cursor === this.content.length) { 142 | return false; 143 | } 144 | let index: number; 145 | if (this.content[this.cursor] === ' ') { 146 | index = this.cursor + 1; 147 | while (index < this.content.length) { 148 | if (this.content[index] === ' ') { 149 | index++; 150 | } else { 151 | break; 152 | } 153 | } 154 | } else { 155 | index = this.cursor; 156 | } 157 | if (index === this.content.length) { 158 | this.cursor = index; 159 | return true; 160 | } 161 | 162 | while (index < this.content.length) { 163 | if (this.content[index] === ' ') { 164 | break; 165 | } else { 166 | index++; 167 | } 168 | } 169 | this.cursor = index; 170 | return true; 171 | } 172 | } 173 | 174 | export interface Options { 175 | history?: boolean; 176 | } 177 | 178 | class CommandHistory { 179 | 180 | private readonly history: string[]; 181 | private current: number; 182 | 183 | constructor() { 184 | this.history = ['']; 185 | this.current = 0; 186 | } 187 | 188 | public update(command: string): void { 189 | this.history[this.history.length - 1] = command; 190 | } 191 | 192 | public markExecuted(): void { 193 | // We execute a command from the history so we need to add it to the top. 194 | if (this.current !== this.history.length - 1) { 195 | this.history[this.history.length - 1] = this.history[this.current]; 196 | } 197 | if (this.history[this.history.length - 1] === this.history[this.history.length - 2]) { 198 | this.history.pop(); 199 | } 200 | this.history.push(''); 201 | this.current = this.history.length - 1; 202 | } 203 | 204 | public previous(): string | undefined { 205 | if (this.current === 0) { 206 | return undefined; 207 | } 208 | return this.history[--this.current]; 209 | } 210 | 211 | public next(): string | undefined { 212 | if (this.current === this.history.length - 1) { 213 | return undefined; 214 | } 215 | return this.history[++this.current]; 216 | } 217 | } 218 | 219 | export class WasmPseudoterminalImpl implements WasmPseudoterminal { 220 | 221 | private readonly options: Options; 222 | private readonly commandHistory: CommandHistory | undefined; 223 | private state: PseudoterminalState; 224 | 225 | private readonly _onDidClose: EventEmitter; 226 | public readonly onDidClose: Event; 227 | 228 | private readonly _onDidWrite: EventEmitter; 229 | public readonly onDidWrite: Event; 230 | 231 | private readonly _onDidChangeName: EventEmitter; 232 | public readonly onDidChangeName: Event; 233 | 234 | private readonly _onDidCtrlC: EventEmitter; 235 | public readonly onDidCtrlC: Event; 236 | 237 | private readonly _onAnyKey: EventEmitter; 238 | public readonly onAnyKey: Event; 239 | 240 | private readonly _onDidChangeState: EventEmitter<{ old: PseudoterminalState; new: PseudoterminalState }>; 241 | public readonly onDidChangeState: Event<{ old: PseudoterminalState; new: PseudoterminalState }>; 242 | 243 | private readonly _onDidCloseTerminal: EventEmitter; 244 | public readonly onDidCloseTerminal: Event; 245 | 246 | // private lines: string[]; 247 | private lineBuffer: Uint8Array; 248 | private readlineCallback: ((value: string ) => void) | undefined; 249 | 250 | private isOpen: boolean; 251 | private nameBuffer: string | undefined; 252 | private writeBuffer: string[] | undefined; 253 | private encoder: RAL.TextEncoder; 254 | private decoder: RAL.TextDecoder; 255 | 256 | constructor(options: Options = {}) { 257 | this.options = options; 258 | this.commandHistory = this.options.history ? new CommandHistory() : undefined; 259 | this.state = PseudoterminalState.busy; 260 | 261 | this._onDidClose = new EventEmitter(); 262 | this.onDidClose = this._onDidClose.event; 263 | 264 | this._onDidWrite = new EventEmitter(); 265 | this.onDidWrite = this._onDidWrite.event; 266 | 267 | this._onDidChangeName = new EventEmitter(); 268 | this.onDidChangeName = this._onDidChangeName.event; 269 | 270 | this._onDidCtrlC = new EventEmitter(); 271 | this.onDidCtrlC = this._onDidCtrlC.event; 272 | 273 | this._onAnyKey = new EventEmitter(); 274 | this.onAnyKey = this._onAnyKey.event; 275 | 276 | this._onDidChangeState = new EventEmitter<{ old: PseudoterminalState; new: PseudoterminalState }>(); 277 | this.onDidChangeState = this._onDidChangeState.event; 278 | 279 | this._onDidCloseTerminal = new EventEmitter(); 280 | this.onDidCloseTerminal = this._onDidCloseTerminal.event; 281 | 282 | this.encoder = RAL().TextEncoder.create(); 283 | this.decoder = RAL().TextDecoder.create(); 284 | 285 | // this.lines = []; 286 | this.lineBuffer = new Uint8Array(0); 287 | 288 | this.isOpen = false; 289 | } 290 | 291 | public get stdio(): Stdio { 292 | return { 293 | in: { kind: 'terminal', terminal: this }, 294 | out: { kind: 'terminal', terminal: this }, 295 | err: { kind: 'terminal', terminal: this } 296 | }; 297 | } 298 | 299 | public setState(state: PseudoterminalState): void { 300 | const old = this.state; 301 | this.state = state; 302 | if (old !== state) { 303 | this._onDidChangeState.fire({ old, new: state }); 304 | } 305 | } 306 | 307 | public getState(): PseudoterminalState { 308 | return this.state; 309 | } 310 | 311 | public setName(name: string): void { 312 | if (this.isOpen) { 313 | this._onDidChangeName.fire(name); 314 | } else { 315 | this.nameBuffer = name; 316 | } 317 | } 318 | 319 | public open(): void { 320 | this.isOpen = true; 321 | if (this.nameBuffer !== undefined) { 322 | this._onDidChangeName.fire(this.nameBuffer); 323 | this.nameBuffer = undefined; 324 | } 325 | if (this.writeBuffer !== undefined) { 326 | for (const item of this.writeBuffer) { 327 | this._onDidWrite.fire(item); 328 | } 329 | this.writeBuffer = undefined; 330 | } 331 | } 332 | 333 | public close(): void { 334 | this._onDidCloseTerminal.fire(); 335 | } 336 | 337 | public async read(maxBytesToRead: number): Promise { 338 | let length: number = maxBytesToRead; 339 | if (length > this.lineBuffer.byteLength) 340 | length = this.lineBuffer.byteLength; 341 | const buf = this.lineBuffer.slice(0, length); 342 | const remain = this.lineBuffer.slice(length, this.lineBuffer.byteLength); 343 | this.lineBuffer = remain; 344 | return buf; 345 | } 346 | 347 | public bytesAvailable(): number { 348 | return this.lineBuffer.byteLength; 349 | } 350 | 351 | public write(content: string): Promise; 352 | public write(content: Uint8Array, encoding?: 'utf-8'): Promise; 353 | public write(content: Uint8Array | string, encoding?: 'utf-8'): Promise | Promise { 354 | if (typeof content === 'string') { 355 | this.writeString(content); 356 | return Promise.resolve(); 357 | } else { 358 | this.writeString(this.decoder.decode(content.slice())); 359 | return Promise.resolve(content.byteLength); 360 | } 361 | } 362 | 363 | private writeString(str: string): void { 364 | if (this.isOpen) { 365 | this._onDidWrite.fire(str); 366 | } else { 367 | if (this.writeBuffer === undefined) { 368 | this.writeBuffer = []; 369 | } 370 | this.writeBuffer.push(str); 371 | } 372 | } 373 | 374 | public handleInput(data: string): void { 375 | if (this.state === PseudoterminalState.free) { 376 | this._onAnyKey.fire(); 377 | return; 378 | } 379 | const dataE = this.encoder.encode(data); 380 | const buf2 = new Uint8Array(this.lineBuffer.byteLength + dataE.byteLength); 381 | buf2.set(new Uint8Array(this.lineBuffer), 0); 382 | buf2.set(new Uint8Array(dataE), this.lineBuffer.byteLength); 383 | this.lineBuffer = buf2 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/terminalDriver.d.ts: -------------------------------------------------------------------------------- 1 | import type { WasmPseudoterminal } from './api'; 2 | import { CharacterDeviceDriver, DeviceId } from './deviceDriver'; 3 | export declare function create(deviceId: DeviceId, terminal: WasmPseudoterminal): CharacterDeviceDriver; 4 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/terminalDriver.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import { Uri } from 'vscode'; 6 | 7 | import type { WasmPseudoterminal } from './api'; 8 | import type { size } from './baseTypes'; 9 | import { fd, fdflags, fdstat, filestat, Filetype, Rights, rights, filesize } from './wasi'; 10 | import { CharacterDeviceDriver, DeviceDriverKind, DeviceId, NoSysDeviceDriver } from './deviceDriver'; 11 | import { BaseFileDescriptor, FileDescriptor } from './fileDescriptor'; 12 | import { BigInts } from './converter'; 13 | 14 | const TerminalBaseRights: rights = Rights.fd_read | Rights.fd_fdstat_set_flags | Rights.fd_write | 15 | Rights.fd_filestat_get | Rights.poll_fd_readwrite; 16 | 17 | const TerminalInheritingRights = 0n; 18 | 19 | class TerminalFileDescriptor extends BaseFileDescriptor { 20 | constructor(deviceId: bigint, fd: fd, rights_base: rights, rights_inheriting: rights, fdflags: fdflags, inode: bigint) { 21 | super(deviceId, fd, Filetype.character_device, rights_base, rights_inheriting, fdflags, inode); 22 | } 23 | 24 | public with(change: { fd: number }): FileDescriptor { 25 | return new TerminalFileDescriptor(this.deviceId, change.fd, this.rights_base, this.rights_inheriting, this.fdflags, this.inode); 26 | } 27 | } 28 | 29 | export function create(deviceId: DeviceId, terminal: WasmPseudoterminal): CharacterDeviceDriver { 30 | 31 | let inodeCounter: bigint = 0n; 32 | 33 | function createTerminalFileDescriptor(fd: 0 | 1 | 2): TerminalFileDescriptor { 34 | return new TerminalFileDescriptor(deviceId, fd, TerminalBaseRights, TerminalInheritingRights, 0, inodeCounter++); 35 | } 36 | 37 | const deviceDriver: Pick = { 38 | kind: DeviceDriverKind.character, 39 | id: deviceId, 40 | uri: Uri.from({ scheme: 'wasi-terminal', authority: deviceId.toString() }), 41 | createStdioFileDescriptor(fd: 0 | 1 | 2): FileDescriptor { 42 | return createTerminalFileDescriptor(fd); 43 | }, 44 | fd_fdstat_get(fileDescriptor: FileDescriptor, result: fdstat): Promise { 45 | result.fs_filetype = fileDescriptor.fileType; 46 | result.fs_flags = fileDescriptor.fdflags; 47 | result.fs_rights_base = fileDescriptor.rights_base; 48 | result.fs_rights_inheriting = fileDescriptor.rights_inheriting; 49 | return Promise.resolve(); 50 | }, 51 | fd_filestat_get(fileDescriptor: FileDescriptor, result: filestat): Promise { 52 | result.dev = fileDescriptor.deviceId; 53 | result.ino = fileDescriptor.inode; 54 | result.filetype = Filetype.character_device; 55 | result.nlink = 0n; 56 | result.size = 101n; 57 | const now = BigInt(Date.now()); 58 | result.atim = now; 59 | result.ctim = now; 60 | result.mtim = now; 61 | return Promise.resolve(); 62 | }, 63 | async fd_read(_fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise { 64 | if (buffers.length === 0) { 65 | return 0; 66 | } 67 | const maxBytesToRead = buffers.reduce((prev, current) => prev + current.length, 0); 68 | const result = await terminal.read(maxBytesToRead); 69 | let offset = 0; 70 | let totalBytesRead = 0; 71 | for (const buffer of buffers) { 72 | const toCopy = Math.min(buffer.length, result.length - offset); 73 | buffer.set(result.subarray(offset, offset + toCopy)); 74 | offset += toCopy; 75 | totalBytesRead += toCopy; 76 | if (toCopy < buffer.length) { 77 | break; 78 | } 79 | } 80 | return totalBytesRead; 81 | }, 82 | fd_write(_fileDescriptor: FileDescriptor, buffers: Uint8Array[]): Promise { 83 | let buffer: Uint8Array; 84 | if (buffers.length === 1) { 85 | buffer = buffers[0]; 86 | } else { 87 | const byteLength: number = buffers.reduce((prev, current) => prev + current.length, 0); 88 | buffer = new Uint8Array(byteLength); 89 | let offset = 0; 90 | for (const item of buffers) { 91 | buffer.set(item, offset); 92 | offset = item.byteLength; 93 | } 94 | } 95 | return terminal.write(buffer); 96 | }, 97 | fd_bytesAvailable(_fileDescriptor: FileDescriptor): Promise { 98 | return Promise.resolve(BigInts.max(0n, BigInt(terminal.bytesAvailable()))); 99 | } 100 | }; 101 | 102 | return Object.assign({}, NoSysDeviceDriver, deviceDriver); 103 | } 104 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/trace.d.ts: -------------------------------------------------------------------------------- 1 | import { ptr, u32, u64 } from './baseTypes'; 2 | import { errno } from './wasi'; 3 | declare namespace wasi { 4 | type Uint32 = { 5 | readonly $ptr: ptr; 6 | value: number; 7 | }; 8 | type Uint32Array = { 9 | readonly $ptr: ptr; 10 | size: number; 11 | get(index: number): number; 12 | set(index: number, value: number): void; 13 | }; 14 | type Uint64 = { 15 | readonly $ptr: ptr; 16 | value: bigint; 17 | }; 18 | type String = { 19 | readonly $ptr: ptr; 20 | byteLength: number; 21 | }; 22 | type StringBuffer = { 23 | readonly $ptr: ptr; 24 | get value(): string; 25 | }; 26 | type Bytes = { 27 | readonly $ptr: ptr; 28 | readonly byteLength: number; 29 | }; 30 | type StructArray = { 31 | readonly $ptr: ptr; 32 | size: number; 33 | get(index: number): T; 34 | }; 35 | } 36 | export declare class Memory { 37 | private readonly raw; 38 | private readonly dataView; 39 | private readonly decoder; 40 | constructor(raw: ArrayBuffer); 41 | readUint32(ptr: ptr): u32; 42 | readUint32Array(ptr: ptr, size: number): wasi.Uint32Array; 43 | readUint64(ptr: ptr): u64; 44 | readStruct(ptr: ptr, info: { 45 | size: number; 46 | create: (memory: DataView, ptr: ptr) => T; 47 | }): T; 48 | readString(ptr: ptr, len?: number): string; 49 | readBytes(ptr: ptr, length: number): Uint8Array; 50 | private getStringLength; 51 | } 52 | export interface TraceMessage { 53 | [name: string]: (memory: ArrayBuffer, result: errno, ...args: (number & bigint)[]) => string; 54 | } 55 | export declare namespace TraceMessage { 56 | function create(): TraceMessage; 57 | } 58 | export {}; 59 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "vscode" 5 | ], 6 | "module": "Node16", 7 | "moduleResolution": "Node16", 8 | "target": "es2020", 9 | "lib": [ 10 | "es2020" 11 | ], 12 | "rootDir": ".", 13 | "strict": true, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "declaration": true, 18 | "stripInternal": true, 19 | "sourceMap": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "outDir": "../../lib/common", 23 | "tsBuildInfoFile": "../../lib/common/compile.tsbuildInfo", 24 | "incremental": true, 25 | "composite": true 26 | }, 27 | "include": [ 28 | "." 29 | ], 30 | "exclude": [ 31 | "test" 32 | ] 33 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/tsconfig.publish.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "vscode" 5 | ], 6 | "module": "Node16", 7 | "moduleResolution": "Node16", 8 | "target": "es2020", 9 | "lib": [ 10 | "es2020" 11 | ], 12 | "rootDir": ".", 13 | "strict": true, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "declaration": true, 18 | "stripInternal": true, 19 | "sourceMap": false, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "outDir": "../../lib/common", 23 | "tsBuildInfoFile": "../../lib/common/publish.tsbuildInfo", 24 | "incremental": true, 25 | "composite": true 26 | }, 27 | "include": [ 28 | "." 29 | ], 30 | "exclude": [ 31 | "test" 32 | ] 33 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/tsconfig.watch.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "vscode" 5 | ], 6 | "module": "Node16", 7 | "moduleResolution": "Node16", 8 | "target": "es2020", 9 | "lib": [ 10 | "es2020" 11 | ], 12 | "rootDir": ".", 13 | "strict": true, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "declaration": true, 18 | "stripInternal": true, 19 | "sourceMap": true, 20 | "noUnusedLocals": false, 21 | "noUnusedParameters": false, 22 | "assumeChangesOnlyAffectDirectDependencies": true, 23 | "outDir": "../../lib/common", 24 | "tsBuildInfoFile": "../../lib/common/watch.tsbuildInfo", 25 | "incremental": true, 26 | "composite": true 27 | }, 28 | "include": [ 29 | "." 30 | ], 31 | "exclude": [ 32 | "test" 33 | ] 34 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/version.d.ts: -------------------------------------------------------------------------------- 1 | declare const version = "0.13.0"; 2 | export default version; 3 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/version.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | const version = '0.13.0'; 7 | export default version; -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/vscodeFileSystemDriver.d.ts: -------------------------------------------------------------------------------- 1 | import { Uri } from 'vscode'; 2 | import { FileSystemDeviceDriver, DeviceId } from './deviceDriver'; 3 | export declare function create(deviceId: DeviceId, baseUri: Uri, readOnly?: boolean): FileSystemDeviceDriver; 4 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/wasiMeta.d.ts: -------------------------------------------------------------------------------- 1 | import { ptr } from './baseTypes'; 2 | export declare enum ParamKind { 3 | ptr = 1, 4 | number = 2, 5 | bigint = 3 6 | } 7 | export type NumberParam = { 8 | kind: ParamKind.number; 9 | size: number; 10 | write: (view: DataView, offset: number, value: number) => void; 11 | read: (view: DataView, offset: number) => number; 12 | }; 13 | export type BigintParam = { 14 | kind: ParamKind.bigint; 15 | size: number; 16 | write: (view: DataView, offset: number, value: bigint) => void; 17 | read: (view: DataView, offset: number) => bigint; 18 | }; 19 | export declare enum DataKind { 20 | param = 1, 21 | result = 2, 22 | both = 3 23 | } 24 | export type PtrParam = { 25 | kind: ParamKind.ptr; 26 | size: 4; 27 | write: (view: DataView, offset: number, value: number) => void; 28 | read: (view: DataView, offset: number) => number; 29 | }; 30 | export type Param = PtrParam | NumberParam | BigintParam; 31 | export type WasiFunctionSignature = { 32 | params: Param[]; 33 | memorySize: number; 34 | }; 35 | export declare namespace WasiFunctionSignature { 36 | function create(params: Param[]): WasiFunctionSignature; 37 | } 38 | export declare enum MemoryTransferDirection { 39 | param = 1, 40 | result = 2, 41 | both = 3 42 | } 43 | export type SingleReverseArgumentTransfer = { 44 | readonly from: ptr; 45 | readonly to: ptr; 46 | readonly size: number; 47 | }; 48 | export type ReverseArgumentTransfer = SingleReverseArgumentTransfer | SingleReverseArgumentTransfer[] | undefined; 49 | export type ReverseArgumentsTransfer = ReverseArgumentTransfer[]; 50 | export type ArgumentTransfer = { 51 | readonly memorySize: number; 52 | copy: (wasmMemory: ArrayBuffer, from: ptr, transferMemory: SharedArrayBuffer, to: ptr) => ReverseArgumentTransfer | undefined; 53 | }; 54 | export type ArgumentsTransfer = { 55 | items: ArgumentTransfer[]; 56 | readonly size: number; 57 | }; 58 | export declare namespace ArgumentsTransfer { 59 | const Null: ArgumentsTransfer; 60 | function create(items: ArgumentTransfer[]): ArgumentsTransfer; 61 | } 62 | export type ReverseCustomTransfer = { 63 | copy: () => void; 64 | }; 65 | export type CustomMemoryTransfer = { 66 | readonly size: number; 67 | copy: (wasmMemory: ArrayBuffer, args: (number | bigint)[], paramBuffer: SharedArrayBuffer, paramIndex: number, transferMemory: SharedArrayBuffer) => ReverseCustomTransfer; 68 | }; 69 | export type MemoryTransfer = ArgumentsTransfer | CustomMemoryTransfer; 70 | export declare namespace MemoryTransfer { 71 | function isCustom(transfer: MemoryTransfer | undefined): transfer is CustomMemoryTransfer; 72 | function isArguments(transfer: MemoryTransfer | undefined): transfer is ArgumentsTransfer; 73 | } 74 | export type ReverseTransfer = ReverseArgumentsTransfer | ReverseCustomTransfer; 75 | export declare namespace ReverseTransfer { 76 | function isCustom(transfer: ReverseTransfer | undefined): transfer is ReverseCustomTransfer; 77 | function isArguments(transfer: ReverseTransfer | undefined): transfer is ReverseArgumentsTransfer; 78 | } 79 | export type WasiFunction = { 80 | readonly name: string; 81 | readonly signature: WasiFunctionSignature; 82 | transfers?: (memory: DataView, ...params: (number & bigint)[]) => ArgumentsTransfer | CustomMemoryTransfer; 83 | }; 84 | export type WasiFunctions = { 85 | add(wasiFunction: WasiFunction): void; 86 | functionAt(index: number): WasiFunction; 87 | get(name: string): WasiFunction; 88 | getIndex(name: string): number; 89 | getName(index: number): string; 90 | }; 91 | export declare const WasiFunctions: WasiFunctions; 92 | export declare namespace U8 { 93 | const size: 1; 94 | const $ptr: PtrParam; 95 | const $param: NumberParam; 96 | } 97 | export declare const Byte: typeof U8; 98 | export declare namespace Bytes { 99 | const $ptr: PtrParam; 100 | function createTransfer(length: number, direction: MemoryTransferDirection): ArgumentTransfer; 101 | } 102 | export declare namespace U16 { 103 | const size: 2; 104 | const $ptr: PtrParam; 105 | const $param: NumberParam; 106 | const $transfer: ArgumentTransfer; 107 | } 108 | export declare namespace U32 { 109 | const size: 4; 110 | const $ptr: PtrParam; 111 | const $param: NumberParam; 112 | const $transfer: ArgumentTransfer; 113 | } 114 | export declare const Size: typeof U32; 115 | export declare namespace U64 { 116 | const size: 8; 117 | const $ptr: PtrParam; 118 | const $param: BigintParam; 119 | const $transfer: ArgumentTransfer; 120 | } 121 | export declare namespace S64 { 122 | const size: 8; 123 | const $ptr: PtrParam; 124 | const $param: BigintParam; 125 | } 126 | export declare namespace Ptr { 127 | const size: 4; 128 | const $param: PtrParam; 129 | function createTransfer(length: number, direction: MemoryTransferDirection): ArgumentTransfer; 130 | } 131 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/common/wasiMeta.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { ptr } from './baseTypes'; 7 | 8 | export enum ParamKind { 9 | ptr = 1, 10 | number = 2, 11 | bigint = 3, 12 | } 13 | 14 | export type NumberParam = { 15 | kind: ParamKind.number; 16 | size: number; 17 | write: (view: DataView, offset: number, value: number) => void; 18 | read: (view: DataView, offset: number) => number; 19 | }; 20 | 21 | export type BigintParam = { 22 | kind: ParamKind.bigint; 23 | size: number; 24 | write: (view: DataView, offset: number, value: bigint) => void; 25 | read: (view: DataView, offset: number) => bigint; 26 | }; 27 | 28 | export enum DataKind { 29 | param = 1, 30 | result = 2, 31 | both = 3 32 | } 33 | 34 | export type PtrParam = { 35 | kind: ParamKind.ptr; 36 | size: 4; 37 | write: (view: DataView, offset: number, value: number) => void; 38 | read: (view: DataView, offset: number) => number; 39 | }; 40 | 41 | 42 | export type Param = PtrParam | NumberParam | BigintParam; 43 | 44 | const ptr_size = 4 as const; 45 | const PtrParam: PtrParam = { kind: ParamKind.ptr, size: ptr_size, write: (view, offset, value) => view.setUint32(offset, value, true), read: (view, offset) => view.getUint32(offset, true) }; 46 | 47 | export type WasiFunctionSignature = { 48 | params: Param[]; 49 | memorySize: number; 50 | }; 51 | 52 | export namespace WasiFunctionSignature { 53 | export function create(params: Param[]): WasiFunctionSignature { 54 | return { 55 | params, 56 | memorySize: getMemorySize(params) 57 | }; 58 | } 59 | function getMemorySize(params: Param[]): number { 60 | let result: number = 0; 61 | for (const param of params) { 62 | result += param.size; 63 | } 64 | return result; 65 | } 66 | } 67 | 68 | export enum MemoryTransferDirection { 69 | param = 1, 70 | result = 2, 71 | both = 3 72 | } 73 | 74 | export type SingleReverseArgumentTransfer = { 75 | readonly from: ptr; 76 | readonly to: ptr; 77 | readonly size: number; 78 | }; 79 | 80 | export type ReverseArgumentTransfer = SingleReverseArgumentTransfer | SingleReverseArgumentTransfer[] | undefined; 81 | 82 | export type ReverseArgumentsTransfer = ReverseArgumentTransfer[]; 83 | 84 | export type ArgumentTransfer = { 85 | readonly memorySize: number; 86 | copy: (wasmMemory: ArrayBuffer, from: ptr, transferMemory: SharedArrayBuffer, to: ptr) => ReverseArgumentTransfer | undefined; 87 | }; 88 | 89 | export type ArgumentsTransfer = { 90 | items: ArgumentTransfer[]; 91 | readonly size: number; 92 | }; 93 | 94 | export namespace ArgumentsTransfer { 95 | 96 | export const Null: ArgumentsTransfer = { 97 | items: [], 98 | size: 0 99 | }; 100 | 101 | export function create(items: ArgumentTransfer[]): ArgumentsTransfer { 102 | return { 103 | items, 104 | size: getMemorySize(items) 105 | }; 106 | } 107 | 108 | function getMemorySize(transfers: ArgumentTransfer[]): number { 109 | let result: number = 0; 110 | for (const transfer of transfers) { 111 | result += transfer.memorySize; 112 | } 113 | return result; 114 | } 115 | } 116 | 117 | export type ReverseCustomTransfer = { 118 | copy: () => void; 119 | }; 120 | 121 | export type CustomMemoryTransfer = { 122 | readonly size: number; 123 | copy: (wasmMemory: ArrayBuffer, args: (number | bigint)[], paramBuffer: SharedArrayBuffer, paramIndex: number, transferMemory: SharedArrayBuffer) => ReverseCustomTransfer; 124 | }; 125 | 126 | export type MemoryTransfer = ArgumentsTransfer | CustomMemoryTransfer; 127 | export namespace MemoryTransfer { 128 | export function isCustom(transfer: MemoryTransfer | undefined): transfer is CustomMemoryTransfer { 129 | const candidate = transfer as CustomMemoryTransfer; 130 | return candidate && typeof candidate.copy === 'function' && typeof candidate.size === 'number'; 131 | } 132 | export function isArguments(transfer: MemoryTransfer | undefined): transfer is ArgumentsTransfer { 133 | const candidate = transfer as ArgumentsTransfer; 134 | return candidate && Array.isArray(candidate.items) && typeof candidate.size === 'number'; 135 | } 136 | } 137 | 138 | export type ReverseTransfer = ReverseArgumentsTransfer | ReverseCustomTransfer; 139 | export namespace ReverseTransfer { 140 | export function isCustom(transfer: ReverseTransfer | undefined): transfer is ReverseCustomTransfer { 141 | const candidate = transfer as ReverseCustomTransfer; 142 | return candidate && typeof candidate.copy === 'function'; 143 | } 144 | export function isArguments(transfer: ReverseTransfer | undefined): transfer is ReverseArgumentsTransfer { 145 | const candidate = transfer as ReverseArgumentsTransfer; 146 | return candidate && Array.isArray(candidate); 147 | } 148 | } 149 | 150 | export type WasiFunction = { 151 | readonly name: string; 152 | readonly signature: WasiFunctionSignature; 153 | transfers?: (memory: DataView, ...params: (number & bigint)[]) => ArgumentsTransfer | CustomMemoryTransfer; 154 | }; 155 | 156 | namespace _WasiFunctions { 157 | const callbacks: WasiFunction[] = []; 158 | const name2Index: Map = new Map(); 159 | const index2Name: Map = new Map(); 160 | 161 | export function functionAt(index: number): WasiFunction { 162 | if (index >= callbacks.length) { 163 | throw new Error('Should never happen'); 164 | } 165 | return callbacks[index]; 166 | } 167 | 168 | export function get(name: string): WasiFunction { 169 | const index = name2Index.get(name); 170 | if (index === undefined) { 171 | throw new Error('Should never happen'); 172 | } 173 | return callbacks[index]; 174 | } 175 | 176 | export function getIndex(name: string): number { 177 | const result = name2Index.get(name); 178 | if (result === undefined) { 179 | throw new Error('Should never happen'); 180 | } 181 | return result; 182 | } 183 | 184 | export function getName(index: number): string { 185 | const result = index2Name.get(index); 186 | if (result === undefined) { 187 | throw new Error('Should never happen'); 188 | } 189 | return result; 190 | } 191 | 192 | export function add(wasiFunction: WasiFunction): void { 193 | const index = callbacks.length; 194 | callbacks.push(wasiFunction); 195 | name2Index.set(wasiFunction.name, index); 196 | index2Name.set(index, wasiFunction.name); 197 | } 198 | } 199 | 200 | export type WasiFunctions = { 201 | add(wasiFunction: WasiFunction): void; 202 | functionAt(index: number): WasiFunction; 203 | get(name: string): WasiFunction; 204 | getIndex(name: string): number; 205 | getName(index: number): string; 206 | }; 207 | export const WasiFunctions: WasiFunctions = _WasiFunctions; 208 | 209 | export namespace U8 { 210 | export const size = 1 as const; 211 | export const $ptr = PtrParam; 212 | export const $param: NumberParam = { kind: ParamKind.number, size, write: (view, offset, value) => view.setUint8(offset, value), read: (view, offset) => view.getUint8(offset) }; 213 | 214 | } 215 | 216 | export const Byte = U8; 217 | 218 | export namespace Bytes { 219 | export const $ptr = PtrParam; 220 | export function createTransfer(length: number, direction: MemoryTransferDirection): ArgumentTransfer { 221 | return { 222 | memorySize: length, 223 | copy: (wasmMemory, from, transferMemory, to) => { 224 | if (direction === MemoryTransferDirection.param || direction === MemoryTransferDirection.both) { 225 | new Uint8Array(transferMemory, to, length).set(new Uint8Array(wasmMemory, from, length)); 226 | } 227 | return direction === MemoryTransferDirection.param ? undefined : { from: to, to: from , size: length }; 228 | } 229 | }; 230 | } 231 | } 232 | 233 | export namespace U16 { 234 | export const size = 2 as const; 235 | export const $ptr = PtrParam; 236 | export const $param: NumberParam = { kind: ParamKind.number, size, write: (view, offset, value) => view.setUint16(offset, value, true), read: (view, offset) => view.getUint16(offset, true) }; 237 | export const $transfer: ArgumentTransfer = { 238 | memorySize: size, 239 | copy: (_wasmMemory, from, _transferMemory, to) => { 240 | // We have a result pointer so we only need instructions to copy the 241 | // result back into the wasm memory 242 | return { from: to, to: from, size: size }; 243 | } 244 | }; 245 | } 246 | 247 | export namespace U32 { 248 | export const size = 4 as const; 249 | export const $ptr = PtrParam; 250 | export const $param: NumberParam = { kind: ParamKind.number, size, write: (view, offset, value) => view.setUint32(offset, value, true), read: (view, offset) => view.getUint32(offset, true) }; 251 | export const $transfer: ArgumentTransfer = { 252 | memorySize: size, 253 | copy: (_wasmMemory, from, _transferMemory, to) => { 254 | // We have a result pointer so we only need instructions to copy the 255 | // result back into the wasm memory 256 | return { from: to, to: from, size: size }; 257 | } 258 | }; 259 | } 260 | 261 | export const Size = U32; 262 | 263 | export namespace U64 { 264 | export const size = 8 as const; 265 | export const $ptr = PtrParam; 266 | export const $param: BigintParam = { kind: ParamKind.bigint, size, write: (view, offset, value) => view.setBigUint64(offset, value, true), read: (view, offset) => view.getBigUint64(offset, true) }; 267 | export const $transfer: ArgumentTransfer = { 268 | memorySize: size, 269 | copy: (_wasmMemory, from, _transferMemory, to) => { 270 | // We have a result pointer so we only need instructions to copy the 271 | // result back into the wasm memory 272 | return { from: to, to: from, size: size }; 273 | } 274 | }; 275 | } 276 | 277 | export namespace S64 { 278 | export const size = 8 as const; 279 | export const $ptr = PtrParam; 280 | export const $param: BigintParam = { kind: ParamKind.bigint, size, write: (view, offset, value) => view.setBigInt64(offset, value, true), read: (view, offset) => view.getBigInt64(offset, true) }; 281 | } 282 | 283 | export namespace Ptr { 284 | export const size = 4 as const; 285 | export const $param = PtrParam; 286 | 287 | export function createTransfer(length: number, direction: MemoryTransferDirection): ArgumentTransfer { 288 | return { 289 | memorySize: length * size, 290 | copy: (wasmMemory, from, transferMemory, to) => { 291 | if (direction === MemoryTransferDirection.param || direction === MemoryTransferDirection.both) { 292 | new Uint8Array(transferMemory, to, size).set(new Uint8Array(wasmMemory, from, size)); 293 | } 294 | return direction === MemoryTransferDirection.param ? undefined : { from: to, to: from , size }; 295 | } 296 | }; 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/connection.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import RAL from '../common/ral'; 7 | import { HostConnection } from '../common/host'; 8 | import { ServiceMessage, WasiCallMessage, WorkerMessage } from '../common/connection'; 9 | 10 | export abstract class BrowserHostConnection extends HostConnection { 11 | 12 | private readonly port: MessagePort | Worker | DedicatedWorkerGlobalScope; 13 | 14 | public constructor(port: MessagePort | Worker | DedicatedWorkerGlobalScope) { 15 | super(); 16 | this.port = port; 17 | this.port.onmessage = ((event: MessageEvent) => { 18 | this.handleMessage(event.data).catch(RAL().console.error); 19 | }); 20 | } 21 | 22 | public postMessage(message: WasiCallMessage | WorkerMessage): void { 23 | this.port.postMessage(message); 24 | } 25 | 26 | public destroy(): void { 27 | this.port.onmessage = null; 28 | } 29 | 30 | protected abstract handleMessage(_message: ServiceMessage): Promise; 31 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/extension.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import RIL from './ril'; 6 | RIL.install(); 7 | 8 | import { ExtensionContext } from 'vscode'; 9 | import { WasiCoreImpl } from '../common/api'; 10 | import { BrowserWasiProcess } from './process'; 11 | 12 | export async function activate(context: ExtensionContext) { 13 | return WasiCoreImpl.create(context, BrowserWasiProcess, async (source) => { 14 | return WebAssembly.compileStreaming(fetch(source.toString())); 15 | }); 16 | } 17 | 18 | export function deactivate() { 19 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/mainWorker.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import RIL from './ril'; 6 | RIL.install(); 7 | 8 | import { TraceWasiHost, Tracer, WasiHost} from '../common/host'; 9 | import { BrowserHostConnection } from './connection'; 10 | import { ServiceMessage, StartMainMessage, WorkerReadyMessage } from '../common/connection'; 11 | import { CapturedPromise } from '../common/promises'; 12 | 13 | class MainBrowserHostConnection extends BrowserHostConnection { 14 | 15 | private _done: CapturedPromise; 16 | 17 | constructor(port: MessagePort | Worker | DedicatedWorkerGlobalScope) { 18 | super(port); 19 | this._done = CapturedPromise.create(); 20 | } 21 | 22 | public done(): Promise { 23 | return this._done.promise; 24 | } 25 | 26 | protected async handleMessage(message: ServiceMessage): Promise { 27 | if (StartMainMessage.is(message)) { 28 | const module = message.module; 29 | const memory = message.memory; 30 | let host = WasiHost.create(this); 31 | let tracer: Tracer | undefined; 32 | if (message.trace) { 33 | tracer = TraceWasiHost.create(this, host); 34 | host = tracer.tracer; 35 | } 36 | const imports: WebAssembly.Imports = { 37 | wasi_snapshot_preview1: host, 38 | wasi: host 39 | }; 40 | if (memory !== undefined) { 41 | imports.env = { 42 | memory: memory 43 | }; 44 | } 45 | const instance = await WebAssembly.instantiate(module, imports); 46 | host.initialize(memory ?? instance); 47 | (instance.exports._start as Function)(); 48 | if (tracer !== undefined) { 49 | tracer.printSummary(); 50 | } 51 | this._done.resolve(); 52 | } 53 | } 54 | } 55 | 56 | async function main(port: MessagePort | Worker | DedicatedWorkerGlobalScope): Promise { 57 | const connection = new MainBrowserHostConnection(port); 58 | try { 59 | const ready: WorkerReadyMessage = { method: 'workerReady' }; 60 | connection.postMessage(ready); 61 | await connection.done(); 62 | } finally { 63 | connection.postMessage({ method: 'workerDone' }); 64 | connection.destroy(); 65 | } 66 | } 67 | 68 | main(self).catch(RIL().console.error).finally(() => close()); -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/process.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import { LogOutputChannel, Uri } from 'vscode'; 6 | 7 | import RAL from '../common/ral'; 8 | 9 | import { WasiProcess } from '../common/process'; 10 | import { WasiService, ServiceConnection } from '../common/service'; 11 | import type { ptr, u32 } from '../common/baseTypes'; 12 | import type { ServiceMessage, StartMainMessage, StartThreadMessage, WorkerMessage } from '../common/connection'; 13 | import type { ProcessOptions } from '../common/api'; 14 | 15 | export class BrowserServiceConnection extends ServiceConnection { 16 | 17 | private readonly port: MessagePort | Worker; 18 | 19 | constructor(wasiService: WasiService, port: MessagePort | Worker, logChannel?: LogOutputChannel | undefined) { 20 | super(wasiService, logChannel); 21 | this.port = port; 22 | this.port.onmessage = ((event: MessageEvent) => { 23 | this.handleMessage(event.data).catch((error) => RAL().console.error(error)); 24 | }); 25 | } 26 | 27 | public postMessage(message: ServiceMessage): void { 28 | try { 29 | this.port.postMessage(message); 30 | } catch (error) { 31 | RAL().console.error(error); 32 | } 33 | } 34 | } 35 | 36 | export class BrowserWasiProcess extends WasiProcess { 37 | 38 | private readonly baseUri: Uri; 39 | private readonly module: Promise; 40 | 41 | private importsMemory: boolean | undefined; 42 | private readonly memoryDescriptor: WebAssembly.MemoryDescriptor | undefined; 43 | private memory: WebAssembly.Memory | undefined; 44 | 45 | private mainWorker: Worker | undefined; 46 | private threadWorkers: Map; 47 | 48 | constructor(baseUri: Uri, programName: string, module: WebAssembly.Module | Promise, memory: WebAssembly.Memory | WebAssembly.MemoryDescriptor | undefined, options: ProcessOptions = {}) { 49 | super(programName, options); 50 | this.baseUri = baseUri; 51 | this.threadWorkers = new Map(); 52 | this.module = module instanceof WebAssembly.Module 53 | ? Promise.resolve(module) 54 | : module; 55 | if (memory instanceof WebAssembly.Memory) { 56 | this.memory = memory; 57 | } else { 58 | this.memoryDescriptor = memory; 59 | } 60 | } 61 | 62 | protected async procExit(): Promise { 63 | if (this.mainWorker !== undefined) { 64 | this.mainWorker.terminate(); 65 | } 66 | await this.cleanUpWorkers(); 67 | await this.destroyStreams(); 68 | await this.cleanupFileDescriptors(); 69 | } 70 | 71 | public async terminate(): Promise { 72 | const result = 0; 73 | await this.procExit(); 74 | 75 | // when terminated, web workers silently exit, and there are no events 76 | // to hook on to know when they are done. To ensure that the run promise resolves, 77 | // we call it here so callers awaiting `process.run()` will get a result. 78 | this.resolveRunPromise(result); 79 | return result; 80 | } 81 | 82 | protected async startMain(wasiService: WasiService): Promise { 83 | const filename = Uri.joinPath(this.baseUri, './dist/web/mainWorker.js').toString(); 84 | const response = await fetch(filename.toString()); 85 | const code = new Blob([await response.text()], { type: "application/javascript" }); 86 | this.mainWorker = new Worker(URL.createObjectURL(code)); 87 | // this.mainWorker = new Worker(filename); 88 | const connection = new BrowserServiceConnection(wasiService, this.mainWorker, this.options.trace); 89 | await connection.workerReady(); 90 | const module = await this.module; 91 | this.importsMemory = this.doesImportMemory(module); 92 | if (this.importsMemory && this.memory === undefined) { 93 | if (this.memoryDescriptor === undefined) { 94 | throw new Error('Web assembly imports memory but no memory descriptor was provided.'); 95 | } 96 | this.memory = new WebAssembly.Memory(this.memoryDescriptor); 97 | } 98 | const message: StartMainMessage = { method: 'startMain', module: await this.module, memory: this.memory, trace: this.options.trace !== undefined }; 99 | connection.postMessage(message); 100 | connection.workerDone().then(async () => { 101 | await this.cleanUpWorkers(); 102 | await this.cleanupFileDescriptors(); 103 | this.resolveRunPromise(0); 104 | 105 | }).catch((error) => { RAL().console.error(error); }); 106 | return Promise.resolve(); 107 | } 108 | 109 | protected async startThread(wasiService: WasiService, tid: u32, start_arg: ptr): Promise { 110 | if (this.mainWorker === undefined) { 111 | throw new Error('Main worker not started'); 112 | } 113 | if (!this.importsMemory || this.memory === undefined) { 114 | throw new Error('Multi threaded applications need to import shared memory.'); 115 | } 116 | const filename = Uri.joinPath(this.baseUri, './dist/web/threadWorker.js').toString(); 117 | const response = await fetch(filename.toString()); 118 | const code = new Blob([await response.text()], { type: "application/javascript" }); 119 | const worker = new Worker(URL.createObjectURL(code)); 120 | // const worker = new Worker(filename); 121 | const connection = new BrowserServiceConnection(wasiService, worker, this.options.trace); 122 | await connection.workerReady(); 123 | const message: StartThreadMessage = { method: 'startThread', module: await this.module, memory: this.memory!, tid, start_arg, trace: this.options.trace !== undefined }; 124 | connection.postMessage(message); 125 | this.threadWorkers.set(tid, worker); 126 | return Promise.resolve(); 127 | } 128 | 129 | private async cleanUpWorkers(): Promise { 130 | for (const worker of this.threadWorkers.values()) { 131 | await worker.terminate(); 132 | } 133 | this.threadWorkers.clear(); 134 | } 135 | 136 | protected async threadEnded(tid: u32): Promise { 137 | const worker = this.threadWorkers.get(tid); 138 | if (worker !== undefined) { 139 | this.threadWorkers.delete(tid); 140 | worker.terminate(); 141 | } 142 | } 143 | 144 | private doesImportMemory(module: WebAssembly.Module): boolean { 145 | const imports = WebAssembly.Module.imports(module); 146 | for (const item of imports) { 147 | if (item.kind === 'memory' && item.name === 'memory') { 148 | return true; 149 | } 150 | } 151 | return false; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/ril.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | import type { Disposable } from 'vscode'; 6 | 7 | import RAL from '../common/ral'; 8 | import * as path from './path'; 9 | 10 | interface RIL extends RAL { 11 | } 12 | 13 | // In Browser environments we can only encode / decode utf-8 14 | const encoder: RAL.TextEncoder = new TextEncoder(); 15 | const decoder: RAL.TextDecoder = new TextDecoder(); 16 | 17 | const _ril: RIL = Object.freeze({ 18 | TextEncoder: Object.freeze({ 19 | create(_encoding: string = 'utf-8'): RAL.TextEncoder { 20 | return encoder; 21 | } 22 | }), 23 | TextDecoder: Object.freeze({ 24 | create(_encoding: string = 'utf-8'): RAL.TextDecoder { 25 | return { 26 | decode(input?: Uint8Array): string { 27 | if (input === undefined) { 28 | return decoder.decode(input); 29 | } else { 30 | if (input.buffer instanceof SharedArrayBuffer) { 31 | return decoder.decode(input.slice(0)); 32 | } else { 33 | return decoder.decode(input); 34 | } 35 | } 36 | } 37 | }; 38 | } 39 | }), 40 | console: console, 41 | timer: Object.freeze({ 42 | setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable { 43 | const handle = setTimeout(callback, ms, ...args); 44 | return { dispose: () => clearTimeout(handle) }; 45 | }, 46 | setImmediate(callback: (...args: any[]) => void, ...args: any[]): Disposable { 47 | const handle = setTimeout(callback, 0, ...args); 48 | return { dispose: () => clearTimeout(handle) }; 49 | }, 50 | setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): Disposable { 51 | const handle = setInterval(callback, ms, ...args); 52 | return { dispose: () => clearInterval(handle) }; 53 | }, 54 | }), 55 | clock: Object.freeze({ 56 | realtime(): bigint { 57 | // Date.now is in ms but clock API is in ns. 58 | return BigInt(Date.now()) * 1000000n; 59 | }, 60 | monotonic(): bigint { 61 | // digits are ms, decimal places are fractions of ms. 62 | const now = self.performance.timeOrigin + self.performance.now(); 63 | const ms = Math.trunc(now); 64 | const msf = now - ms; 65 | // We need to convert everything into nanoseconds 66 | return BigInt(ms) * 1000000n + BigInt(Math.round(msf * 1000000)); 67 | }, 68 | }), 69 | crypto: Object.freeze({ 70 | randomGet(size: number): Uint8Array { 71 | const result = new Uint8Array(size); 72 | self.crypto.getRandomValues(result); 73 | return result; 74 | } 75 | }), 76 | path: path 77 | }); 78 | 79 | 80 | function RIL(): RIL { 81 | return _ril; 82 | } 83 | 84 | namespace RIL { 85 | export function install(): void { 86 | if (!RAL.isInstalled()) { 87 | RAL.install(_ril); 88 | } 89 | } 90 | } 91 | 92 | if (!RAL.isInstalled()) { 93 | RAL.install(_ril); 94 | } 95 | export default RIL; -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/threadWorker.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import RIL from './ril'; 6 | RIL.install(); 7 | 8 | import { TraceWasiHost, Tracer, WasiHost} from '../common/host'; 9 | import { BrowserHostConnection } from './connection'; 10 | import { ServiceMessage, StartThreadMessage, WorkerReadyMessage } from '../common/connection'; 11 | import { CapturedPromise } from '../common/promises'; 12 | 13 | class ThreadBrowserHostConnection extends BrowserHostConnection { 14 | 15 | private _done: CapturedPromise; 16 | 17 | constructor(port: MessagePort | Worker | DedicatedWorkerGlobalScope) { 18 | super(port); 19 | this._done = CapturedPromise.create(); 20 | } 21 | 22 | public done(): Promise { 23 | return this._done.promise; 24 | } 25 | 26 | protected async handleMessage(message: ServiceMessage): Promise { 27 | if (StartThreadMessage.is(message)) { 28 | const module = message.module; 29 | const memory = message.memory; 30 | let host = WasiHost.create(this); 31 | let tracer: Tracer | undefined; 32 | if (message.trace) { 33 | tracer = TraceWasiHost.create(this, host); 34 | host = tracer.tracer; 35 | } 36 | const instance = await WebAssembly.instantiate(module, { 37 | env: { memory: memory }, 38 | wasi_snapshot_preview1: host, 39 | wasi: host 40 | }); 41 | host.initialize(memory ?? instance); 42 | (instance.exports.wasi_thread_start as Function)(message.tid, message.start_arg); 43 | host.thread_exit(message.tid); 44 | if (tracer !== undefined) { 45 | tracer.printSummary(); 46 | } 47 | this._done.resolve(); 48 | } 49 | } 50 | } 51 | 52 | async function main(port: MessagePort | Worker | DedicatedWorkerGlobalScope): Promise { 53 | const connection = new ThreadBrowserHostConnection(port); 54 | try { 55 | const ready: WorkerReadyMessage = { method: 'workerReady' }; 56 | connection.postMessage(ready); 57 | await connection.done(); 58 | } finally { 59 | connection.postMessage({ method: 'workerDone' }); 60 | connection.destroy(); 61 | } 62 | } 63 | 64 | main(self).catch(RIL().console.error).finally(() => close()); -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "vscode" 5 | ], 6 | "module": "Node16", 7 | "moduleResolution": "Node16", 8 | "target": "es2020", 9 | "lib": [ 10 | "webworker", 11 | "es2020" 12 | ], 13 | "rootDir": ".", 14 | "strict": true, 15 | "noImplicitAny": true, 16 | "noImplicitReturns": true, 17 | "noImplicitThis": true, 18 | "declaration": true, 19 | "stripInternal": true, 20 | "sourceMap": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "outDir": "../../lib/web", 24 | "tsBuildInfoFile": "../../lib/web/compile.tsbuildInfo", 25 | "incremental": true, 26 | "composite": true 27 | }, 28 | "include": [ 29 | "." 30 | ], 31 | "exclude": [ 32 | "test" 33 | ], 34 | "references": [ 35 | { 36 | "path": "../common/tsconfig.json" 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/tsconfig.publish.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "vscode" 5 | ], 6 | "module": "Node16", 7 | "moduleResolution": "Node16", 8 | "target": "es2020", 9 | "lib": [ 10 | "webworker", 11 | "es2020" 12 | ], 13 | "rootDir": ".", 14 | "strict": true, 15 | "noImplicitAny": true, 16 | "noImplicitReturns": true, 17 | "noImplicitThis": true, 18 | "declaration": true, 19 | "stripInternal": true, 20 | "sourceMap": false, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "outDir": "../../lib/web", 24 | "tsBuildInfoFile": "../../lib/web/publish.tsbuildInfo", 25 | "incremental": true, 26 | "composite": true 27 | }, 28 | "include": [ 29 | "." 30 | ], 31 | "exclude": [ 32 | "test" 33 | ], 34 | "references": [ 35 | { 36 | "path": "../common/tsconfig.publish.json" 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/src/web/tsconfig.watch.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "vscode" 5 | ], 6 | "module": "Node16", 7 | "moduleResolution": "Node16", 8 | "target": "es2020", 9 | "lib": [ 10 | "webworker", 11 | "es2020" 12 | ], 13 | "rootDir": ".", 14 | "strict": true, 15 | "noImplicitAny": true, 16 | "noImplicitReturns": true, 17 | "noImplicitThis": true, 18 | "declaration": true, 19 | "stripInternal": true, 20 | "sourceMap": true, 21 | "noUnusedLocals": false, 22 | "noUnusedParameters": false, 23 | "assumeChangesOnlyAffectDirectDependencies": true, 24 | "outDir": "../../lib/web", 25 | "tsBuildInfoFile": "../../lib/web/watch.tsbuildInfo", 26 | "incremental": true, 27 | "composite": true 28 | }, 29 | "include": [ 30 | "." 31 | ], 32 | "exclude": [ 33 | "test" 34 | ], 35 | "references": [ 36 | { 37 | "path": "../common/tsconfig.watch.json" 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "composite": true 5 | }, 6 | "files": [], 7 | "references": [ 8 | { 9 | "path": "./src/common/tsconfig.json" 10 | }, 11 | { 12 | "path": "./src/common/test/tsconfig.json" 13 | }, 14 | { 15 | "path": "./src/web/tsconfig.json" 16 | }, 17 | { 18 | "path": "./src/web/test/tsconfig.json" 19 | }, 20 | { 21 | "path": "./src/desktop/tsconfig.json" 22 | }, 23 | { 24 | "path": "./src/desktop/test/tsconfig.json" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/tsconfig.publish.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "composite": true 5 | }, 6 | "files": [], 7 | "references": [ 8 | { 9 | "path": "./src/common/tsconfig.publish.json" 10 | }, 11 | { 12 | "path": "./src/common/test/tsconfig.publish.json" 13 | }, 14 | { 15 | "path": "./src/web/tsconfig.publish.json" 16 | }, 17 | { 18 | "path": "./src/web/test/tsconfig.publish.json" 19 | }, 20 | { 21 | "path": "./src/desktop/tsconfig.publish.json" 22 | }, 23 | { 24 | "path": "./src/desktop/test/tsconfig.publish.json" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/tsconfig.watch.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "composite": true 5 | }, 6 | "files": [], 7 | "references": [ 8 | { 9 | "path": "./src/common/tsconfig.watch.json" 10 | }, 11 | { 12 | "path": "./src/common/test/tsconfig.watch.json" 13 | }, 14 | { 15 | "path": "./src/web/tsconfig.watch.json" 16 | }, 17 | { 18 | "path": "./src/web/test/tsconfig.watch.json" 19 | }, 20 | { 21 | "path": "./src/desktop/tsconfig.watch.json" 22 | }, 23 | { 24 | "path": "./src/desktop/test/tsconfig.watch.json" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/typings/webAssemblyCommon.d.ts: -------------------------------------------------------------------------------- 1 | /*! ***************************************************************************** 2 | Copyright (c) Microsoft Corporation. All rights reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | MERCHANTABLITY OR NON-INFRINGEMENT. 11 | 12 | See the Apache Version 2.0 License for specific language governing permissions 13 | and limitations under the License. 14 | ***************************************************************************** */ 15 | 16 | declare namespace WebAssembly { 17 | 18 | interface CompileError extends Error { 19 | } 20 | 21 | var CompileError: { 22 | prototype: CompileError; 23 | new(message?: string): CompileError; 24 | (message?: string): CompileError; 25 | }; 26 | 27 | interface LinkError extends Error { 28 | } 29 | 30 | var LinkError: { 31 | prototype: LinkError; 32 | new(message?: string): LinkError; 33 | (message?: string): LinkError; 34 | }; 35 | 36 | interface MemoryDescriptor { 37 | initial: number; 38 | maximum?: number; 39 | shared?: boolean; 40 | } 41 | 42 | interface Memory { 43 | readonly buffer: ArrayBuffer; 44 | grow(delta: number): number; 45 | } 46 | 47 | var Memory: { 48 | prototype: Memory; 49 | new(descriptor: MemoryDescriptor): Memory; 50 | }; 51 | 52 | interface Module { 53 | } 54 | 55 | interface RuntimeError extends Error { 56 | } 57 | 58 | var RuntimeError: { 59 | prototype: RuntimeError; 60 | new(message?: string): RuntimeError; 61 | (message?: string): RuntimeError; 62 | }; 63 | } -------------------------------------------------------------------------------- /src/vendor/wasm-wasi-core/typings/webAssemblyNode.d.ts: -------------------------------------------------------------------------------- 1 | /*! ***************************************************************************** 2 | Copyright (c) Microsoft Corporation. All rights reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | MERCHANTABLITY OR NON-INFRINGEMENT. 11 | 12 | See the Apache Version 2.0 License for specific language governing permissions 13 | and limitations under the License. 14 | ***************************************************************************** */ 15 | /// 16 | 17 | type BufferSource = ArrayBufferView | ArrayBuffer; 18 | declare namespace WebAssembly { 19 | 20 | type ImportExportKind = 'function' | 'global' | 'memory' | 'table'; 21 | type TableKind = 'anyfunc' | 'externref'; 22 | type ValueType = 'anyfunc' | 'externref' | 'f32' | 'f64' | 'i32' | 'i64' | 'v128'; 23 | type ExportValue = Function | Global | Memory | Table; 24 | type Exports = Record; 25 | type ImportValue = ExportValue | number; 26 | type Imports = Record; 27 | type ModuleImports = Record; 28 | 29 | interface GlobalDescriptor { 30 | mutable?: boolean; 31 | value: ValueType; 32 | } 33 | 34 | interface ModuleExportDescriptor { 35 | kind: ImportExportKind; 36 | name: string; 37 | } 38 | 39 | interface ModuleImportDescriptor { 40 | kind: ImportExportKind; 41 | module: string; 42 | name: string; 43 | } 44 | 45 | interface TableDescriptor { 46 | element: TableKind; 47 | initial: number; 48 | maximum?: number; 49 | } 50 | 51 | interface Table { 52 | readonly length: number; 53 | get(index: number): any; 54 | grow(delta: number, value?: any): number; 55 | set(index: number, value?: any): void; 56 | } 57 | 58 | var Table: { 59 | prototype: Table; 60 | new(descriptor: TableDescriptor, value?: any): Table; 61 | }; 62 | 63 | interface Global { 64 | value: any; 65 | valueOf(): any; 66 | } 67 | 68 | var Global: { 69 | prototype: Global; 70 | new(descriptor: GlobalDescriptor, v?: any): Global; 71 | }; 72 | 73 | interface Instance { 74 | readonly exports: Exports; 75 | } 76 | 77 | var Instance: { 78 | prototype: Instance; 79 | new(module: Module, importObject?: Imports): Instance; 80 | }; 81 | 82 | var Module: { 83 | prototype: Module; 84 | new(bytes: BufferSource): Module; 85 | customSections(moduleObject: Module, sectionName: string): ArrayBuffer[]; 86 | exports(moduleObject: Module): ModuleExportDescriptor[]; 87 | imports(moduleObject: Module): ModuleImportDescriptor[]; 88 | }; 89 | 90 | interface WebAssemblyInstantiatedSource { 91 | instance: Instance; 92 | module: Module; 93 | } 94 | 95 | function compile(bytes: BufferSource): Promise; 96 | function instantiate(bytes: BufferSource, importObject?: Imports): Promise; 97 | function instantiate(moduleObject: Module, importObject?: Imports): Promise; 98 | function validate(bytes: BufferSource): boolean; 99 | } -------------------------------------------------------------------------------- /src/web/extension.d.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionContext } from 'vscode'; 2 | export declare function activate(context: ExtensionContext): Promise; 3 | export declare function deactivate(): void; 4 | -------------------------------------------------------------------------------- /src/web/extension.ts: -------------------------------------------------------------------------------- 1 | import RIL from './../vendor/wasm-wasi-core/src/web/ril'; 2 | RIL.install(); 3 | 4 | import { Wasm, WasmProcess, WasiCoreImpl, ProcessOptions, WorkspaceFolderDescriptor, MemoryFileSystem, MemoryFileSystemDescriptor, MountPointDescriptor } from './../vendor/wasm-wasi-core/src/common/api'; 5 | import { BrowserWasiProcess } from './../vendor/wasm-wasi-core/src/web/process'; 6 | import { commands, ExtensionContext, Uri, window, workspace, WorkspaceFolder } from 'vscode'; 7 | import { createStack } from './net/stack'; 8 | 9 | export async function activate(context: ExtensionContext) { 10 | commands.registerCommand('container-wasm.run', async () => { 11 | const networkingMode = workspace.getConfiguration('container').networkingMode; 12 | let stackWorker: any = null; 13 | let net: any = null; 14 | let containerImage = workspace.getConfiguration('container').containerImage; 15 | let imageLocation = workspace.getConfiguration('container').imageLocation; 16 | let imageWithDecompression = workspace.getConfiguration('container').imageWithDecompression; 17 | let imageChunks = workspace.getConfiguration('container').imageChunks; 18 | let helperImageLocation = workspace.getConfiguration('container').helperImageLocation; 19 | let helperImageWithDecompression = workspace.getConfiguration('container').helperImageWithDecompression; 20 | if (networkingMode == "fetch") { 21 | const response = await fetch(Uri.joinPath(context.extensionUri, "dist/web/stack-worker.js").toString()); 22 | const code = new Blob([await response.text()], { type: "application/javascript" }); 23 | stackWorker = new Worker(URL.createObjectURL(code)); 24 | if (containerImage != "") { 25 | if (imageLocation == "") { 26 | imageLocation = "https://ktock.github.io/container2wasm-demo/extras/base.wasm.gzip"; 27 | imageWithDecompression = true; 28 | imageChunks = 0; 29 | } 30 | if (helperImageLocation == "") { 31 | helperImageLocation = "https://ktock.github.io/container2wasm-demo/extras/imagemounter.wasm.gzip"; 32 | helperImageWithDecompression = true; 33 | } 34 | } else { 35 | if (helperImageLocation == "") { 36 | helperImageLocation = "https://ktock.github.io/container2wasm-demo/src/c2w-net-proxy.wasm"; 37 | } 38 | } 39 | net = createStack(stackWorker, helperImageLocation, helperImageWithDecompression, containerImage); 40 | } 41 | let bits: ArrayBuffer; 42 | try { 43 | const url = Uri.parse(imageLocation, true); 44 | if (!(url.scheme === "http" || url.scheme === "https")) { 45 | throw new Error("unrecognized url"); 46 | } 47 | if (imageChunks > 0) { 48 | let format = (s: string) => imageLocation + s + '.wasm'; 49 | let files = []; 50 | for (let i = 0; i < imageChunks; i++) { 51 | let s = i.toString(); 52 | while (s.length < 2) s = "0" + s; 53 | files[i] = s; 54 | } 55 | files = files.map(format); 56 | let list: Promise[] = []; 57 | files.forEach(file => list.push(fetch(file))); 58 | 59 | const resps = await Promise.all(list) 60 | let results: Promise[] = []; 61 | resps.forEach(r => results.push(r['arrayBuffer']())); 62 | const ab = await Promise.all(results) 63 | const blob = new Blob(ab); 64 | if (imageWithDecompression) { 65 | const ds = new DecompressionStream("gzip") 66 | bits = await new Response(blob.stream().pipeThrough(ds))['arrayBuffer'](); 67 | } else { 68 | bits = await blob.arrayBuffer(); 69 | } 70 | } else { 71 | const resp = await fetch(imageLocation); 72 | if (imageWithDecompression) { 73 | let wasmP = resp['blob']().then((blob) => { 74 | const ds = new DecompressionStream("gzip") 75 | return new Response(blob.stream().pipeThrough(ds))['arrayBuffer'](); 76 | }); 77 | bits = await wasmP; 78 | } else { 79 | bits = await resp['arrayBuffer'](); 80 | } 81 | } 82 | } catch (_) { 83 | const url = Uri.joinPath(context.extensionUri, imageLocation); 84 | try { 85 | bits = await workspace.fs.readFile(url); 86 | } catch (error : any) { 87 | // Show an error message if something goes wrong. 88 | await window.showErrorMessage(error.message); 89 | return; 90 | } 91 | } 92 | 93 | // Load the WASM API 94 | const wasm: Wasm = await wasiCoreExt_activate(context) 95 | 96 | // Create a pseudoterminal to provide stdio to the WASM process. 97 | const pty = wasm.createPseudoterminal(); 98 | const terminal = window.createTerminal({ 99 | name: 'Run Wasm', 100 | pty, 101 | isTransient: true 102 | }); 103 | terminal.show(true); 104 | 105 | try { 106 | const module = await WebAssembly.compile(bits); 107 | 108 | let workspaceMountpoint = workspace.getConfiguration('container').workspaceMountpoint; 109 | let mountDescs: MountPointDescriptor[] = []; 110 | if (workspaceMountpoint != "") { 111 | workspaceMountpoint = workspaceMountpoint.replace(/\/+$/, ""); // trailing slash unsupported by wasm-wasi 112 | mountDescs = workspaceFolderDescriptorWithMountPoint(workspaceMountpoint); 113 | } 114 | let opts: ProcessOptions = { 115 | stdio: pty.stdio, 116 | mountPoints: mountDescs, 117 | } 118 | 119 | if (net != null) { 120 | // fill fetch-based networking options 121 | const certFs: MemoryFileSystem = await wasm.createMemoryFileSystem(); 122 | const certD: Uint8Array = await net.wait_cert(); 123 | certFs.createFile("proxy.crt", certD); 124 | const mfd: MemoryFileSystemDescriptor = { 125 | kind: 'memoryFileSystem', 126 | fileSystem: certFs, 127 | mountPoint: "/.wasmenv" 128 | } 129 | opts.mountPoints.push(mfd); 130 | const mac = "02:XX:XX:XX:XX:XX".replace(/X/g, function() { 131 | return "0123456789ABCDEF".charAt(Math.floor(Math.random() * 16)) 132 | }); 133 | opts.args = ['--net=socket', '--mac', mac]; 134 | if (containerImage != "") { 135 | opts.args = opts.args.concat(['--external-bundle=9p=192.168.127.252']); 136 | } 137 | opts.env = { 138 | "SSL_CERT_FILE": "/.wasmenv/proxy.crt", 139 | "https_proxy": "http://192.168.127.253:80", 140 | "http_proxy": "http://192.168.127.253:80", 141 | "HTTPS_PROXY": "http://192.168.127.253:80", 142 | "HTTP_PROXY": "http://192.168.127.253:80" 143 | }; 144 | opts.net = net; 145 | } 146 | 147 | // Create a WASM process. 148 | const process = await wasm.createProcess('wasm', module, opts); 149 | 150 | const id = addProcess(wasm, stackWorker, process); 151 | const result = await process.run(); 152 | deleteProcess(id); 153 | 154 | if (result !== 0) { 155 | await window.showErrorMessage(`Process ended with error: ${result}`); 156 | } 157 | } catch (error : any) { 158 | // Show an error message if something goes wrong. 159 | await window.showErrorMessage(error.message); 160 | } 161 | }); 162 | } 163 | 164 | // This method is called when your extension is deactivated 165 | export function deactivate() { 166 | processes = {}; 167 | } 168 | 169 | async function wasiCoreExt_activate(context: ExtensionContext) { 170 | return WasiCoreImpl.create(context, BrowserWasiProcess, async (source) => { 171 | return WebAssembly.compileStreaming(fetch(source.toString())); 172 | }); 173 | } 174 | 175 | let processes = {}; 176 | var curID = 0; 177 | var maxID = 0x7FFFFFFF; 178 | function getID() { 179 | var startID = curID; 180 | while (true) { 181 | if (processes[curID] == undefined) { 182 | return curID; 183 | } 184 | if (curID >= maxID) { 185 | curID = 0; 186 | } else { 187 | curID++; 188 | } 189 | if (curID == startID) { 190 | return -1; // exhausted 191 | } 192 | } 193 | return curID; 194 | } 195 | 196 | function addProcess(wasm: Wasm, stackWorker: Worker, process: WasmProcess) { 197 | const id: number = getID(); 198 | processes[id] = {wasm, stackWorker, process}; 199 | return id; 200 | } 201 | 202 | function deleteProcess(id: number) { 203 | delete processes[id] 204 | } 205 | 206 | function workspaceFolderDescriptorWithMountPoint(mountpoint: string) { 207 | let descs: MountPointDescriptor[] = []; 208 | const folders = workspace.workspaceFolders; 209 | if (folders !== undefined) { 210 | if (folders.length === 1) { 211 | descs.push(createWorkspaceFolderDescriptor(folders[0], mountpoint, true)); 212 | } else { 213 | for (const folder of folders) { 214 | descs.push(createWorkspaceFolderDescriptor(folder, mountpoint, false)); 215 | } 216 | } 217 | } 218 | return descs; 219 | } 220 | 221 | function createWorkspaceFolderDescriptor(folder: WorkspaceFolder, mountpoint: string, single: boolean): MountPointDescriptor { 222 | const p: string = single ? mountpoint : mountpoint + "/" + folder.name; 223 | return { kind: 'vscodeFileSystem', uri: folder.uri, mountPoint: p}; 224 | } 225 | -------------------------------------------------------------------------------- /src/web/net/wasi-util.js: -------------------------------------------------------------------------------- 1 | import * as wasitype from "@bjorn3/browser_wasi_shim"; 2 | 3 | //////////////////////////////////////////////////////////// 4 | // 5 | // event-related classes adopted from the on-going discussion 6 | // towards poll_oneoff support in browser_wasi_sim project. 7 | // Ref: https://github.com/bjorn3/browser_wasi_shim/issues/14#issuecomment-1450351935 8 | // 9 | //////////////////////////////////////////////////////////// 10 | 11 | export class EventType { 12 | /*:: variant: "clock" | "fd_read" | "fd_write"*/ 13 | 14 | constructor(variant/*: "clock" | "fd_read" | "fd_write"*/) { 15 | this.variant = variant; 16 | } 17 | 18 | static from_u8(data/*: number*/)/*: EventType*/ { 19 | switch (data) { 20 | case wasitype.wasi.EVENTTYPE_CLOCK: 21 | return new EventType("clock"); 22 | case wasitype.wasi.EVENTTYPE_FD_READ: 23 | return new EventType("fd_read"); 24 | case wasitype.wasi.EVENTTYPE_FD_WRITE: 25 | return new EventType("fd_write"); 26 | default: 27 | throw "Invalid event type " + String(data); 28 | } 29 | } 30 | 31 | to_u8()/*: number*/ { 32 | switch (this.variant) { 33 | case "clock": 34 | return wasitype.wasi.EVENTTYPE_CLOCK; 35 | case "fd_read": 36 | return wasitype.wasi.EVENTTYPE_FD_READ; 37 | case "fd_write": 38 | return wasitype.wasi.EVENTTYPE_FD_WRITE; 39 | default: 40 | throw "unreachable"; 41 | } 42 | } 43 | } 44 | 45 | export class Event { 46 | /*:: userdata: UserData*/ 47 | /*:: error: number*/ 48 | /*:: type: EventType*/ 49 | /*:: fd_readwrite: EventFdReadWrite | null*/ 50 | 51 | write_bytes(view/*: DataView*/, ptr/*: number*/) { 52 | view.setBigUint64(ptr, this.userdata, true); 53 | view.setUint8(ptr + 8, this.error); 54 | view.setUint8(ptr + 9, 0); 55 | view.setUint8(ptr + 10, this.type.to_u8()); 56 | // if (this.fd_readwrite) { 57 | // this.fd_readwrite.write_bytes(view, ptr + 16); 58 | // } 59 | } 60 | 61 | static write_bytes_array(view/*: DataView*/, ptr/*: number*/, events/*: Array*/) { 62 | for (let i = 0; i < events.length; i++) { 63 | events[i].write_bytes(view, ptr + 32 * i); 64 | } 65 | } 66 | } 67 | 68 | export class SubscriptionClock { 69 | /*:: timeout: number*/ 70 | 71 | static read_bytes(view/*: DataView*/, ptr/*: number*/)/*: SubscriptionFdReadWrite*/ { 72 | let self = new SubscriptionClock(); 73 | self.timeout = Number(view.getBigUint64(ptr + 8, true)); 74 | return self; 75 | } 76 | } 77 | 78 | export class SubscriptionFdReadWrite { 79 | /*:: fd: number*/ 80 | 81 | static read_bytes(view/*: DataView*/, ptr/*: number*/)/*: SubscriptionFdReadWrite*/ { 82 | let self = new SubscriptionFdReadWrite(); 83 | self.fd = view.getUint32(ptr, true); 84 | return self; 85 | } 86 | } 87 | 88 | export class SubscriptionU { 89 | /*:: tag: EventType */ 90 | /*:: data: SubscriptionClock | SubscriptionFdReadWrite */ 91 | 92 | static read_bytes(view/*: DataView*/, ptr/*: number*/)/*: SubscriptionU*/ { 93 | let self = new SubscriptionU(); 94 | self.tag = EventType.from_u8(view.getUint8(ptr)); 95 | switch (self.tag.variant) { 96 | case "clock": 97 | self.data = SubscriptionClock.read_bytes(view, ptr + 8); 98 | break; 99 | case "fd_read": 100 | case "fd_write": 101 | self.data = SubscriptionFdReadWrite.read_bytes(view, ptr + 8); 102 | break; 103 | default: 104 | throw "unreachable"; 105 | } 106 | return self; 107 | } 108 | } 109 | 110 | export class Subscription { 111 | /*:: userdata: UserData */ 112 | /*:: u: SubscriptionU */ 113 | 114 | static read_bytes(view/*: DataView*/, ptr/*: number*/)/*: Subscription*/ { 115 | let subscription = new Subscription(); 116 | subscription.userdata = view.getBigUint64(ptr, true); 117 | subscription.u = SubscriptionU.read_bytes(view, ptr + 8); 118 | return subscription; 119 | } 120 | 121 | static read_bytes_array(view/*: DataView*/, ptr/*: number*/, len/*: number*/)/*: Array*/ { 122 | let subscriptions = []; 123 | for (let i = 0; i < len; i++) { 124 | subscriptions.push(Subscription.read_bytes(view, ptr + 48 * i)); 125 | } 126 | return subscriptions; 127 | } 128 | } 129 | 130 | export function wasiHackSocket(wasi, listenfd, connfd, sockAccept, sockSend, sockRecv) { 131 | // definition from wasi-libc https://github.com/WebAssembly/wasi-libc/blob/wasi-sdk-19/expected/wasm32-wasi/predefined-macros.txt 132 | const ERRNO_INVAL = 28; 133 | const ERRNO_AGAIN= 6; 134 | var connfdUsed = false; 135 | var connbuf = new Uint8Array(0); 136 | var _fd_close = wasi.wasiImport.fd_close; 137 | wasi.wasiImport.fd_close = (fd) => { 138 | if (fd == connfd) { 139 | connfdUsed = false; 140 | return 0; 141 | } 142 | return _fd_close.apply(wasi.wasiImport, [fd]); 143 | } 144 | var _fd_read = wasi.wasiImport.fd_read; 145 | wasi.wasiImport.fd_read = (fd, iovs_ptr, iovs_len, nread_ptr) => { 146 | if (fd == connfd) { 147 | return wasi.wasiImport.sock_recv(fd, iovs_ptr, iovs_len, 0, nread_ptr, 0); 148 | } 149 | return _fd_read.apply(wasi.wasiImport, [fd, iovs_ptr, iovs_len, nread_ptr]); 150 | } 151 | var _fd_write = wasi.wasiImport.fd_write; 152 | wasi.wasiImport.fd_write = (fd, iovs_ptr, iovs_len, nwritten_ptr) => { 153 | if (fd == connfd) { 154 | return wasi.wasiImport.sock_send(fd, iovs_ptr, iovs_len, 0, nwritten_ptr); 155 | } 156 | return _fd_write.apply(wasi.wasiImport, [fd, iovs_ptr, iovs_len, nwritten_ptr]); 157 | } 158 | var _fd_fdstat_get = wasi.wasiImport.fd_fdstat_get; 159 | wasi.wasiImport.fd_fdstat_get = (fd, fdstat_ptr) => { 160 | if ((fd == listenfd) || (fd == connfd) && connfdUsed){ 161 | let buffer = new DataView(wasi.inst.exports.memory.buffer); 162 | // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fdstat-struct 163 | buffer.setUint8(fdstat_ptr, 6); // filetype = 6 (socket_stream) 164 | buffer.setUint8(fdstat_ptr + 1, 2); // fdflags = 2 (nonblock) 165 | return 0; 166 | } 167 | return _fd_fdstat_get.apply(wasi.wasiImport, [fd, fdstat_ptr]); 168 | } 169 | wasi.wasiImport.sock_accept = (fd, flags, fd_ptr) => { 170 | if (fd != listenfd) { 171 | console.log("sock_accept: unknown fd " + fd); 172 | return ERRNO_INVAL; 173 | } 174 | if (connfdUsed) { 175 | console.log("sock_accept: multi-connection is unsupported"); 176 | return ERRNO_INVAL; 177 | } 178 | if (!sockAccept()) { 179 | return ERRNO_AGAIN; 180 | } 181 | connfdUsed = true; 182 | var buffer = new DataView(wasi.inst.exports.memory.buffer); 183 | buffer.setUint32(fd_ptr, connfd, true); 184 | return 0; 185 | } 186 | wasi.wasiImport.sock_send = (fd, iovs_ptr, iovs_len, si_flags/*not defined*/, nwritten_ptr) => { 187 | if (fd != connfd) { 188 | console.log("sock_send: unknown fd " + fd); 189 | return ERRNO_INVAL; 190 | } 191 | var buffer = new DataView(wasi.inst.exports.memory.buffer); 192 | var buffer8 = new Uint8Array(wasi.inst.exports.memory.buffer); 193 | var iovecs = wasitype.wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len); 194 | var wtotal = 0 195 | for (var i = 0; i < iovecs.length; i++) { 196 | var iovec = iovecs[i]; 197 | if (iovec.buf_len == 0) { 198 | continue; 199 | } 200 | var ret = sockSend(buffer8.subarray(iovec.buf, iovec.buf + iovec.buf_len)); 201 | if (ret < 0) { 202 | return ERRNO_INVAL; 203 | } 204 | wtotal += iovec.buf_len; 205 | } 206 | buffer.setUint32(nwritten_ptr, wtotal, true); 207 | return 0; 208 | } 209 | wasi.wasiImport.sock_recv = (fd, iovs_ptr, iovs_len, ri_flags, nread_ptr, ro_flags_ptr) => { 210 | if (ri_flags != 0) { 211 | console.log("ri_flags are unsupported"); // TODO 212 | } 213 | if (fd != connfd) { 214 | console.log("sock_recv: unknown fd " + fd); 215 | return ERRNO_INVAL; 216 | } 217 | var buffer = new DataView(wasi.inst.exports.memory.buffer); 218 | var buffer8 = new Uint8Array(wasi.inst.exports.memory.buffer); 219 | var iovecs = wasitype.wasi.Iovec.read_bytes_array(buffer, iovs_ptr, iovs_len); 220 | var nread = 0; 221 | for (var i = 0; i < iovecs.length; i++) { 222 | var iovec = iovecs[i]; 223 | if (iovec.buf_len == 0) { 224 | continue; 225 | } 226 | var retlen = sockRecv(buffer8, iovec.buf, iovec.buf_len); 227 | if ((retlen <= 0) && (i == 0)) { 228 | return ERRNO_AGAIN; 229 | } 230 | nread += retlen; 231 | } 232 | buffer.setUint32(nread_ptr, nread, true); 233 | // TODO: support ro_flags_ptr 234 | return 0; 235 | } 236 | wasi.wasiImport.sock_shutdown = (fd, sdflags) => { 237 | if (fd == connfd) { 238 | connfdUsed = false; 239 | } 240 | return 0; 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/web/test/suite/extension.test.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /src/web/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Web Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/web/test/suite/index.d.ts: -------------------------------------------------------------------------------- 1 | export declare function run(): Promise; 2 | -------------------------------------------------------------------------------- /src/web/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | // Imports mocha for the browser, defining the `mocha` global. 2 | require('mocha/mocha'); 3 | 4 | export function run(): Promise { 5 | 6 | return new Promise((c, e) => { 7 | mocha.setup({ 8 | ui: 'tdd', 9 | reporter: undefined 10 | }); 11 | 12 | // Bundles all files in the current directory matching `*.test` 13 | const importAll = (r: __WebpackModuleApi.RequireContext) => r.keys().forEach(r); 14 | importAll(require.context('.', true, /\.test$/)); 15 | 16 | try { 17 | // Run the mocha test 18 | mocha.run(failures => { 19 | if (failures > 0) { 20 | e(new Error(`${failures} tests failed.`)); 21 | } else { 22 | c(); 23 | } 24 | }); 25 | } catch (err) { 26 | console.error(err); 27 | e(err); 28 | } 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "outDir": "dist", 6 | "lib": [ 7 | "ES2020", "WebWorker" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": false /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "include": [ 18 | "src" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) vscode-container-wasm authors. All rights reserved. 3 | * Licensed under the MIT License. 4 | * This has been forked from vscode-wasm project and patched for our use-case. 5 | * Please see also the following Copyright header and the "Acknowledgement" section in README. 6 | *--------------------------------------------------------------------------------------------*/ 7 | 8 | /*--------------------------------------------------------------------------------------------- 9 | * Copyright (c) Microsoft Corporation. All rights reserved. 10 | * Licensed under the MIT License. See License.txt in the project root for license information. 11 | *--------------------------------------------------------------------------------------------*/ 12 | 13 | //@ts-check 14 | 'use strict'; 15 | 16 | //@ts-check 17 | /** @typedef {import('webpack').Configuration} WebpackConfig **/ 18 | 19 | const path = require('path'); 20 | const webpack = require('webpack'); 21 | 22 | /** @type WebpackConfig */ 23 | const webExtensionConfig = { 24 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 25 | target: 'webworker', // extensions run in a webworker context 26 | entry: { 27 | 'extension': './src/web/extension.ts', 28 | 'test/suite/index': './src/web/test/suite/index.ts', 29 | 'stack-worker': './src/web/net/stack-worker.js', 30 | 'mainWorker': './src/vendor/wasm-wasi-core/src/web/mainWorker.ts', 31 | 'threadWorker': './src/vendor/wasm-wasi-core/src/web/threadWorker.ts', 32 | }, 33 | experiments: { 34 | asyncWebAssembly: true 35 | }, 36 | output: { 37 | filename: '[name].js', 38 | path: path.join(__dirname, './dist/web'), 39 | libraryTarget: 'commonjs', 40 | devtoolModuleFilenameTemplate: '../../[resource-path]' 41 | }, 42 | resolve: { 43 | mainFields: ['browser', 'module', 'main'], // look for `browser` entry point in imported node modules 44 | extensions: ['.ts', '.js'], // support ts-files and js-files 45 | alias: { 46 | // provides alternate implementation for node module and source files 47 | }, 48 | fallback: { 49 | // Webpack 5 no longer polyfills Node.js core modules automatically. 50 | // see https://webpack.js.org/configuration/resolve/#resolvefallback 51 | // for the list of Node.js core module polyfills. 52 | 'assert': require.resolve('assert') 53 | } 54 | }, 55 | module: { 56 | rules: [ 57 | { 58 | test: /\.ts$/, 59 | exclude: /node_modules/, 60 | use: [{ 61 | loader: 'ts-loader' 62 | }] 63 | }, 64 | { 65 | test: /\.wasm$/, 66 | type: "asset/inline" 67 | } 68 | ] 69 | }, 70 | plugins: [ 71 | new webpack.optimize.LimitChunkCountPlugin({ 72 | maxChunks: 1 // disable chunks by default since web extensions must be a single bundle 73 | }), 74 | new webpack.ProvidePlugin({ 75 | process: 'process/browser', // provide a shim for the global `process` variable 76 | }), 77 | ], 78 | externals: { 79 | 'vscode': 'commonjs vscode', // ignored because it doesn't exist 80 | }, 81 | performance: { 82 | hints: false 83 | }, 84 | devtool: 'nosources-source-map', // create a source map that points to the original source file 85 | infrastructureLogging: { 86 | level: "log", // enables logging required for problem matchers 87 | }, 88 | }; 89 | 90 | module.exports = [ webExtensionConfig ]; 91 | --------------------------------------------------------------------------------