diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36581c768..a16134547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,15 +63,21 @@ jobs: run: | rustup target add wasm32-unknown-unknown cargo check -p oxc_wasm --target wasm32-unknown-unknown - - name: Build types + + - name: Build run: | npx -y wasm-pack build --target web --dev ./crates/oxc_wasm + npx -y wasm-pack build --target web --dev ./wasm/parser + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 + - name: Check output types - run: npx -y -p typescript tsc --lib es2020,dom crates/oxc_wasm/pkg/oxc_wasm.d.ts + run: | + npx -y -p typescript tsc --lib es2020,dom crates/oxc_wasm/pkg/oxc_wasm.d.ts + typos: name: Spell Check runs-on: ubuntu-latest diff --git a/wasm/parser/Cargo.toml b/wasm/parser/Cargo.toml index efe4ae384..5d632884d 100644 --- a/wasm/parser/Cargo.toml +++ b/wasm/parser/Cargo.toml @@ -25,7 +25,7 @@ default = ["console_error_panic_hook"] [dependencies] oxc = { workspace = true, features = ["serde", "wasm"] } -serde = { workspace = true } +serde = { workspace = true, features = ["derive"] } wasm-bindgen = { workspace = true } serde-wasm-bindgen = { workspace = true } diff --git a/wasm/parser/README.md b/wasm/parser/README.md index 368248d2b..fdfdec730 100644 --- a/wasm/parser/README.md +++ b/wasm/parser/README.md @@ -7,7 +7,7 @@ Checkout [oxc-parser](https://www.npmjs.com/package/oxc-parser) for usage in nod Source code: https://github.com/oxc-project/oxc/tree/main/wasm/parser -## 🚴 Usage +## Usage ```js import initWasm, { parseSync } from "@oxc-parser/wasm"; @@ -16,9 +16,37 @@ async function main() { await initWasm(); const code = "let foo"; - const result = parseSync(code, { filename: "test.ts" }); + const result = parseSync(code, { sourceFilename: "test.ts" }); console.log(result); } main(); ``` + +## Notes + +### UTF8 vs UTF16 byte offsets + +The `span` value returned from the ASTs and diagnostics is in UTF8 byte offsets. Converting to UTF16 byte offsets: + +```js +let sourceTextUtf8 = new TextEncoder().encode(sourceText); + +const convertToUtf8 = (sourceTextUtf8, d) => { + return new TextDecoder().decode(sourceTextUtf8.slice(0, d)).length; +} + +const diagnostics = result.errors.map((d) => ({ + from: convertToUtf8(sourceTextUtf8, d.start), + to: convertToUtf8(sourceTextUtf8, d.end), + severity: d.severity.toLowerCase(), + message: d.message, +})); +``` + +### Vite + +`wasm-pack build --target web` is used for the wasm build. + +You may need something like https://github.com/nshen/vite-plugin-wasm-pack to get it working with vite, +otherwise vite will load the wasm file as a HTML file causing a `CompileError: WebAssembly.instantiate(): expected magic word` error. diff --git a/wasm/parser/src/lib.rs b/wasm/parser/src/lib.rs index 469d9f4f8..81834b71d 100644 --- a/wasm/parser/src/lib.rs +++ b/wasm/parser/src/lib.rs @@ -1,6 +1,6 @@ #![allow(clippy::needless_pass_by_value)] -use serde::Serialize; +use serde::{Deserialize, Serialize}; use tsify::Tsify; use wasm_bindgen::prelude::*; @@ -12,31 +12,33 @@ pub fn main() { console_error_panic_hook::set_once(); } -/// Babel Parser Options -/// -/// -#[wasm_bindgen(getter_with_clone)] -#[derive(Default, Tsify)] +#[derive(Debug, Default, Clone, Deserialize, Tsify)] +#[tsify(from_wasm_abi)] pub struct ParserOptions { - #[wasm_bindgen(js_name = sourceType)] + #[serde(rename = "sourceType")] + #[tsify(optional, type = "\"script\" | \"module\"")] pub source_type: Option, - #[wasm_bindgen] - pub filename: Option, + + /// "module" and "jsx" will be inferred from `sourceFilename`. + #[serde(rename = "sourceFilename")] + #[tsify(optional)] + pub source_filename: Option, } -#[wasm_bindgen(getter_with_clone)] #[derive(Default, Tsify)] +#[wasm_bindgen(getter_with_clone)] pub struct ParseResult { #[wasm_bindgen(readonly, skip_typescript)] #[tsify(type = "Program")] pub program: JsValue, + #[wasm_bindgen(readonly, skip_typescript)] - #[tsify(type = "OxcDiagnostic[]")] + #[tsify(type = "Diagnostic[]")] pub errors: Vec, } -#[derive(Default, Tsify, Serialize)] -pub struct OxcDiagnostic { +#[derive(Debug, Default, Serialize, Tsify)] +pub struct Diagnostic { pub start: usize, pub end: usize, pub severity: String, @@ -61,7 +63,7 @@ pub fn parse_sync( let allocator = Allocator::default(); let source_type = options - .filename + .source_filename .as_ref() .map(|name| SourceType::from_path(name).unwrap()) .unwrap_or_default(); @@ -87,7 +89,7 @@ pub fn parse_sync( let Some(labels) = error.labels() else { return vec![] }; labels .map(|label| { - OxcDiagnostic { + Diagnostic { start: label.offset(), end: label.offset() + label.len(), severity: format!("{:?}", error.severity().unwrap_or_default()), @@ -96,9 +98,9 @@ pub fn parse_sync( .serialize(&serializer) .unwrap() }) - .collect::>() + .collect::>() }) - .collect::>() + .collect::>() }; Ok(ParseResult { program, errors })