diff --git a/Cargo.lock b/Cargo.lock index d8623061..2f9dc24e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,6 +301,26 @@ dependencies = [ "windows-sys 0.59.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 = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "cookie" version = "0.12.0" @@ -882,10 +902,11 @@ checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "js-sys" -version = "0.3.58" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1033,6 +1054,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1713,12 +1744,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.20" @@ -1782,6 +1828,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -2001,6 +2058,24 @@ dependencies = [ "squawk_parser", ] +[[package]] +name = "squawk_wasm" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "console_log", + "line-index", + "log", + "serde", + "serde-wasm-bindgen", + "squawk_lexer", + "squawk_linter", + "squawk_syntax", + "wasm-bindgen", + "wasm-bindgen-test", + "web-sys", +] + [[package]] name = "string" version = "0.2.1" @@ -2369,9 +2444,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -2456,6 +2531,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.2.0" @@ -2475,34 +2560,48 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.81" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if 1.0.0", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.81" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", - "lazy_static", "log", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.101", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.81" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2510,28 +2609,55 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.81" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.81" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +dependencies = [ + "js-sys", + "minicov", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] name = "web-sys" -version = "0.3.58" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 163f4247..1af1f798 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,12 @@ rowan = "0.15.15" smol_str = "0.3.2" enum-iterator = "2.1.0" line-index = "0.1.2" +serde-wasm-bindgen = "0.6.5" +wasm-bindgen = "0.2.100" +wasm-bindgen-test = "0.3.34" +web-sys = "0.3.77" +console_error_panic_hook = "0.1.7" +console_log = "1.0.0" # local squawk-parser = { version = "0.0.0", path = "./crates/parser" } @@ -44,6 +50,7 @@ squawk-github = { version = "0.0.0", path = "./crates/github" } squawk_lexer = { version = "0.0.0", path = "./crates/squawk_lexer" } squawk_parser = { version = "0.0.0", path = "./crates/squawk_parser" } squawk_syntax = { version = "0.0.0", path = "./crates/squawk_syntax" } +squawk_linter = { version = "0.0.0", path = "./crates/squawk_linter" } [workspace.lints.clippy] collapsible_else_if = "allow" diff --git a/crates/squawk_wasm/Cargo.toml b/crates/squawk_wasm/Cargo.toml new file mode 100644 index 00000000..18685497 --- /dev/null +++ b/crates/squawk_wasm/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "squawk_wasm" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +[dependencies] + +squawk_syntax.workspace = true +squawk_linter.workspace = true +squawk_lexer.workspace = true + +wasm-bindgen.workspace = true +serde-wasm-bindgen.workspace = true +serde.workspace = true +console_error_panic_hook = { workspace = true, optional = true } +web-sys = { workspace = true, features = ["Window"] } +console_log.workspace = true +log.workspace = true +line-index.workspace = true + +[dev-dependencies] +wasm-bindgen-test.workspace = true + +[lints] +workspace = true diff --git a/crates/squawk_wasm/README.md b/crates/squawk_wasm/README.md new file mode 100644 index 00000000..8d108544 --- /dev/null +++ b/crates/squawk_wasm/README.md @@ -0,0 +1,5 @@ +# squak_wasm + +```shell +wasm-pack build --target web crates/squawk_wasm +``` diff --git a/crates/squawk_wasm/src/lib.rs b/crates/squawk_wasm/src/lib.rs new file mode 100644 index 00000000..dc67d7c5 --- /dev/null +++ b/crates/squawk_wasm/src/lib.rs @@ -0,0 +1,136 @@ +use line_index::LineIndex; +use log::info; +use serde::Serialize; +use wasm_bindgen::prelude::*; +use web_sys::js_sys::Error; + +#[wasm_bindgen(start)] +pub fn run() { + use log::Level; + + // 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(); + console_log::init_with_level(Level::Debug).expect("Initializing logger went wrong."); + info!("init!"); +} + +#[wasm_bindgen] +pub fn dump_cst(text: String) -> String { + let parse = squawk_syntax::SourceFile::parse(&text); + format!("{:#?}", parse.syntax_node()) +} + +#[wasm_bindgen] +pub fn dump_tokens(text: String) -> String { + let tokens = squawk_lexer::tokenize(&text); + let mut start = 0; + let mut out = String::new(); + for token in tokens { + let end = start + token.len; + let content = &text[start as usize..(end) as usize]; + out += &format!("{:?}@{start}..{end} {:?}\n", token.kind, content); + start += token.len; + } + out +} + +#[allow(dead_code)] +#[derive(Serialize)] +enum Severity { + Hint, + Info, + Warning, + Error, +} + +#[derive(Serialize)] +struct LintError { + severity: Severity, + code: String, + message: String, + start_line_number: u32, + start_column: u32, + end_line_number: u32, + end_column: u32, + // used for the linter tab + range_start: usize, + // used for the linter tab + range_end: usize, + // used for the linter tab + messages: Vec, +} + +#[wasm_bindgen] +pub fn lint(text: String) -> Result { + let mut linter = squawk_linter::Linter::with_all_rules(); + let parse = squawk_syntax::SourceFile::parse(&text); + let parse_errors = parse.errors(); + + let line_index = LineIndex::new(&text); + + // TODO: chain these with other stuff + let parse_errors = parse_errors.iter().map(|x| { + let range_start = x.range().start(); + let range_end = x.range().end(); + let start = line_index.line_col(range_start); + let end = line_index.line_col(range_end); + let start = line_index + .to_wide(line_index::WideEncoding::Utf16, start) + .unwrap(); + let end = line_index + .to_wide(line_index::WideEncoding::Utf16, end) + .unwrap(); + LintError { + severity: Severity::Error, + code: "syntax-error".to_string(), + message: x.message().to_string(), + start_line_number: start.line, + start_column: start.col, + end_line_number: end.line, + end_column: end.col, + range_start: range_start.into(), + range_end: range_end.into(), + messages: vec![], + } + }); + + let lint_errors = linter.lint(parse, &text); + let errors = lint_errors.into_iter().map(|x| { + let start = line_index.line_col(x.text_range.start()); + let end = line_index.line_col(x.text_range.end()); + let start = line_index + .to_wide(line_index::WideEncoding::Utf16, start) + .unwrap(); + let end = line_index + .to_wide(line_index::WideEncoding::Utf16, end) + .unwrap(); + LintError { + code: x.code.to_string(), + range_start: x.text_range.start().into(), + range_end: x.text_range.end().into(), + message: x.message.clone(), + messages: x.messages.clone(), + // parser errors should be error + severity: Severity::Warning, + start_line_number: start.line, + start_column: start.col, + end_line_number: end.line, + end_column: end.col, + } + }); + + let mut errors_to_dump = errors.chain(parse_errors).collect::>(); + errors_to_dump.sort_by_key(|k| (k.start_line_number, k.start_column)); + + serde_wasm_bindgen::to_value(&errors_to_dump).map_err(into_error) +} + +fn into_error(err: E) -> Error { + Error::new(&err.to_string()) +}