feat(wasm): add wasm to oxc (#130)

This commit is contained in:
Domon 2023-03-06 14:13:06 +08:00 committed by GitHub
parent 500f42b134
commit 24d327c40d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 346 additions and 11 deletions

119
Cargo.lock generated
View file

@ -100,6 +100,12 @@ version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -183,7 +189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff0805f79ecb1b35163f3957a6934ea8d04fcd36ef98b52e7316f63e72e73d1"
dependencies = [
"castaway",
"cfg-if",
"cfg-if 1.0.0",
"itoa",
"ryu",
"serde",
@ -203,6 +209,16 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen",
]
[[package]]
name = "convert_case"
version = "0.6.0"
@ -218,7 +234,7 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -261,7 +277,7 @@ version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"crossbeam-utils",
]
@ -271,7 +287,7 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"crossbeam-epoch",
"crossbeam-utils",
]
@ -283,7 +299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
dependencies = [
"autocfg",
"cfg-if",
"cfg-if 1.0.0",
"crossbeam-utils",
"memoffset",
"scopeguard",
@ -295,7 +311,7 @@ version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -316,7 +332,7 @@ version = "0.8.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -380,7 +396,7 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"libc",
"wasi",
]
@ -613,7 +629,7 @@ version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -631,6 +647,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "memory_units"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
[[package]]
name = "miette"
version = "5.5.0"
@ -905,6 +927,25 @@ dependencies = [
"oxc_ast",
]
[[package]]
name = "oxc_wasm"
version = "0.0.0"
dependencies = [
"console_error_panic_hook",
"miette",
"oxc_allocator",
"oxc_ast",
"oxc_diagnostics",
"oxc_linter",
"oxc_parser",
"oxc_semantic",
"serde",
"serde_json",
"wasm-bindgen",
"wasm-bindgen-test",
"wee_alloc",
]
[[package]]
name = "percent-encoding"
version = "2.2.0"
@ -1048,6 +1089,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -1239,7 +1286,7 @@ version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"once_cell",
]
@ -1385,7 +1432,9 @@ version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"serde",
"serde_json",
"wasm-bindgen-macro",
]
@ -1404,6 +1453,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.84"
@ -1433,6 +1494,30 @@ version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b"
dependencies = [
"console_error_panic_hook",
"js-sys",
"scoped-tls",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "web-sys"
version = "0.3.61"
@ -1462,6 +1547,18 @@ dependencies = [
"webpki",
]
[[package]]
name = "wee_alloc"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
dependencies = [
"cfg-if 0.1.10",
"libc",
"memory_units",
"winapi",
]
[[package]]
name = "winapi"
version = "0.3.9"

View file

@ -45,6 +45,28 @@ impl Linter {
Self { rules }
}
#[must_use]
pub fn from_json_str(s: &str) -> Self {
let rules = serde_json::from_str(s)
.ok()
.and_then(|v: serde_json::Value| v.get("rules").cloned())
.and_then(|v| v.as_object().cloned())
.map_or_else(
|| RULES.to_vec(),
|rules_config| {
RULES
.iter()
.map(|rule| {
let value = rules_config.get(rule.name());
rule.read_json(value.cloned())
})
.collect()
},
);
Self { rules }
}
#[must_use]
pub fn from_rules(rules: Vec<RuleEnum>) -> Self {
Self { rules }

6
crates/oxc_wasm/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
/target
**/*.rs.bk
Cargo.lock
bin/
pkg/
wasm-pack.log

View file

@ -0,0 +1,50 @@
[package]
name = "oxc_wasm"
authors.workspace = true
description.workspace = true
edition.workspace = true
homepage.workspace = true
keywords.workspace = true
license.workspace = true
repository.workspace = true
version.workspace = true
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
oxc_allocator = {path = "../oxc_allocator"}
oxc_ast = {path = "../oxc_ast"}
oxc_diagnostics = {path = "../oxc_diagnostics"}
oxc_linter = {path = "../oxc_linter"}
oxc_parser = {path = "../oxc_parser"}
oxc_semantic = {path = "../oxc_semantic"}
miette = {workspace = true, features = ["fancy-no-backtrace"]}
serde = {workspace = true, features = ["derive"]}
serde_json = {workspace = true}
wasm-bindgen = {version = "0.2", features = ["serde-serialize"]}
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = {version = "0.1.6", optional = true}
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
#
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
wee_alloc = {version = "0.4.5", optional = true}
[dev-dependencies]
wasm-bindgen-test = "0.3.13"
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"

38
crates/oxc_wasm/README.md Normal file
View file

@ -0,0 +1,38 @@
## About
Wasm package for oxc compiler.
## 🚴 Usage
```js
import oxc from 'oxc-wasm'
const ast = oxc.main(code, options)
```
### 🛠️ Build with `wasm-pack build`
```
wasm-pack build
```
### 🔬 Test in Headless Browsers with `wasm-pack test`
```
wasm-pack test --headless --firefox
```
### 🎁 Publish to NPM with `wasm-pack publish`
```
wasm-pack publish
```
## 🔋 Batteries Included
- [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
between WebAssembly and JavaScript.
- [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
for logging panic messages to the developer console.
- [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized
for small code size.

View file

@ -0,0 +1,62 @@
use std::{rc::Rc, sync::Arc};
use miette::NamedSource;
use oxc_allocator::Allocator;
use oxc_ast::SourceType;
use oxc_diagnostics::Diagnostics;
use oxc_linter::Linter;
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use wasm_bindgen::JsValue;
pub struct Driver {
allocator: Allocator,
}
impl Driver {
pub fn new() -> Self {
Self { allocator: Allocator::default() }
}
#[allow(deprecated)]
pub fn run(
&self,
path: &str,
source_text: &str,
source_type: SourceType,
eslintrc: &str,
) -> JsValue {
let ret = Parser::new(&self.allocator, source_text, source_type)
.allow_return_outside_function(true)
.parse();
let program = self.allocator.alloc(ret.program);
let diagnostics = Diagnostics::default();
let semantic = SemanticBuilder::new(source_type).build(program, Rc::new(ret.trivias));
let mut diagnostics = diagnostics.into_inner();
let source = Arc::new(NamedSource::new(path, source_text.to_string()));
diagnostics.extend(
Linter::from_json_str(eslintrc)
.run(&Rc::new(semantic), source_text, false)
.into_iter()
.map(|m| m.error.with_source_code(source.clone()))
.chain(ret.errors),
);
if diagnostics.is_empty() {
if let Ok(ast) = JsValue::from_serde(program) {
return ast;
}
}
let result = diagnostics
.into_iter()
.map(|error| format!("{error:?}"))
.collect::<Vec<String>>()
.join("\n");
JsValue::from_str(&result)
}
}

View file

@ -0,0 +1,50 @@
mod driver;
mod utils;
use driver::Driver;
use oxc_ast::SourceType;
use serde::{Deserialize, Serialize};
use utils::set_panic_hook;
use wasm_bindgen::prelude::*;
#[derive(Deserialize, Serialize, PartialEq, Eq)]
pub enum Language {
#[serde(rename = "javascript")]
JavaScript,
#[serde(rename = "typescript")]
TypeScript,
}
impl Default for Language {
fn default() -> Self {
Self::TypeScript
}
}
#[derive(Serialize, Deserialize, Default)]
pub struct Options {
pub language: Option<Language>,
pub jsx: Option<bool>,
pub eslintrc: Option<String>,
}
#[wasm_bindgen]
#[must_use]
#[allow(deprecated)]
pub fn main(text: &str, js_options: &JsValue) -> JsValue {
set_panic_hook();
let options: Options = js_options.into_serde().unwrap_or_default();
let path_str = format!(
"test.{}{}",
if matches!(options.language, Some(Language::TypeScript)) { "ts" } else { "js" },
if options.jsx.unwrap_or_default() { "x" } else { "" }
);
let source_type = SourceType::from_path(&path_str).unwrap_or_default();
let driver = Driver::new();
driver.run(&path_str, text, source_type, &options.eslintrc.unwrap_or_default())
}

View file

@ -0,0 +1,10 @@
pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the
// `set_panic_hook` function at least once during initialization, and then
// we will get better error messages if our code ever panics.
//
// For more details see
// https://github.com/rustwasm/console_error_panic_hook#readme
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}