From 423c168e7ee168d608e0ff909e6d01595ac390bb Mon Sep 17 00:00:00 2001 From: Wenzhuo Liu Date: Thu, 14 Mar 2024 23:27:32 +0800 Subject: [PATCH] feat: add wasm and webui (#3) * add wasm and re-org code * feat: add webui * ci: add gh pages * feat: add link * test: add missing snapshots --- .github/workflows/gh-pages.yml | 55 + Cargo.lock | 61 + Cargo.toml | 3 +- src/lib.rs | 1061 +---------------- src/pretty.rs | 1054 ++++++++++++++++ src/prop.rs | 5 +- ...__pretty__tests__convert_func_call-2.snap} | 2 +- ...ua__pretty__tests__convert_func_call.snap} | 2 +- ...hua__pretty__tests__convert_markup-2.snap} | 2 +- ...hihua__pretty__tests__convert_markup.snap} | 2 +- ...st_geshihua__pretty__tests__to_doc-2.snap} | 4 +- ...st_geshihua__pretty__tests__to_doc-3.snap} | 4 +- ...st_geshihua__pretty__tests__to_doc-4.snap} | 4 +- ...ypst_geshihua__pretty__tests__to_doc.snap} | 4 +- ...geshihua__util__tests__pretty_items-2.snap | 10 - ...geshihua__util__tests__pretty_items-3.snap | 5 - ...t_geshihua__util__tests__pretty_items.snap | 9 - src/util.rs | 2 +- web/.gitignore | 24 + web/index.html | 15 + web/package.json | 21 + web/src/main.ts | 57 + web/src/style.css | 103 ++ web/src/vite-env.d.ts | 1 + web/tsconfig.json | 23 + web/vite.config.mjs | 11 + web/yarn.lock | 395 ++++++ 27 files changed, 1848 insertions(+), 1091 deletions(-) create mode 100644 .github/workflows/gh-pages.yml create mode 100644 src/pretty.rs rename src/snapshots/{typst_geshihua__tests__convert_func_call-2.snap => typst_geshihua__pretty__tests__convert_func_call-2.snap} (79%) rename src/snapshots/{typst_geshihua__tests__convert_func_call.snap => typst_geshihua__pretty__tests__convert_func_call.snap} (95%) rename src/snapshots/{typst_geshihua__tests__convert_markup-2.snap => typst_geshihua__pretty__tests__convert_markup-2.snap} (89%) rename src/snapshots/{typst_geshihua__tests__convert_markup.snap => typst_geshihua__pretty__tests__convert_markup.snap} (95%) rename src/snapshots/{typst_geshihua__tests__to_doc-2.snap => typst_geshihua__pretty__tests__to_doc-2.snap} (53%) rename src/snapshots/{typst_geshihua__tests__to_doc-3.snap => typst_geshihua__pretty__tests__to_doc-3.snap} (54%) rename src/snapshots/{typst_geshihua__tests__to_doc-4.snap => typst_geshihua__pretty__tests__to_doc-4.snap} (54%) rename src/snapshots/{typst_geshihua__tests__to_doc.snap => typst_geshihua__pretty__tests__to_doc.snap} (53%) delete mode 100644 src/snapshots/typst_geshihua__util__tests__pretty_items-2.snap delete mode 100644 src/snapshots/typst_geshihua__util__tests__pretty_items-3.snap delete mode 100644 src/snapshots/typst_geshihua__util__tests__pretty_items.snap create mode 100644 web/.gitignore create mode 100644 web/index.html create mode 100644 web/package.json create mode 100644 web/src/main.ts create mode 100644 web/src/style.css create mode 100644 web/src/vite-env.d.ts create mode 100644 web/tsconfig.json create mode 100644 web/vite.config.mjs create mode 100644 web/yarn.lock diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 00000000..67a8a8c5 --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -0,0 +1,55 @@ +name: GitHub Pages +on: + push: + branches: + - master + workflow_dispatch: + +permissions: + pages: write + id-token: write + contents: read + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build-gh-pages: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v4 + with: { submodules: recursive } + - uses: typst-community/setup-typst@v3 + with: { typst-version: "0.10.0" } + - uses: rui314/setup-mold@v1 + - uses: dtolnay/rust-toolchain@stable + with: { targets: wasm32-unknown-unknown } + - uses: jetli/wasm-pack-action@v0.4.0 + with: + version: "v0.12.1" + - uses: mozilla-actions/sccache-action@v0.0.3 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - run: | + wasm-pack build + - run: | + cd web + yarn + yarn build + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + # Upload `/github-pages` sub directory + path: "web/dist" + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/Cargo.lock b/Cargo.lock index 8539f921..e33bdfaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,6 +89,12 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + [[package]] name = "camino" version = "1.1.6" @@ -777,6 +783,7 @@ dependencies = [ "pretty_assertions", "typst-syntax", "vergen", + "wasm-bindgen", ] [[package]] @@ -885,6 +892,60 @@ dependencies = [ "time", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 206a576a..97c8222a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ path = "src/main.rs" [lib] name = "typst_geshihua" path = "src/lib.rs" -crate-type = ["lib"] +crate-type = ["cdylib", "lib"] [dependencies] @@ -20,6 +20,7 @@ clap = { version = "4.5.2", features = ["derive", "env"] } itertools = "0.12.1" once_cell = "1.19.0" pretty = "0.12.3" +wasm-bindgen = "0.2" typst-syntax = { git = "https://github.com/typst/typst.git", tag = "v0.11.0-rc1" } [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 13474600..35e82ffd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,1012 +1,9 @@ +pub mod pretty; pub mod prop; pub mod util; -use std::borrow::Cow; -use std::collections::HashSet; - -use itertools::Itertools; -use pretty::BoxDoc; -use prop::get_no_format_nodes; -use typst_syntax::{ast, SyntaxNode}; -use typst_syntax::{ast::*, SyntaxKind}; - -use crate::util::pretty_items; - -#[derive(Debug, Default)] -pub struct PrettyPrinter { - disabled_nodes: HashSet, -} - -impl PrettyPrinter { - pub fn new(disabled_nodes: HashSet) -> Self { - Self { disabled_nodes } - } -} - -impl PrettyPrinter { - pub fn convert_markup<'a>(&'a self, root: Markup<'a>) -> BoxDoc<'a, ()> { - let mut doc: BoxDoc<()> = BoxDoc::nil(); - for node in root.to_untyped().children() { - if let Some(expr) = node.cast::() { - let expr_doc = self.convert_expr(expr); - doc = doc.append(expr_doc); - } else if let Some(space) = node.cast::() { - doc = doc.append(self.convert_space(space)); - } else { - doc = doc.append(trivia(node)); - } - } - doc - } - - fn check_disabled<'a>(&'a self, node: &SyntaxNode) -> Option> { - if self.disabled_nodes.contains(node) { - Some(self.format_disabled(node)) - } else { - None - } - } - - fn format_disabled<'a>(&'a self, node: &SyntaxNode) -> BoxDoc<'a, ()> { - let doc: BoxDoc<()> = BoxDoc::text(node.clone().into_text().to_string()); - doc - } - - fn convert_expr<'a>(&'a self, expr: Expr<'a>) -> BoxDoc<'a, ()> { - if let Some(res) = self.check_disabled(expr.to_untyped()) { - return res; - } - match expr { - ast::Expr::Text(t) => self.convert_text(t), - ast::Expr::Space(s) => self.convert_space(s), - ast::Expr::Linebreak(b) => self.convert_linebreak(b), - ast::Expr::Parbreak(b) => self.convert_parbreak(b), - ast::Expr::Escape(e) => self.convert_escape(e), - ast::Expr::Shorthand(s) => self.convert_shorthand(s), - ast::Expr::SmartQuote(s) => self.convert_smart_quote(s), - ast::Expr::Strong(s) => self.convert_strong(s), - ast::Expr::Emph(e) => self.convert_emph(e), - ast::Expr::Raw(r) => self.convert_raw(r), - ast::Expr::Link(l) => self.convert_link(l), - ast::Expr::Label(l) => self.convert_label(l), - ast::Expr::Ref(r) => self.convert_ref(r), - ast::Expr::Heading(h) => self.convert_heading(h), - ast::Expr::List(l) => self.convert_list_item(l), - ast::Expr::Enum(e) => self.convert_enum_item(e), - ast::Expr::Term(t) => self.convert_term_item(t), - ast::Expr::Equation(e) => self.convert_equation(e), - ast::Expr::Math(m) => self.convert_math(m), - ast::Expr::MathIdent(mi) => trivia(mi.to_untyped()), - ast::Expr::MathAlignPoint(map) => trivia(map.to_untyped()), - ast::Expr::MathDelimited(md) => self.convert_math_delimited(md), - ast::Expr::MathAttach(ma) => self.convert_math_attach(ma), - ast::Expr::MathPrimes(mp) => self.convert_math_primes(mp), - ast::Expr::MathFrac(mf) => self.convert_math_frac(mf), - ast::Expr::MathRoot(mr) => self.convert_math_root(mr), - ast::Expr::Ident(i) => self.convert_ident(i), - ast::Expr::None(n) => self.convert_none(n), - ast::Expr::Auto(a) => self.convert_auto(a), - ast::Expr::Bool(b) => self.convert_bool(b), - ast::Expr::Int(i) => self.convert_int(i), - ast::Expr::Float(f) => self.convert_float(f), - ast::Expr::Numeric(n) => self.convert_numeric(n), - ast::Expr::Str(s) => self.convert_str(s), - ast::Expr::Code(c) => self.convert_code_block(c), - ast::Expr::Content(c) => self.convert_content_block(c), - ast::Expr::Parenthesized(p) => self.convert_parenthesized(p), - ast::Expr::Array(a) => self.convert_array(a), - ast::Expr::Dict(d) => self.convert_dict(d), - ast::Expr::Unary(u) => self.convert_unary(u), - ast::Expr::Binary(b) => self.convert_binary(b), - ast::Expr::FieldAccess(fa) => self.convert_field_access(fa), - ast::Expr::FuncCall(fc) => self.convert_func_call(fc), - ast::Expr::Closure(c) => self.convert_closure(c), - ast::Expr::Let(l) => self.convert_let_binding(l), - ast::Expr::DestructAssign(da) => self.convert_destruct_assignment(da), - ast::Expr::Set(s) => self.convert_set_rule(s), - ast::Expr::Show(s) => self.convert_show_rule(s), - ast::Expr::Conditional(c) => self.convert_conditional(c), - ast::Expr::While(w) => self.convert_while(w), - ast::Expr::For(f) => self.convert_for(f), - ast::Expr::Import(i) => self.convert_import(i), - ast::Expr::Include(i) => self.convert_include(i), - ast::Expr::Break(b) => self.convert_break(b), - ast::Expr::Continue(c) => self.convert_continue(c), - ast::Expr::Return(r) => self.convert_return(r), - ast::Expr::Contextual(c) => self.convert_contextual(c), - } - .group() - } - - fn convert_text<'a>(&'a self, text: Text<'a>) -> BoxDoc<'a, ()> { - let node = text.to_untyped(); - trivia(node) - } - - fn convert_space<'a>(&'a self, space: Space<'a>) -> BoxDoc<'a, ()> { - let node = space.to_untyped(); - if node.text().contains('\n') { - BoxDoc::hardline() - } else { - BoxDoc::space() - } - } - - fn convert_linebreak<'a>(&'a self, linebreak: Linebreak<'a>) -> BoxDoc<'a, ()> { - let node = linebreak.to_untyped(); - trivia(node) - } - - fn convert_parbreak<'a>(&'a self, _parbreak: Parbreak<'a>) -> BoxDoc<'a, ()> { - BoxDoc::hardline().append(BoxDoc::hardline()) - } - - fn convert_escape<'a>(&'a self, escape: Escape<'a>) -> BoxDoc<'a, ()> { - let node = escape.to_untyped(); - trivia(node) - } - - fn convert_shorthand<'a>(&'a self, shorthand: Shorthand<'a>) -> BoxDoc<'a, ()> { - let node = shorthand.to_untyped(); - trivia(node) - } - - fn convert_smart_quote<'a>(&'a self, smart_quote: SmartQuote<'a>) -> BoxDoc<'a, ()> { - let node = smart_quote.to_untyped(); - trivia(node) - } - - fn convert_strong<'a>(&'a self, strong: Strong<'a>) -> BoxDoc<'a, ()> { - let body = self.convert_markup(strong.body()); - BoxDoc::text("*").append(body).append(BoxDoc::text("*")) - } - - fn convert_emph<'a>(&'a self, emph: Emph<'a>) -> BoxDoc<'a, ()> { - let body = self.convert_markup(emph.body()); - BoxDoc::text("_").append(body).append(BoxDoc::text("_")) - } - - fn convert_raw<'a>(&'a self, raw: Raw<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil(); - let is_block = raw.block(); - let has_lang = raw.lang().is_some(); - let mut is_opening = true; - for child in raw.to_untyped().children() { - if let Some(delim) = child.cast::() { - doc = doc.append(trivia(delim.to_untyped())); - if is_block && !has_lang && is_opening { - doc = doc.append(BoxDoc::hardline()); - is_opening = false; - } - } - if let Some(lang) = child.cast::() { - doc = doc.append(trivia(lang.to_untyped())); - doc = doc.append(BoxDoc::hardline()); - } - if let Some(line) = child.cast::() { - doc = doc.append(trivia(line.to_untyped())); - if is_block { - doc = doc.append(BoxDoc::hardline()); - } - } - } - doc - } - - fn convert_link<'a>(&'a self, link: Link<'a>) -> BoxDoc<'a, ()> { - let node = link.to_untyped(); - trivia(node) - } - - fn convert_label<'a>(&'a self, label: Label<'a>) -> BoxDoc<'a, ()> { - let node = label.to_untyped(); - trivia(node) - } - - fn convert_ref<'a>(&'a self, reference: Ref<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::text("@"); - doc = doc.append(BoxDoc::text(reference.target())); - if let Some(supplement) = reference.supplement() { - doc = doc.append(self.convert_content_block(supplement)); - } - doc - } - - fn convert_heading<'a>(&'a self, heading: Heading<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::text("=".repeat(heading.depth().into())); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_markup(heading.body())); - doc - } - - fn convert_list_item<'a>(&'a self, list_item: ListItem<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::text("-"); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_markup(list_item.body()).nest(2)); - doc - } - - fn convert_enum_item<'a>(&'a self, enum_item: EnumItem<'a>) -> BoxDoc<'a, ()> { - let mut doc = if let Some(number) = enum_item.number() { - BoxDoc::text(format!("{number}.")) - } else { - BoxDoc::text("+") - }; - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_markup(enum_item.body()).nest(2)); - doc - } - - fn convert_term_item<'a>(&'a self, term: TermItem<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::text("/"); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_markup(term.term())); - doc = doc.append(BoxDoc::text(":")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_markup(term.description()).nest(2)); - doc - } - - fn convert_equation<'a>(&'a self, equation: Equation<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::text("$"); - if equation.block() { - doc = doc.append(BoxDoc::line()); - } - doc = doc.append(self.convert_math(equation.body()).nest(2)); - if equation.block() { - doc = doc.append(BoxDoc::line()); - } - doc = doc.append(BoxDoc::text("$")); - doc - } - - fn convert_math<'a>(&'a self, math: Math<'a>) -> BoxDoc<'a, ()> { - let mut doc: BoxDoc<()> = BoxDoc::nil(); - for node in math.to_untyped().children() { - if let Some(expr) = node.cast::() { - let expr_doc = self.convert_expr(expr); - doc = doc.append(expr_doc); - } else if let Some(space) = node.cast::() { - doc = doc.append(self.convert_space(space)); - } else { - doc = doc.append(trivia(node)); - } - } - doc - } - - fn convert_ident<'a>(&'a self, ident: Ident<'a>) -> BoxDoc<'a, ()> { - let doc = BoxDoc::nil().append(BoxDoc::text(ident.as_str())); - doc - } - - fn convert_none<'a>(&'a self, _none: None<'a>) -> BoxDoc<'a, ()> { - BoxDoc::nil().append(BoxDoc::text("none")) - } - - fn convert_auto<'a>(&'a self, _auto: Auto<'a>) -> BoxDoc<'a, ()> { - BoxDoc::nil().append(BoxDoc::text("auto")) - } - - fn convert_bool<'a>(&'a self, boolean: Bool<'a>) -> BoxDoc<'a, ()> { - let node = boolean.to_untyped(); - trivia(node) - } - - fn convert_int<'a>(&'a self, int: Int<'a>) -> BoxDoc<'a, ()> { - let node = int.to_untyped(); - trivia(node) - } - - fn convert_float<'a>(&'a self, float: Float<'a>) -> BoxDoc<'a, ()> { - let node = float.to_untyped(); - trivia(node) - } - - fn convert_numeric<'a>(&'a self, numeric: Numeric<'a>) -> BoxDoc<'a, ()> { - let node = numeric.to_untyped(); - trivia(node) - } - - fn convert_str<'a>(&'a self, str: Str<'a>) -> BoxDoc<'a, ()> { - let node = str.to_untyped(); - trivia(node) - } - - fn convert_code_block<'a>(&'a self, code_block: CodeBlock<'a>) -> BoxDoc<'a, ()> { - let mut codes: Vec<_> = vec![]; - for node in code_block.to_untyped().children() { - if let Some(code) = node.cast::() { - let code_doc = self.convert_code(code); - codes.extend(code_doc); - } else if node.kind() == SyntaxKind::LineComment - || node.kind() == SyntaxKind::BlockComment - { - codes.push(to_doc(std::borrow::Cow::Borrowed(node.text()), true)); - } - } - let doc = pretty_items( - &codes, - BoxDoc::text(";").append(BoxDoc::space()), - BoxDoc::nil(), - (BoxDoc::text("{"), BoxDoc::text("}")), - true, - util::FoldStyle::Never, - ); - doc - } - - fn convert_code<'a>(&'a self, code: Code<'a>) -> Vec> { - let mut codes: Vec<_> = vec![]; - for node in code.to_untyped().children() { - if let Some(expr) = node.cast::() { - let expr_doc = self.convert_expr(expr); - codes.push(expr_doc); - } else if node.kind() == SyntaxKind::LineComment - || node.kind() == SyntaxKind::BlockComment - { - codes.push(to_doc(std::borrow::Cow::Borrowed(node.text()), true)); - } else if node.kind() == SyntaxKind::Space { - let newline_cnt = node.text().chars().filter(|c| *c == '\n').count(); - for _ in 0..newline_cnt.saturating_sub(1) { - codes.push(BoxDoc::nil()); - } - } - } - codes - } - - fn convert_content_block<'a>(&'a self, content_block: ContentBlock<'a>) -> BoxDoc<'a, ()> { - let content = self.convert_markup(content_block.body()).group().nest(2); - let doc = BoxDoc::text("[").append(content).append(BoxDoc::text("]")); - doc - } - - fn convert_parenthesized<'a>(&'a self, parenthesized: Parenthesized<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::text("("); - let inner = self.convert_expr(parenthesized.expr()); - let multiline_expr = BoxDoc::line() - .append(inner.clone()) - .append(BoxDoc::line()) - .nest(2) - .group(); - let singleline_expr = inner; - doc = doc.append(multiline_expr.flat_alt(singleline_expr)); - doc = doc.append(BoxDoc::text(")")); - doc - } - - fn convert_array<'a>(&'a self, array: Array<'a>) -> BoxDoc<'a, ()> { - let array_items = array - .items() - .map(|item| self.convert_array_item(item)) - .collect_vec(); - if array_items.len() == 1 { - let singleline = BoxDoc::text("(") - .append(array_items[0].clone()) - .append(BoxDoc::text(",")) - .append(BoxDoc::text(")")); - let multiline = BoxDoc::text("(") - .append( - BoxDoc::hardline() - .append(array_items[0].clone()) - .append(BoxDoc::text(",")) - .nest(2), - ) - .append(BoxDoc::hardline()) - .append(BoxDoc::text(")")) - .group(); - multiline.flat_alt(singleline) - } else { - pretty_items( - &array_items, - BoxDoc::text(",").append(BoxDoc::space()), - BoxDoc::text(","), - (BoxDoc::text("("), BoxDoc::text(")")), - false, - util::FoldStyle::Fit, - ) - } - } - - fn convert_array_item<'a>(&'a self, array_item: ArrayItem<'a>) -> BoxDoc<'a, ()> { - let doc = match array_item { - ArrayItem::Pos(p) => self.convert_expr(p), - ArrayItem::Spread(s) => self.convert_spread(s), - }; - doc - } - - fn convert_dict<'a>(&'a self, dict: Dict<'a>) -> BoxDoc<'a, ()> { - if dict.items().count() == 0 { - return BoxDoc::text("(:)"); - } - let dict_items = dict - .items() - .map(|item| self.convert_dict_item(item)) - .collect_vec(); - pretty_items( - &dict_items, - BoxDoc::text(",").append(BoxDoc::space()), - BoxDoc::text(","), - (BoxDoc::text("("), BoxDoc::text(")")), - false, - util::FoldStyle::Fit, - ) - } - - fn convert_dict_item<'a>(&'a self, dict_item: DictItem<'a>) -> BoxDoc<'a, ()> { - match dict_item { - DictItem::Named(n) => self.convert_named(n), - DictItem::Keyed(k) => self.convert_keyed(k), - DictItem::Spread(s) => self.convert_spread(s), - } - } - - fn convert_named<'a>(&'a self, named: Named<'a>) -> BoxDoc<'a, ()> { - if let Some(res) = self.check_disabled(named.to_untyped()) { - return res; - } - // TODO: better handling hash # - let has_hash = named - .to_untyped() - .children() - .any(|node| matches!(node.kind(), SyntaxKind::Hash)); - let mut doc = self.convert_ident(named.name()); - doc = doc.append(BoxDoc::text(":")); - doc = doc.append(BoxDoc::space()); - if has_hash { - doc = doc.append(BoxDoc::text("#")); - } - doc = doc.append(self.convert_expr(named.expr())); - doc - } - - fn convert_keyed<'a>(&'a self, keyed: Keyed<'a>) -> BoxDoc<'a, ()> { - let mut doc = self.convert_expr(keyed.key()); - doc = doc.append(BoxDoc::text(":")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(keyed.expr())); - doc - } - - fn convert_unary<'a>(&'a self, unary: Unary<'a>) -> BoxDoc<'a, ()> { - let op_text = match unary.op() { - UnOp::Pos => "+", - UnOp::Neg => "-", - UnOp::Not => "not ", - }; - BoxDoc::text(op_text).append(self.convert_expr(unary.expr())) - } - - fn convert_binary<'a>(&'a self, binary: Binary<'a>) -> BoxDoc<'a, ()> { - BoxDoc::nil() - .append(self.convert_expr(binary.lhs())) - .append(BoxDoc::space()) - .append(BoxDoc::text(binary.op().as_str())) - .append(BoxDoc::space()) - .append(self.convert_expr(binary.rhs())) - } - - fn convert_field_access<'a>(&'a self, field_access: FieldAccess<'a>) -> BoxDoc<'a, ()> { - let left = BoxDoc::nil().append(self.convert_expr(field_access.target())); - let singleline_right = BoxDoc::text(".").append(self.convert_ident(field_access.field())); - let _multiline_right = BoxDoc::hardline() - .append(BoxDoc::text(".")) - .append(self.convert_ident(field_access.field())) - .nest(2) - .group(); - // TODO: typst doesn't support this - // left.append(multiline_right.flat_alt(singleline_right)) - left.append(singleline_right) - } - - fn convert_func_call<'a>(&'a self, func_call: FuncCall<'a>) -> BoxDoc<'a, ()> { - let doc = BoxDoc::nil().append(self.convert_expr(func_call.callee())); - if let Some(res) = self.check_disabled(func_call.args().to_untyped()) { - return doc.append(res); - } - let has_parenthesized_args = func_call - .args() - .to_untyped() - .children() - .any(|node| matches!(node.kind(), SyntaxKind::LeftParen | SyntaxKind::RightParen)); - let parenthesized_args = if has_parenthesized_args { - let args = self.convert_parenthesized_args(func_call.args()); - pretty_items( - &args, - BoxDoc::text(",").append(BoxDoc::space()), - BoxDoc::text(","), - (BoxDoc::text("("), BoxDoc::text(")")), - false, - util::FoldStyle::Fit, - ) - } else { - BoxDoc::nil() - }; - let doc = doc - .append(parenthesized_args) - .append(self.convert_additional_args(func_call.args(), has_parenthesized_args)); - doc - } - - fn convert_parenthesized_args<'a>(&'a self, args: Args<'a>) -> Vec> { - let node = args.to_untyped(); - let args = node - .children() - .take_while(|node| node.kind() != SyntaxKind::RightParen) - .filter_map(|node| node.cast::<'_, Arg>()) - .map(|arg| self.convert_arg(arg)) - .collect(); - args - } - - fn convert_additional_args<'a>(&'a self, args: Args<'a>, has_paren: bool) -> BoxDoc<'a, ()> { - let node = args.to_untyped(); - let args = node - .children() - .skip_while(|node| { - if has_paren { - node.kind() != SyntaxKind::RightParen - } else { - node.kind() != SyntaxKind::ContentBlock - } - }) - .filter_map(|node| node.cast::<'_, Arg>()); - BoxDoc::concat(args.map(|arg| self.convert_arg(arg))).group() - } - - fn convert_arg<'a>(&'a self, arg: Arg<'a>) -> BoxDoc<'a, ()> { - match arg { - Arg::Pos(p) => self.convert_expr(p), - Arg::Named(n) => self.convert_named(n), - Arg::Spread(s) => self.convert_spread(s), - } - } - - fn convert_closure<'a>(&'a self, closure: Closure<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil(); - let params = self.convert_params(closure.params()); - let arg_list = pretty_items( - ¶ms, - BoxDoc::text(",").append(BoxDoc::space()), - BoxDoc::text(","), - (BoxDoc::text("("), BoxDoc::text(")")), - false, - util::FoldStyle::Fit, - ); - if let Some(name) = closure.name() { - doc = doc.append(self.convert_ident(name)); - doc = doc.append(arg_list); - doc = doc.append(BoxDoc::space()); - doc = doc.append(BoxDoc::text("=")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(closure.body())); - } else { - if params.len() == 1 - && matches!(closure.params().children().next().unwrap(), Param::Pos(_)) - && !matches!( - closure.params().children().next().unwrap(), - Param::Pos(Pattern::Destructuring(_)) - ) - { - doc = params[0].clone(); - } else { - doc = arg_list - } - doc = doc.append(BoxDoc::space()); - doc = doc.append(BoxDoc::text("=>")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(closure.body())); - } - doc - } - - fn convert_params<'a>(&'a self, params: Params<'a>) -> Vec> { - params - .children() - .map(|param| self.convert_param(param)) - .collect() - } - - fn convert_param<'a>(&'a self, param: Param<'a>) -> BoxDoc<'a, ()> { - match param { - Param::Pos(p) => self.convert_pattern(p), - Param::Named(n) => self.convert_named(n), - Param::Spread(s) => self.convert_spread(s), - } - } - - fn convert_spread<'a>(&'a self, spread: Spread<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::text(".."); - let ident = if let Some(id) = spread.sink_ident() { - self.convert_ident(id) - } else if let Some(expr) = spread.sink_expr() { - self.convert_expr(expr) - } else { - BoxDoc::nil() - }; - doc = doc.append(ident); - doc - } - - fn convert_pattern<'a>(&'a self, pattern: Pattern<'a>) -> BoxDoc<'a, ()> { - match pattern { - Pattern::Normal(n) => self.convert_expr(n), - Pattern::Placeholder(p) => self.convert_underscore(p), - Pattern::Destructuring(d) => self.convert_destructuring(d), - Pattern::Parenthesized(p) => self.convert_parenthesized(p), - } - } - - fn convert_underscore<'a>(&'a self, _underscore: Underscore<'a>) -> BoxDoc<'a, ()> { - BoxDoc::text("_") - } - - fn convert_destructuring<'a>(&'a self, destructuring: Destructuring<'a>) -> BoxDoc<'a, ()> { - BoxDoc::text("(") - .append(BoxDoc::intersperse( - destructuring - .items() - .map(|item| self.convert_destructuring_item(item)), - BoxDoc::text(",").append(BoxDoc::line()), - )) - .append(BoxDoc::text(")")) - } - - fn convert_destructuring_item<'a>( - &'a self, - destructuring_item: DestructuringItem<'a>, - ) -> BoxDoc<'a, ()> { - match destructuring_item { - DestructuringItem::Spread(s) => self.convert_spread(s), - DestructuringItem::Named(n) => self.convert_named(n), - DestructuringItem::Pattern(p) => self.convert_pattern(p), - } - } - - fn convert_let_binding<'a>(&'a self, let_binding: LetBinding<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil() - .append(BoxDoc::text("let")) - .append(BoxDoc::space()); - match let_binding.kind() { - LetBindingKind::Normal(n) => { - doc = doc.append(self.convert_pattern(n).group()); - if let Some(expr) = let_binding.init() { - doc = doc.append(BoxDoc::space()); - doc = doc.append(BoxDoc::text("=")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(expr)); - } - } - LetBindingKind::Closure(_c) => { - if let Some(c) = let_binding.init() { - doc = doc.append(self.convert_expr(c)); - } - } - } - doc - } - - fn convert_destruct_assignment<'a>( - &'a self, - destruct_assign: DestructAssignment<'a>, - ) -> BoxDoc<'a, ()> { - self.convert_pattern(destruct_assign.pattern()) - .append(BoxDoc::space()) - .append(BoxDoc::text("=")) - .append(BoxDoc::space()) - .append(self.convert_expr(destruct_assign.value())) - } - - fn convert_set_rule<'a>(&'a self, set_rule: SetRule<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil() - .append(BoxDoc::text("set")) - .append(BoxDoc::space()); - doc = doc.append(self.convert_expr(set_rule.target())); - doc = doc.append(pretty_items( - &self.convert_parenthesized_args(set_rule.args()), - BoxDoc::text(",").append(BoxDoc::space()), - BoxDoc::text(","), - (BoxDoc::text("("), BoxDoc::text(")")), - false, - util::FoldStyle::Single, - )); - if let Some(condition) = set_rule.condition() { - doc = doc.append(BoxDoc::space()); - doc = doc.append(BoxDoc::text("if")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(condition)); - } - doc - } - - fn convert_show_rule<'a>(&'a self, show_rule: ShowRule<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil().append(BoxDoc::text("show")); - if let Some(selector) = show_rule.selector() { - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(selector)); - } - doc = doc.append(BoxDoc::text(":")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(show_rule.transform())); - doc - } - - fn convert_conditional<'a>(&'a self, conditional: Conditional<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil(); - enum CastType { - Condition, - Then, - Else, - } - let has_else = conditional.else_body().is_some(); - let mut expr_type = CastType::Condition; - for child in conditional.to_untyped().children() { - if child.kind() == SyntaxKind::If { - doc = doc.append(BoxDoc::text("if")); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::Else { - doc = doc.append(BoxDoc::text("else")); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::BlockComment { - doc = doc.append(trivia(child)); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::LineComment { - doc = doc.append(trivia(child)); - doc = doc.append(BoxDoc::hardline()); - } else { - match expr_type { - CastType::Condition => { - if let Some(condition) = child.cast() { - doc = doc.append(self.convert_expr(condition)); - doc = doc.append(BoxDoc::space()); - expr_type = CastType::Then; - } - } - CastType::Then => { - if let Some(then_expr) = child.cast() { - doc = doc.append(self.convert_expr(then_expr).group()); - if has_else { - expr_type = CastType::Else; - doc = doc.append(BoxDoc::space()); - } - } - } - CastType::Else => { - if let Some(else_expr) = child.cast() { - doc = doc.append(self.convert_expr(else_expr).group()); - } - } - } - } - } - doc - } - - fn convert_while<'a>(&'a self, while_loop: WhileLoop<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil(); - #[derive(Debug, PartialEq)] - enum CastType { - Condition, - Body, - } - let mut expr_type = CastType::Condition; - for child in while_loop.to_untyped().children() { - if child.kind() == SyntaxKind::While { - doc = doc.append(BoxDoc::text("while")); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::BlockComment { - doc = doc.append(trivia(child)); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::LineComment { - doc = doc.append(trivia(child)); - doc = doc.append(BoxDoc::hardline()); - } else if let Some(expr) = child.cast() { - doc = doc.append(self.convert_expr(expr)); - if expr_type == CastType::Condition { - doc = doc.append(BoxDoc::space()); - expr_type = CastType::Body; - } - } - } - doc - } - - fn convert_for<'a>(&'a self, for_loop: ForLoop<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil(); - enum CastType { - Pattern, - Iter, - Body, - } - let mut expr_type = CastType::Pattern; - for child in for_loop.to_untyped().children() { - if child.kind() == SyntaxKind::For { - doc = doc.append(BoxDoc::text("for")); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::In { - doc = doc.append(BoxDoc::text("in")); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::BlockComment { - doc = doc.append(trivia(child)); - doc = doc.append(BoxDoc::space()); - } else if child.kind() == SyntaxKind::LineComment { - doc = doc.append(trivia(child)); - doc = doc.append(BoxDoc::hardline()); - } else { - match expr_type { - CastType::Pattern => { - if let Some(pattern) = child.cast() { - doc = doc.append(self.convert_pattern(pattern)); - doc = doc.append(BoxDoc::space()); - expr_type = CastType::Iter; - } - } - CastType::Iter => { - if let Some(iter) = child.cast() { - doc = doc.append(self.convert_expr(iter)); - doc = doc.append(BoxDoc::space()); - expr_type = CastType::Body; - } - } - CastType::Body => { - if let Some(body) = child.cast() { - doc = doc.append(self.convert_expr(body)); - } - } - } - } - } - doc - } - - fn convert_import<'a>(&'a self, import: ModuleImport<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil().append(BoxDoc::text("import")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_expr(import.source())); - if let Some(imports) = import.imports() { - doc = doc.append(BoxDoc::text(":")); - doc = doc.append(BoxDoc::space()); - let imports = match imports { - Imports::Wildcard => BoxDoc::text("*"), - Imports::Items(i) => BoxDoc::intersperse( - i.iter().map(|item| self.convert_import_item(item)), - BoxDoc::text(",").append(BoxDoc::line()), - ), - }; - doc = doc.append(imports.group()); - } - if let Some(new_name) = import.new_name() { - doc = doc.append(BoxDoc::space()); - doc = doc.append(BoxDoc::text("as")); - doc = doc.append(BoxDoc::space()); - doc = doc.append(self.convert_ident(new_name)); - } - doc - } - - fn convert_import_item<'a>(&'a self, import_item: ImportItem<'a>) -> BoxDoc<'a, ()> { - match import_item { - ImportItem::Simple(s) => self.convert_ident(s), - ImportItem::Renamed(r) => self - .convert_ident(r.original_name()) - .append(BoxDoc::space()) - .append(BoxDoc::text("as")) - .append(BoxDoc::space()) - .append(self.convert_ident(r.new_name())), - } - } - - fn convert_include<'a>(&'a self, include: ModuleInclude<'a>) -> BoxDoc<'a, ()> { - BoxDoc::nil() - .append(BoxDoc::text("include")) - .append(BoxDoc::space()) - .append(self.convert_expr(include.source())) - } - - fn convert_break<'a>(&'a self, _break: LoopBreak<'a>) -> BoxDoc<'a, ()> { - BoxDoc::nil().append(BoxDoc::text("break")) - } - - fn convert_continue<'a>(&'a self, _continue: LoopContinue<'a>) -> BoxDoc<'a, ()> { - BoxDoc::nil().append(BoxDoc::text("continue")) - } - - fn convert_return<'a>(&'a self, return_stmt: FuncReturn<'a>) -> BoxDoc<'a, ()> { - let mut doc = BoxDoc::nil() - .append(BoxDoc::text("return")) - .append(BoxDoc::space()); - if let Some(body) = return_stmt.body() { - doc = doc.append(self.convert_expr(body)); - } - doc - } - - fn convert_math_delimited<'a>(&'a self, math_delimited: MathDelimited<'a>) -> BoxDoc<'a, ()> { - let open = self.convert_expr(math_delimited.open()); - let close = self.convert_expr(math_delimited.close()); - let body = self.convert_math(math_delimited.body()); - let singleline = open.clone().append(body.clone()).append(close.clone()); - let multiline = open - .append(BoxDoc::hardline()) - .append(body) - .append(BoxDoc::hardline()) - .nest(2) - .append(close); - multiline.flat_alt(singleline) - } - - fn convert_math_attach<'a>(&'a self, math_attach: MathAttach<'a>) -> BoxDoc<'a, ()> { - let mut doc = self.convert_expr(math_attach.base()); - if let Some(primes) = math_attach.primes() { - doc = doc.append(self.convert_math_primes(primes)); - } - if let Some(bottom) = math_attach.bottom() { - doc = doc.append(BoxDoc::text("_")); - doc = doc.append(self.convert_expr(bottom)); - } - if let Some(top) = math_attach.top() { - doc = doc.append(BoxDoc::text("^")); - doc = doc.append(self.convert_expr(top)); - } - doc - } - - fn convert_math_primes<'a>(&'a self, math_primes: MathPrimes<'a>) -> BoxDoc<'a, ()> { - BoxDoc::text("'".repeat(math_primes.count())) - } - - fn convert_math_frac<'a>(&'a self, math_frac: MathFrac<'a>) -> BoxDoc<'a, ()> { - let singleline = self - .convert_expr(math_frac.num()) - .append(BoxDoc::space()) - .append(BoxDoc::text("/")) - .append(BoxDoc::space()) - .append(self.convert_expr(math_frac.denom())); - // TODO: add multiline version - singleline - } - - fn convert_math_root<'a>(&'a self, math_root: MathRoot<'a>) -> BoxDoc<'a, ()> { - let sqrt_sym = if let Some(index) = math_root.index() { - if index == 3 { - BoxDoc::text("∛") - } else if index == 4 { - BoxDoc::text("∜") - } else { - // TODO: actually unreachable - BoxDoc::text("√") - } - } else { - BoxDoc::text("√") - }; - sqrt_sym.append(self.convert_expr(math_root.radicand())) - } - - fn convert_contextual<'a>(&'a self, ctx: Contextual<'a>) -> BoxDoc<'a, ()> { - let body = self.convert_expr(ctx.body()); - BoxDoc::text("context").append(BoxDoc::space()).append(body) - } -} - -fn trivia(node: &SyntaxNode) -> BoxDoc<'_, ()> { - to_doc(std::borrow::Cow::Borrowed(node.text()), false) -} - -pub fn to_doc(s: Cow<'_, str>, strip_prefix: bool) -> BoxDoc<'_, ()> { - let get_line = |s: &str| { - if strip_prefix { - s.trim_start().to_string() - } else { - s.to_string() - } - }; - BoxDoc::intersperse( - s.lines().map(|s| BoxDoc::text(get_line(s))), - BoxDoc::hardline(), - ) -} +pub use pretty::PrettyPrinter; +pub use prop::get_no_format_nodes; pub fn pretty_print(content: &str, width: usize) -> String { let root = typst_syntax::parse(content); @@ -1017,51 +14,11 @@ pub fn pretty_print(content: &str, width: usize) -> String { doc.pretty(width).to_string() } -#[cfg(test)] -mod tests { - use typst_syntax::parse; - - use super::*; - - #[test] - fn test_to_doc() { - let tests = [ - "command can take a directory as an argument to use as the book", - "123\n456\n789", - "123\n4567\n789\n", - "123\n4568\n789\n", - ]; - for test in tests.into_iter() { - insta::assert_debug_snapshot!(to_doc(test.into(), false)); - } - } - - #[test] - fn convert_markup() { - let tests = [r"=== --open - -When you use the `--open` flag, typst-book will open the rendered book in -your default web browser after building it."]; - for test in tests.into_iter() { - let root = parse(test); - insta::assert_debug_snapshot!(root); - let markup = root.cast().unwrap(); - let printer = PrettyPrinter::default(); - let doc = printer.convert_markup(markup); - insta::assert_debug_snapshot!(doc.pretty(120).to_string()); - } - } +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::prelude::*; - #[test] - fn convert_func_call() { - let tests = [r#"#link("http://example.com")[test]"#]; - for test in tests.into_iter() { - let root = parse(test); - insta::assert_debug_snapshot!(root); - let markup = root.cast().unwrap(); - let printer = PrettyPrinter::default(); - let doc = printer.convert_markup(markup); - insta::assert_debug_snapshot!(doc.pretty(120).to_string()); - } - } +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +pub fn pretty_print_wasm(content: &str, width: usize) -> String { + pretty_print(content, width) } diff --git a/src/pretty.rs b/src/pretty.rs new file mode 100644 index 00000000..e95d1a09 --- /dev/null +++ b/src/pretty.rs @@ -0,0 +1,1054 @@ +use std::borrow::Cow; +use std::collections::HashSet; + +use itertools::Itertools; +use pretty::BoxDoc; +use typst_syntax::{ast, SyntaxNode}; +use typst_syntax::{ast::*, SyntaxKind}; + +use crate::util::{self, pretty_items}; + +#[derive(Debug, Default)] +pub struct PrettyPrinter { + disabled_nodes: HashSet, +} + +impl PrettyPrinter { + pub fn new(disabled_nodes: HashSet) -> Self { + Self { disabled_nodes } + } +} + +impl PrettyPrinter { + pub fn convert_markup<'a>(&'a self, root: Markup<'a>) -> BoxDoc<'a, ()> { + let mut doc: BoxDoc<()> = BoxDoc::nil(); + for node in root.to_untyped().children() { + if let Some(expr) = node.cast::() { + let expr_doc = self.convert_expr(expr); + doc = doc.append(expr_doc); + } else if let Some(space) = node.cast::() { + doc = doc.append(self.convert_space(space)); + } else { + doc = doc.append(trivia(node)); + } + } + doc + } + + fn check_disabled<'a>(&'a self, node: &SyntaxNode) -> Option> { + if self.disabled_nodes.contains(node) { + Some(self.format_disabled(node)) + } else { + None + } + } + + fn format_disabled<'a>(&'a self, node: &SyntaxNode) -> BoxDoc<'a, ()> { + let doc: BoxDoc<()> = BoxDoc::text(node.clone().into_text().to_string()); + doc + } + + fn convert_expr<'a>(&'a self, expr: Expr<'a>) -> BoxDoc<'a, ()> { + if let Some(res) = self.check_disabled(expr.to_untyped()) { + return res; + } + match expr { + ast::Expr::Text(t) => self.convert_text(t), + ast::Expr::Space(s) => self.convert_space(s), + ast::Expr::Linebreak(b) => self.convert_linebreak(b), + ast::Expr::Parbreak(b) => self.convert_parbreak(b), + ast::Expr::Escape(e) => self.convert_escape(e), + ast::Expr::Shorthand(s) => self.convert_shorthand(s), + ast::Expr::SmartQuote(s) => self.convert_smart_quote(s), + ast::Expr::Strong(s) => self.convert_strong(s), + ast::Expr::Emph(e) => self.convert_emph(e), + ast::Expr::Raw(r) => self.convert_raw(r), + ast::Expr::Link(l) => self.convert_link(l), + ast::Expr::Label(l) => self.convert_label(l), + ast::Expr::Ref(r) => self.convert_ref(r), + ast::Expr::Heading(h) => self.convert_heading(h), + ast::Expr::List(l) => self.convert_list_item(l), + ast::Expr::Enum(e) => self.convert_enum_item(e), + ast::Expr::Term(t) => self.convert_term_item(t), + ast::Expr::Equation(e) => self.convert_equation(e), + ast::Expr::Math(m) => self.convert_math(m), + ast::Expr::MathIdent(mi) => trivia(mi.to_untyped()), + ast::Expr::MathAlignPoint(map) => trivia(map.to_untyped()), + ast::Expr::MathDelimited(md) => self.convert_math_delimited(md), + ast::Expr::MathAttach(ma) => self.convert_math_attach(ma), + ast::Expr::MathPrimes(mp) => self.convert_math_primes(mp), + ast::Expr::MathFrac(mf) => self.convert_math_frac(mf), + ast::Expr::MathRoot(mr) => self.convert_math_root(mr), + ast::Expr::Ident(i) => self.convert_ident(i), + ast::Expr::None(n) => self.convert_none(n), + ast::Expr::Auto(a) => self.convert_auto(a), + ast::Expr::Bool(b) => self.convert_bool(b), + ast::Expr::Int(i) => self.convert_int(i), + ast::Expr::Float(f) => self.convert_float(f), + ast::Expr::Numeric(n) => self.convert_numeric(n), + ast::Expr::Str(s) => self.convert_str(s), + ast::Expr::Code(c) => self.convert_code_block(c), + ast::Expr::Content(c) => self.convert_content_block(c), + ast::Expr::Parenthesized(p) => self.convert_parenthesized(p), + ast::Expr::Array(a) => self.convert_array(a), + ast::Expr::Dict(d) => self.convert_dict(d), + ast::Expr::Unary(u) => self.convert_unary(u), + ast::Expr::Binary(b) => self.convert_binary(b), + ast::Expr::FieldAccess(fa) => self.convert_field_access(fa), + ast::Expr::FuncCall(fc) => self.convert_func_call(fc), + ast::Expr::Closure(c) => self.convert_closure(c), + ast::Expr::Let(l) => self.convert_let_binding(l), + ast::Expr::DestructAssign(da) => self.convert_destruct_assignment(da), + ast::Expr::Set(s) => self.convert_set_rule(s), + ast::Expr::Show(s) => self.convert_show_rule(s), + ast::Expr::Conditional(c) => self.convert_conditional(c), + ast::Expr::While(w) => self.convert_while(w), + ast::Expr::For(f) => self.convert_for(f), + ast::Expr::Import(i) => self.convert_import(i), + ast::Expr::Include(i) => self.convert_include(i), + ast::Expr::Break(b) => self.convert_break(b), + ast::Expr::Continue(c) => self.convert_continue(c), + ast::Expr::Return(r) => self.convert_return(r), + ast::Expr::Contextual(c) => self.convert_contextual(c), + } + .group() + } + + fn convert_text<'a>(&'a self, text: Text<'a>) -> BoxDoc<'a, ()> { + let node = text.to_untyped(); + trivia(node) + } + + fn convert_space<'a>(&'a self, space: Space<'a>) -> BoxDoc<'a, ()> { + let node = space.to_untyped(); + if node.text().contains('\n') { + BoxDoc::hardline() + } else { + BoxDoc::space() + } + } + + fn convert_linebreak<'a>(&'a self, linebreak: Linebreak<'a>) -> BoxDoc<'a, ()> { + let node = linebreak.to_untyped(); + trivia(node) + } + + fn convert_parbreak<'a>(&'a self, _parbreak: Parbreak<'a>) -> BoxDoc<'a, ()> { + BoxDoc::hardline().append(BoxDoc::hardline()) + } + + fn convert_escape<'a>(&'a self, escape: Escape<'a>) -> BoxDoc<'a, ()> { + let node = escape.to_untyped(); + trivia(node) + } + + fn convert_shorthand<'a>(&'a self, shorthand: Shorthand<'a>) -> BoxDoc<'a, ()> { + let node = shorthand.to_untyped(); + trivia(node) + } + + fn convert_smart_quote<'a>(&'a self, smart_quote: SmartQuote<'a>) -> BoxDoc<'a, ()> { + let node = smart_quote.to_untyped(); + trivia(node) + } + + fn convert_strong<'a>(&'a self, strong: Strong<'a>) -> BoxDoc<'a, ()> { + let body = self.convert_markup(strong.body()); + BoxDoc::text("*").append(body).append(BoxDoc::text("*")) + } + + fn convert_emph<'a>(&'a self, emph: Emph<'a>) -> BoxDoc<'a, ()> { + let body = self.convert_markup(emph.body()); + BoxDoc::text("_").append(body).append(BoxDoc::text("_")) + } + + fn convert_raw<'a>(&'a self, raw: Raw<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil(); + let is_block = raw.block(); + let has_lang = raw.lang().is_some(); + let mut is_opening = true; + for child in raw.to_untyped().children() { + if let Some(delim) = child.cast::() { + doc = doc.append(trivia(delim.to_untyped())); + if is_block && !has_lang && is_opening { + doc = doc.append(BoxDoc::hardline()); + is_opening = false; + } + } + if let Some(lang) = child.cast::() { + doc = doc.append(trivia(lang.to_untyped())); + doc = doc.append(BoxDoc::hardline()); + } + if let Some(line) = child.cast::() { + doc = doc.append(trivia(line.to_untyped())); + if is_block { + doc = doc.append(BoxDoc::hardline()); + } + } + } + doc + } + + fn convert_link<'a>(&'a self, link: Link<'a>) -> BoxDoc<'a, ()> { + let node = link.to_untyped(); + trivia(node) + } + + fn convert_label<'a>(&'a self, label: Label<'a>) -> BoxDoc<'a, ()> { + let node = label.to_untyped(); + trivia(node) + } + + fn convert_ref<'a>(&'a self, reference: Ref<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::text("@"); + doc = doc.append(BoxDoc::text(reference.target())); + if let Some(supplement) = reference.supplement() { + doc = doc.append(self.convert_content_block(supplement)); + } + doc + } + + fn convert_heading<'a>(&'a self, heading: Heading<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::text("=".repeat(heading.depth().into())); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_markup(heading.body())); + doc + } + + fn convert_list_item<'a>(&'a self, list_item: ListItem<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::text("-"); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_markup(list_item.body()).nest(2)); + doc + } + + fn convert_enum_item<'a>(&'a self, enum_item: EnumItem<'a>) -> BoxDoc<'a, ()> { + let mut doc = if let Some(number) = enum_item.number() { + BoxDoc::text(format!("{number}.")) + } else { + BoxDoc::text("+") + }; + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_markup(enum_item.body()).nest(2)); + doc + } + + fn convert_term_item<'a>(&'a self, term: TermItem<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::text("/"); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_markup(term.term())); + doc = doc.append(BoxDoc::text(":")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_markup(term.description()).nest(2)); + doc + } + + fn convert_equation<'a>(&'a self, equation: Equation<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::text("$"); + if equation.block() { + doc = doc.append(BoxDoc::line()); + } + doc = doc.append(self.convert_math(equation.body()).nest(2)); + if equation.block() { + doc = doc.append(BoxDoc::line()); + } + doc = doc.append(BoxDoc::text("$")); + doc + } + + fn convert_math<'a>(&'a self, math: Math<'a>) -> BoxDoc<'a, ()> { + let mut doc: BoxDoc<()> = BoxDoc::nil(); + for node in math.to_untyped().children() { + if let Some(expr) = node.cast::() { + let expr_doc = self.convert_expr(expr); + doc = doc.append(expr_doc); + } else if let Some(space) = node.cast::() { + doc = doc.append(self.convert_space(space)); + } else { + doc = doc.append(trivia(node)); + } + } + doc + } + + fn convert_ident<'a>(&'a self, ident: Ident<'a>) -> BoxDoc<'a, ()> { + let doc = BoxDoc::nil().append(BoxDoc::text(ident.as_str())); + doc + } + + fn convert_none<'a>(&'a self, _none: None<'a>) -> BoxDoc<'a, ()> { + BoxDoc::nil().append(BoxDoc::text("none")) + } + + fn convert_auto<'a>(&'a self, _auto: Auto<'a>) -> BoxDoc<'a, ()> { + BoxDoc::nil().append(BoxDoc::text("auto")) + } + + fn convert_bool<'a>(&'a self, boolean: Bool<'a>) -> BoxDoc<'a, ()> { + let node = boolean.to_untyped(); + trivia(node) + } + + fn convert_int<'a>(&'a self, int: Int<'a>) -> BoxDoc<'a, ()> { + let node = int.to_untyped(); + trivia(node) + } + + fn convert_float<'a>(&'a self, float: Float<'a>) -> BoxDoc<'a, ()> { + let node = float.to_untyped(); + trivia(node) + } + + fn convert_numeric<'a>(&'a self, numeric: Numeric<'a>) -> BoxDoc<'a, ()> { + let node = numeric.to_untyped(); + trivia(node) + } + + fn convert_str<'a>(&'a self, str: Str<'a>) -> BoxDoc<'a, ()> { + let node = str.to_untyped(); + trivia(node) + } + + fn convert_code_block<'a>(&'a self, code_block: CodeBlock<'a>) -> BoxDoc<'a, ()> { + let mut codes: Vec<_> = vec![]; + for node in code_block.to_untyped().children() { + if let Some(code) = node.cast::() { + let code_doc = self.convert_code(code); + codes.extend(code_doc); + } else if node.kind() == SyntaxKind::LineComment + || node.kind() == SyntaxKind::BlockComment + { + codes.push(to_doc(std::borrow::Cow::Borrowed(node.text()), true)); + } + } + let doc = pretty_items( + &codes, + BoxDoc::text(";").append(BoxDoc::space()), + BoxDoc::nil(), + (BoxDoc::text("{"), BoxDoc::text("}")), + true, + util::FoldStyle::Never, + ); + doc + } + + fn convert_code<'a>(&'a self, code: Code<'a>) -> Vec> { + let mut codes: Vec<_> = vec![]; + for node in code.to_untyped().children() { + if let Some(expr) = node.cast::() { + let expr_doc = self.convert_expr(expr); + codes.push(expr_doc); + } else if node.kind() == SyntaxKind::LineComment + || node.kind() == SyntaxKind::BlockComment + { + codes.push(to_doc(std::borrow::Cow::Borrowed(node.text()), true)); + } else if node.kind() == SyntaxKind::Space { + let newline_cnt = node.text().chars().filter(|c| *c == '\n').count(); + for _ in 0..newline_cnt.saturating_sub(1) { + codes.push(BoxDoc::nil()); + } + } + } + codes + } + + fn convert_content_block<'a>(&'a self, content_block: ContentBlock<'a>) -> BoxDoc<'a, ()> { + let content = self.convert_markup(content_block.body()).group().nest(2); + let doc = BoxDoc::text("[").append(content).append(BoxDoc::text("]")); + doc + } + + fn convert_parenthesized<'a>(&'a self, parenthesized: Parenthesized<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::text("("); + let inner = self.convert_expr(parenthesized.expr()); + let multiline_expr = BoxDoc::line() + .append(inner.clone()) + .append(BoxDoc::line()) + .nest(2) + .group(); + let singleline_expr = inner; + doc = doc.append(multiline_expr.flat_alt(singleline_expr)); + doc = doc.append(BoxDoc::text(")")); + doc + } + + fn convert_array<'a>(&'a self, array: Array<'a>) -> BoxDoc<'a, ()> { + let array_items = array + .items() + .map(|item| self.convert_array_item(item)) + .collect_vec(); + if array_items.len() == 1 { + let singleline = BoxDoc::text("(") + .append(array_items[0].clone()) + .append(BoxDoc::text(",")) + .append(BoxDoc::text(")")); + let multiline = BoxDoc::text("(") + .append( + BoxDoc::hardline() + .append(array_items[0].clone()) + .append(BoxDoc::text(",")) + .nest(2), + ) + .append(BoxDoc::hardline()) + .append(BoxDoc::text(")")) + .group(); + multiline.flat_alt(singleline) + } else { + pretty_items( + &array_items, + BoxDoc::text(",").append(BoxDoc::space()), + BoxDoc::text(","), + (BoxDoc::text("("), BoxDoc::text(")")), + false, + util::FoldStyle::Fit, + ) + } + } + + fn convert_array_item<'a>(&'a self, array_item: ArrayItem<'a>) -> BoxDoc<'a, ()> { + let doc = match array_item { + ArrayItem::Pos(p) => self.convert_expr(p), + ArrayItem::Spread(s) => self.convert_spread(s), + }; + doc + } + + fn convert_dict<'a>(&'a self, dict: Dict<'a>) -> BoxDoc<'a, ()> { + if dict.items().count() == 0 { + return BoxDoc::text("(:)"); + } + let dict_items = dict + .items() + .map(|item| self.convert_dict_item(item)) + .collect_vec(); + pretty_items( + &dict_items, + BoxDoc::text(",").append(BoxDoc::space()), + BoxDoc::text(","), + (BoxDoc::text("("), BoxDoc::text(")")), + false, + util::FoldStyle::Fit, + ) + } + + fn convert_dict_item<'a>(&'a self, dict_item: DictItem<'a>) -> BoxDoc<'a, ()> { + match dict_item { + DictItem::Named(n) => self.convert_named(n), + DictItem::Keyed(k) => self.convert_keyed(k), + DictItem::Spread(s) => self.convert_spread(s), + } + } + + fn convert_named<'a>(&'a self, named: Named<'a>) -> BoxDoc<'a, ()> { + if let Some(res) = self.check_disabled(named.to_untyped()) { + return res; + } + // TODO: better handling hash # + let has_hash = named + .to_untyped() + .children() + .any(|node| matches!(node.kind(), SyntaxKind::Hash)); + let mut doc = self.convert_ident(named.name()); + doc = doc.append(BoxDoc::text(":")); + doc = doc.append(BoxDoc::space()); + if has_hash { + doc = doc.append(BoxDoc::text("#")); + } + doc = doc.append(self.convert_expr(named.expr())); + doc + } + + fn convert_keyed<'a>(&'a self, keyed: Keyed<'a>) -> BoxDoc<'a, ()> { + let mut doc = self.convert_expr(keyed.key()); + doc = doc.append(BoxDoc::text(":")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(keyed.expr())); + doc + } + + fn convert_unary<'a>(&'a self, unary: Unary<'a>) -> BoxDoc<'a, ()> { + let op_text = match unary.op() { + UnOp::Pos => "+", + UnOp::Neg => "-", + UnOp::Not => "not ", + }; + BoxDoc::text(op_text).append(self.convert_expr(unary.expr())) + } + + fn convert_binary<'a>(&'a self, binary: Binary<'a>) -> BoxDoc<'a, ()> { + BoxDoc::nil() + .append(self.convert_expr(binary.lhs())) + .append(BoxDoc::space()) + .append(BoxDoc::text(binary.op().as_str())) + .append(BoxDoc::space()) + .append(self.convert_expr(binary.rhs())) + } + + fn convert_field_access<'a>(&'a self, field_access: FieldAccess<'a>) -> BoxDoc<'a, ()> { + let left = BoxDoc::nil().append(self.convert_expr(field_access.target())); + let singleline_right = BoxDoc::text(".").append(self.convert_ident(field_access.field())); + let _multiline_right = BoxDoc::hardline() + .append(BoxDoc::text(".")) + .append(self.convert_ident(field_access.field())) + .nest(2) + .group(); + // TODO: typst doesn't support this + // left.append(multiline_right.flat_alt(singleline_right)) + left.append(singleline_right) + } + + fn convert_func_call<'a>(&'a self, func_call: FuncCall<'a>) -> BoxDoc<'a, ()> { + let doc = BoxDoc::nil().append(self.convert_expr(func_call.callee())); + if let Some(res) = self.check_disabled(func_call.args().to_untyped()) { + return doc.append(res); + } + let has_parenthesized_args = func_call + .args() + .to_untyped() + .children() + .any(|node| matches!(node.kind(), SyntaxKind::LeftParen | SyntaxKind::RightParen)); + let parenthesized_args = if has_parenthesized_args { + let args = self.convert_parenthesized_args(func_call.args()); + pretty_items( + &args, + BoxDoc::text(",").append(BoxDoc::space()), + BoxDoc::text(","), + (BoxDoc::text("("), BoxDoc::text(")")), + false, + util::FoldStyle::Fit, + ) + } else { + BoxDoc::nil() + }; + let doc = doc + .append(parenthesized_args) + .append(self.convert_additional_args(func_call.args(), has_parenthesized_args)); + doc + } + + fn convert_parenthesized_args<'a>(&'a self, args: Args<'a>) -> Vec> { + let node = args.to_untyped(); + let args = node + .children() + .take_while(|node| node.kind() != SyntaxKind::RightParen) + .filter_map(|node| node.cast::<'_, Arg>()) + .map(|arg| self.convert_arg(arg)) + .collect(); + args + } + + fn convert_additional_args<'a>(&'a self, args: Args<'a>, has_paren: bool) -> BoxDoc<'a, ()> { + let node = args.to_untyped(); + let args = node + .children() + .skip_while(|node| { + if has_paren { + node.kind() != SyntaxKind::RightParen + } else { + node.kind() != SyntaxKind::ContentBlock + } + }) + .filter_map(|node| node.cast::<'_, Arg>()); + BoxDoc::concat(args.map(|arg| self.convert_arg(arg))).group() + } + + fn convert_arg<'a>(&'a self, arg: Arg<'a>) -> BoxDoc<'a, ()> { + match arg { + Arg::Pos(p) => self.convert_expr(p), + Arg::Named(n) => self.convert_named(n), + Arg::Spread(s) => self.convert_spread(s), + } + } + + fn convert_closure<'a>(&'a self, closure: Closure<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil(); + let params = self.convert_params(closure.params()); + let arg_list = pretty_items( + ¶ms, + BoxDoc::text(",").append(BoxDoc::space()), + BoxDoc::text(","), + (BoxDoc::text("("), BoxDoc::text(")")), + false, + util::FoldStyle::Fit, + ); + if let Some(name) = closure.name() { + doc = doc.append(self.convert_ident(name)); + doc = doc.append(arg_list); + doc = doc.append(BoxDoc::space()); + doc = doc.append(BoxDoc::text("=")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(closure.body())); + } else { + if params.len() == 1 + && matches!(closure.params().children().next().unwrap(), Param::Pos(_)) + && !matches!( + closure.params().children().next().unwrap(), + Param::Pos(Pattern::Destructuring(_)) + ) + { + doc = params[0].clone(); + } else { + doc = arg_list + } + doc = doc.append(BoxDoc::space()); + doc = doc.append(BoxDoc::text("=>")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(closure.body())); + } + doc + } + + fn convert_params<'a>(&'a self, params: Params<'a>) -> Vec> { + params + .children() + .map(|param| self.convert_param(param)) + .collect() + } + + fn convert_param<'a>(&'a self, param: Param<'a>) -> BoxDoc<'a, ()> { + match param { + Param::Pos(p) => self.convert_pattern(p), + Param::Named(n) => self.convert_named(n), + Param::Spread(s) => self.convert_spread(s), + } + } + + fn convert_spread<'a>(&'a self, spread: Spread<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::text(".."); + let ident = if let Some(id) = spread.sink_ident() { + self.convert_ident(id) + } else if let Some(expr) = spread.sink_expr() { + self.convert_expr(expr) + } else { + BoxDoc::nil() + }; + doc = doc.append(ident); + doc + } + + fn convert_pattern<'a>(&'a self, pattern: Pattern<'a>) -> BoxDoc<'a, ()> { + match pattern { + Pattern::Normal(n) => self.convert_expr(n), + Pattern::Placeholder(p) => self.convert_underscore(p), + Pattern::Destructuring(d) => self.convert_destructuring(d), + Pattern::Parenthesized(p) => self.convert_parenthesized(p), + } + } + + fn convert_underscore<'a>(&'a self, _underscore: Underscore<'a>) -> BoxDoc<'a, ()> { + BoxDoc::text("_") + } + + fn convert_destructuring<'a>(&'a self, destructuring: Destructuring<'a>) -> BoxDoc<'a, ()> { + BoxDoc::text("(") + .append(BoxDoc::intersperse( + destructuring + .items() + .map(|item| self.convert_destructuring_item(item)), + BoxDoc::text(",").append(BoxDoc::line()), + )) + .append(BoxDoc::text(")")) + } + + fn convert_destructuring_item<'a>( + &'a self, + destructuring_item: DestructuringItem<'a>, + ) -> BoxDoc<'a, ()> { + match destructuring_item { + DestructuringItem::Spread(s) => self.convert_spread(s), + DestructuringItem::Named(n) => self.convert_named(n), + DestructuringItem::Pattern(p) => self.convert_pattern(p), + } + } + + fn convert_let_binding<'a>(&'a self, let_binding: LetBinding<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil() + .append(BoxDoc::text("let")) + .append(BoxDoc::space()); + match let_binding.kind() { + LetBindingKind::Normal(n) => { + doc = doc.append(self.convert_pattern(n).group()); + if let Some(expr) = let_binding.init() { + doc = doc.append(BoxDoc::space()); + doc = doc.append(BoxDoc::text("=")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(expr)); + } + } + LetBindingKind::Closure(_c) => { + if let Some(c) = let_binding.init() { + doc = doc.append(self.convert_expr(c)); + } + } + } + doc + } + + fn convert_destruct_assignment<'a>( + &'a self, + destruct_assign: DestructAssignment<'a>, + ) -> BoxDoc<'a, ()> { + self.convert_pattern(destruct_assign.pattern()) + .append(BoxDoc::space()) + .append(BoxDoc::text("=")) + .append(BoxDoc::space()) + .append(self.convert_expr(destruct_assign.value())) + } + + fn convert_set_rule<'a>(&'a self, set_rule: SetRule<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil() + .append(BoxDoc::text("set")) + .append(BoxDoc::space()); + doc = doc.append(self.convert_expr(set_rule.target())); + doc = doc.append(pretty_items( + &self.convert_parenthesized_args(set_rule.args()), + BoxDoc::text(",").append(BoxDoc::space()), + BoxDoc::text(","), + (BoxDoc::text("("), BoxDoc::text(")")), + false, + util::FoldStyle::Single, + )); + if let Some(condition) = set_rule.condition() { + doc = doc.append(BoxDoc::space()); + doc = doc.append(BoxDoc::text("if")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(condition)); + } + doc + } + + fn convert_show_rule<'a>(&'a self, show_rule: ShowRule<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil().append(BoxDoc::text("show")); + if let Some(selector) = show_rule.selector() { + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(selector)); + } + doc = doc.append(BoxDoc::text(":")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(show_rule.transform())); + doc + } + + fn convert_conditional<'a>(&'a self, conditional: Conditional<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil(); + enum CastType { + Condition, + Then, + Else, + } + let has_else = conditional.else_body().is_some(); + let mut expr_type = CastType::Condition; + for child in conditional.to_untyped().children() { + if child.kind() == SyntaxKind::If { + doc = doc.append(BoxDoc::text("if")); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::Else { + doc = doc.append(BoxDoc::text("else")); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::BlockComment { + doc = doc.append(trivia(child)); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::LineComment { + doc = doc.append(trivia(child)); + doc = doc.append(BoxDoc::hardline()); + } else { + match expr_type { + CastType::Condition => { + if let Some(condition) = child.cast() { + doc = doc.append(self.convert_expr(condition)); + doc = doc.append(BoxDoc::space()); + expr_type = CastType::Then; + } + } + CastType::Then => { + if let Some(then_expr) = child.cast() { + doc = doc.append(self.convert_expr(then_expr).group()); + if has_else { + expr_type = CastType::Else; + doc = doc.append(BoxDoc::space()); + } + } + } + CastType::Else => { + if let Some(else_expr) = child.cast() { + doc = doc.append(self.convert_expr(else_expr).group()); + } + } + } + } + } + doc + } + + fn convert_while<'a>(&'a self, while_loop: WhileLoop<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil(); + #[derive(Debug, PartialEq)] + enum CastType { + Condition, + Body, + } + let mut expr_type = CastType::Condition; + for child in while_loop.to_untyped().children() { + if child.kind() == SyntaxKind::While { + doc = doc.append(BoxDoc::text("while")); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::BlockComment { + doc = doc.append(trivia(child)); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::LineComment { + doc = doc.append(trivia(child)); + doc = doc.append(BoxDoc::hardline()); + } else if let Some(expr) = child.cast() { + doc = doc.append(self.convert_expr(expr)); + if expr_type == CastType::Condition { + doc = doc.append(BoxDoc::space()); + expr_type = CastType::Body; + } + } + } + doc + } + + fn convert_for<'a>(&'a self, for_loop: ForLoop<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil(); + enum CastType { + Pattern, + Iter, + Body, + } + let mut expr_type = CastType::Pattern; + for child in for_loop.to_untyped().children() { + if child.kind() == SyntaxKind::For { + doc = doc.append(BoxDoc::text("for")); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::In { + doc = doc.append(BoxDoc::text("in")); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::BlockComment { + doc = doc.append(trivia(child)); + doc = doc.append(BoxDoc::space()); + } else if child.kind() == SyntaxKind::LineComment { + doc = doc.append(trivia(child)); + doc = doc.append(BoxDoc::hardline()); + } else { + match expr_type { + CastType::Pattern => { + if let Some(pattern) = child.cast() { + doc = doc.append(self.convert_pattern(pattern)); + doc = doc.append(BoxDoc::space()); + expr_type = CastType::Iter; + } + } + CastType::Iter => { + if let Some(iter) = child.cast() { + doc = doc.append(self.convert_expr(iter)); + doc = doc.append(BoxDoc::space()); + expr_type = CastType::Body; + } + } + CastType::Body => { + if let Some(body) = child.cast() { + doc = doc.append(self.convert_expr(body)); + } + } + } + } + } + doc + } + + fn convert_import<'a>(&'a self, import: ModuleImport<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil().append(BoxDoc::text("import")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_expr(import.source())); + if let Some(imports) = import.imports() { + doc = doc.append(BoxDoc::text(":")); + doc = doc.append(BoxDoc::space()); + let imports = match imports { + Imports::Wildcard => BoxDoc::text("*"), + Imports::Items(i) => BoxDoc::intersperse( + i.iter().map(|item| self.convert_import_item(item)), + BoxDoc::text(",").append(BoxDoc::line()), + ), + }; + doc = doc.append(imports.group()); + } + if let Some(new_name) = import.new_name() { + doc = doc.append(BoxDoc::space()); + doc = doc.append(BoxDoc::text("as")); + doc = doc.append(BoxDoc::space()); + doc = doc.append(self.convert_ident(new_name)); + } + doc + } + + fn convert_import_item<'a>(&'a self, import_item: ImportItem<'a>) -> BoxDoc<'a, ()> { + match import_item { + ImportItem::Simple(s) => self.convert_ident(s), + ImportItem::Renamed(r) => self + .convert_ident(r.original_name()) + .append(BoxDoc::space()) + .append(BoxDoc::text("as")) + .append(BoxDoc::space()) + .append(self.convert_ident(r.new_name())), + } + } + + fn convert_include<'a>(&'a self, include: ModuleInclude<'a>) -> BoxDoc<'a, ()> { + BoxDoc::nil() + .append(BoxDoc::text("include")) + .append(BoxDoc::space()) + .append(self.convert_expr(include.source())) + } + + fn convert_break<'a>(&'a self, _break: LoopBreak<'a>) -> BoxDoc<'a, ()> { + BoxDoc::nil().append(BoxDoc::text("break")) + } + + fn convert_continue<'a>(&'a self, _continue: LoopContinue<'a>) -> BoxDoc<'a, ()> { + BoxDoc::nil().append(BoxDoc::text("continue")) + } + + fn convert_return<'a>(&'a self, return_stmt: FuncReturn<'a>) -> BoxDoc<'a, ()> { + let mut doc = BoxDoc::nil() + .append(BoxDoc::text("return")) + .append(BoxDoc::space()); + if let Some(body) = return_stmt.body() { + doc = doc.append(self.convert_expr(body)); + } + doc + } + + fn convert_math_delimited<'a>(&'a self, math_delimited: MathDelimited<'a>) -> BoxDoc<'a, ()> { + let open = self.convert_expr(math_delimited.open()); + let close = self.convert_expr(math_delimited.close()); + let body = self.convert_math(math_delimited.body()); + let singleline = open.clone().append(body.clone()).append(close.clone()); + let multiline = open + .append(BoxDoc::hardline()) + .append(body) + .append(BoxDoc::hardline()) + .nest(2) + .append(close); + multiline.flat_alt(singleline) + } + + fn convert_math_attach<'a>(&'a self, math_attach: MathAttach<'a>) -> BoxDoc<'a, ()> { + let mut doc = self.convert_expr(math_attach.base()); + if let Some(primes) = math_attach.primes() { + doc = doc.append(self.convert_math_primes(primes)); + } + if let Some(bottom) = math_attach.bottom() { + doc = doc.append(BoxDoc::text("_")); + doc = doc.append(self.convert_expr(bottom)); + } + if let Some(top) = math_attach.top() { + doc = doc.append(BoxDoc::text("^")); + doc = doc.append(self.convert_expr(top)); + } + doc + } + + fn convert_math_primes<'a>(&'a self, math_primes: MathPrimes<'a>) -> BoxDoc<'a, ()> { + BoxDoc::text("'".repeat(math_primes.count())) + } + + fn convert_math_frac<'a>(&'a self, math_frac: MathFrac<'a>) -> BoxDoc<'a, ()> { + let singleline = self + .convert_expr(math_frac.num()) + .append(BoxDoc::space()) + .append(BoxDoc::text("/")) + .append(BoxDoc::space()) + .append(self.convert_expr(math_frac.denom())); + // TODO: add multiline version + singleline + } + + fn convert_math_root<'a>(&'a self, math_root: MathRoot<'a>) -> BoxDoc<'a, ()> { + let sqrt_sym = if let Some(index) = math_root.index() { + if index == 3 { + BoxDoc::text("∛") + } else if index == 4 { + BoxDoc::text("∜") + } else { + // TODO: actually unreachable + BoxDoc::text("√") + } + } else { + BoxDoc::text("√") + }; + sqrt_sym.append(self.convert_expr(math_root.radicand())) + } + + fn convert_contextual<'a>(&'a self, ctx: Contextual<'a>) -> BoxDoc<'a, ()> { + let body = self.convert_expr(ctx.body()); + BoxDoc::text("context").append(BoxDoc::space()).append(body) + } +} + +fn trivia(node: &SyntaxNode) -> BoxDoc<'_, ()> { + to_doc(std::borrow::Cow::Borrowed(node.text()), false) +} + +pub fn to_doc(s: Cow<'_, str>, strip_prefix: bool) -> BoxDoc<'_, ()> { + let get_line = |s: &str| { + if strip_prefix { + s.trim_start().to_string() + } else { + s.to_string() + } + }; + BoxDoc::intersperse( + s.lines().map(|s| BoxDoc::text(get_line(s))), + BoxDoc::hardline(), + ) +} + +#[cfg(test)] +mod tests { + use typst_syntax::parse; + + use super::*; + + #[test] + fn test_to_doc() { + let tests = [ + "command can take a directory as an argument to use as the book", + "123\n456\n789", + "123\n4567\n789\n", + "123\n4568\n789\n", + ]; + for test in tests.into_iter() { + insta::assert_debug_snapshot!(to_doc(test.into(), false)); + } + } + + #[test] + fn convert_markup() { + let tests = [r"=== --open + +When you use the `--open` flag, typst-book will open the rendered book in +your default web browser after building it."]; + for test in tests.into_iter() { + let root = parse(test); + insta::assert_debug_snapshot!(root); + let markup = root.cast().unwrap(); + let printer = PrettyPrinter::default(); + let doc = printer.convert_markup(markup); + insta::assert_debug_snapshot!(doc.pretty(120).to_string()); + } + } + + #[test] + fn convert_func_call() { + let tests = [r#"#link("http://example.com")[test]"#]; + for test in tests.into_iter() { + let root = parse(test); + insta::assert_debug_snapshot!(root); + let markup = root.cast().unwrap(); + let printer = PrettyPrinter::default(); + let doc = printer.convert_markup(markup); + insta::assert_debug_snapshot!(doc.pretty(120).to_string()); + } + } +} diff --git a/src/prop.rs b/src/prop.rs index 19c2e960..b063f3fb 100644 --- a/src/prop.rs +++ b/src/prop.rs @@ -1,6 +1,9 @@ use std::collections::HashSet; -use typst_syntax::{ast::{Args, AstNode}, SyntaxKind, SyntaxNode}; +use typst_syntax::{ + ast::{Args, AstNode}, + SyntaxKind, SyntaxNode, +}; pub fn get_no_format_nodes(root: SyntaxNode) -> HashSet { let mut no_format_nodes = HashSet::new(); diff --git a/src/snapshots/typst_geshihua__tests__convert_func_call-2.snap b/src/snapshots/typst_geshihua__pretty__tests__convert_func_call-2.snap similarity index 79% rename from src/snapshots/typst_geshihua__tests__convert_func_call-2.snap rename to src/snapshots/typst_geshihua__pretty__tests__convert_func_call-2.snap index e907e556..1667456b 100644 --- a/src/snapshots/typst_geshihua__tests__convert_func_call-2.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__convert_func_call-2.snap @@ -1,5 +1,5 @@ --- -source: src/lib.rs +source: src/pretty.rs expression: doc.pretty(120).to_string() --- "#link(\"http://example.com\")[test]" diff --git a/src/snapshots/typst_geshihua__tests__convert_func_call.snap b/src/snapshots/typst_geshihua__pretty__tests__convert_func_call.snap similarity index 95% rename from src/snapshots/typst_geshihua__tests__convert_func_call.snap rename to src/snapshots/typst_geshihua__pretty__tests__convert_func_call.snap index 51ab00c9..d0eb8141 100644 --- a/src/snapshots/typst_geshihua__tests__convert_func_call.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__convert_func_call.snap @@ -1,5 +1,5 @@ --- -source: src/lib.rs +source: src/pretty.rs expression: root --- Markup: 33 [ diff --git a/src/snapshots/typst_geshihua__tests__convert_markup-2.snap b/src/snapshots/typst_geshihua__pretty__tests__convert_markup-2.snap similarity index 89% rename from src/snapshots/typst_geshihua__tests__convert_markup-2.snap rename to src/snapshots/typst_geshihua__pretty__tests__convert_markup-2.snap index 25707076..bf8053bb 100644 --- a/src/snapshots/typst_geshihua__tests__convert_markup-2.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__convert_markup-2.snap @@ -1,5 +1,5 @@ --- -source: src/lib.rs +source: src/pretty.rs expression: doc.pretty(120).to_string() --- "=== --open\n\nWhen you use the `--open` flag, typst-book will open the rendered book in\nyour default web browser after building it." diff --git a/src/snapshots/typst_geshihua__tests__convert_markup.snap b/src/snapshots/typst_geshihua__pretty__tests__convert_markup.snap similarity index 95% rename from src/snapshots/typst_geshihua__tests__convert_markup.snap rename to src/snapshots/typst_geshihua__pretty__tests__convert_markup.snap index 72f96299..582f72b8 100644 --- a/src/snapshots/typst_geshihua__tests__convert_markup.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__convert_markup.snap @@ -1,5 +1,5 @@ --- -source: src/lib.rs +source: src/pretty.rs expression: root --- Markup: 129 [ diff --git a/src/snapshots/typst_geshihua__tests__to_doc-2.snap b/src/snapshots/typst_geshihua__pretty__tests__to_doc-2.snap similarity index 53% rename from src/snapshots/typst_geshihua__tests__to_doc-2.snap rename to src/snapshots/typst_geshihua__pretty__tests__to_doc-2.snap index c01b17d8..13429383 100644 --- a/src/snapshots/typst_geshihua__tests__to_doc-2.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__to_doc-2.snap @@ -1,6 +1,6 @@ --- -source: src/lib.rs -expression: to_doc(test.into()) +source: src/pretty.rs +expression: "to_doc(test.into(), false)" --- [ "123", diff --git a/src/snapshots/typst_geshihua__tests__to_doc-3.snap b/src/snapshots/typst_geshihua__pretty__tests__to_doc-3.snap similarity index 54% rename from src/snapshots/typst_geshihua__tests__to_doc-3.snap rename to src/snapshots/typst_geshihua__pretty__tests__to_doc-3.snap index 8b9fa4b2..8e4de54c 100644 --- a/src/snapshots/typst_geshihua__tests__to_doc-3.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__to_doc-3.snap @@ -1,6 +1,6 @@ --- -source: src/lib.rs -expression: to_doc(test.into()) +source: src/pretty.rs +expression: "to_doc(test.into(), false)" --- [ "123", diff --git a/src/snapshots/typst_geshihua__tests__to_doc-4.snap b/src/snapshots/typst_geshihua__pretty__tests__to_doc-4.snap similarity index 54% rename from src/snapshots/typst_geshihua__tests__to_doc-4.snap rename to src/snapshots/typst_geshihua__pretty__tests__to_doc-4.snap index b0528d93..664768bb 100644 --- a/src/snapshots/typst_geshihua__tests__to_doc-4.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__to_doc-4.snap @@ -1,6 +1,6 @@ --- -source: src/lib.rs -expression: to_doc(test.into()) +source: src/pretty.rs +expression: "to_doc(test.into(), false)" --- [ "123", diff --git a/src/snapshots/typst_geshihua__tests__to_doc.snap b/src/snapshots/typst_geshihua__pretty__tests__to_doc.snap similarity index 53% rename from src/snapshots/typst_geshihua__tests__to_doc.snap rename to src/snapshots/typst_geshihua__pretty__tests__to_doc.snap index a865131d..7dfb0b2f 100644 --- a/src/snapshots/typst_geshihua__tests__to_doc.snap +++ b/src/snapshots/typst_geshihua__pretty__tests__to_doc.snap @@ -1,5 +1,5 @@ --- -source: src/lib.rs -expression: to_doc(test.into()) +source: src/pretty.rs +expression: "to_doc(test.into(), false)" --- "command can take a directory as an argument to use as the book" diff --git a/src/snapshots/typst_geshihua__util__tests__pretty_items-2.snap b/src/snapshots/typst_geshihua__util__tests__pretty_items-2.snap deleted file mode 100644 index 018987d9..00000000 --- a/src/snapshots/typst_geshihua__util__tests__pretty_items-2.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: src/util.rs -expression: outer.pretty(10).to_string() ---- -[ - 123, - 12345, - 1234, - 1234567, -] diff --git a/src/snapshots/typst_geshihua__util__tests__pretty_items-3.snap b/src/snapshots/typst_geshihua__util__tests__pretty_items-3.snap deleted file mode 100644 index faa1dc26..00000000 --- a/src/snapshots/typst_geshihua__util__tests__pretty_items-3.snap +++ /dev/null @@ -1,5 +0,0 @@ ---- -source: src/util.rs -expression: outer.pretty(80).to_string() ---- -[123, 12345, 1234, 1234567] diff --git a/src/snapshots/typst_geshihua__util__tests__pretty_items.snap b/src/snapshots/typst_geshihua__util__tests__pretty_items.snap deleted file mode 100644 index bff26442..00000000 --- a/src/snapshots/typst_geshihua__util__tests__pretty_items.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: src/util.rs -expression: outer ---- -[ - "{", - "let a = 1;", - "}", -] diff --git a/src/util.rs b/src/util.rs index ba5797ee..0bc279a0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -75,7 +75,7 @@ fn pretty_items_impl<'a>( } else { multi } - }, + } FoldStyle::Never => multi, } } diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/web/index.html b/web/index.html new file mode 100644 index 00000000..666a4d35 --- /dev/null +++ b/web/index.html @@ -0,0 +1,15 @@ + + + + + + + Typst Geshihua + + + +
+ + + + diff --git a/web/package.json b/web/package.json new file mode 100644 index 00000000..47a3fc71 --- /dev/null +++ b/web/package.json @@ -0,0 +1,21 @@ +{ + "name": "typst-geshihua-web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "devDependencies": { + "typescript": "^5.2.2", + "vite": "^5.1.6", + "vite-plugin-wasm": "^3.3.0" + }, + "dependencies": { + "typst_geshihua": "file:../pkg", + "vanjs-core": "^1.5.0-rc.1", + "vite-plugin-top-level-await": "^1.4.1" + } +} diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100644 index 00000000..f5c1e545 --- /dev/null +++ b/web/src/main.ts @@ -0,0 +1,57 @@ +import './style.css' +import { pretty_print_wasm } from "typst_geshihua" +import van from "vanjs-core" +const { div, textarea, input, label, p, a } = van.tags; + +const App = () => { + const input_val = van.state("") + const output = van.state("") + const columns = van.state(80) + van.derive( + () => { + try { + output.val = pretty_print_wasm(input_val.val, columns.val) + } catch (e) { + output.val = e as string + } + } + ) + return div( + p("Powered by ", a({ + href: "https://github.com/Enter-tainer/typst-geshihua" + }, "Typst Geshihua")), + textarea({ + class: "mitex-input", + placeholder: "Put typst code here", + value: input_val, + autofocus: true, + rows: 30, + oninput(event: Event) { + input_val.val = (event.target! as HTMLInputElement).value; + }, + }), + textarea({ + class: "mitex-output", + value: output, + readOnly: true, + placeholder: "Output", + rows: 30, + onfocus: (event: Event) => + (event.target! as HTMLTextAreaElement).select(), + }) + , div(label("Columns: "), + input({ + type: "number", + value: columns, + oninput(event: Event) { + columns.val = parseInt((event.target! as HTMLInputElement).value) + } + }) + ) + ) +} + +const appElement = document.querySelector('#app'); +if (appElement) { + van.add(appElement, App()); +} diff --git a/web/src/style.css b/web/src/style.css new file mode 100644 index 00000000..4fcb8c71 --- /dev/null +++ b/web/src/style.css @@ -0,0 +1,103 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +#app { + max-width: 1280px; + width: 80%; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} + +button:hover { + border-color: #646cff; +} + +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + + a:hover { + color: #747bff; + } + + button { + background-color: #f9f9f9; + } +} + +textarea { + font-family: "Roboto Mono", Menlo, Consolas, monospace; + font-size: 1em; + font-weight: 400; + line-height: 1.5; + padding: 0.6em 1.2em; + margin: 1em; + border-radius: 4px; + border: 1px solid #e0e0e0; + transition: border-color 0.25s; + width: 40%; +} diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/web/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 00000000..75abdef2 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/web/vite.config.mjs b/web/vite.config.mjs new file mode 100644 index 00000000..55a9c94a --- /dev/null +++ b/web/vite.config.mjs @@ -0,0 +1,11 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; +import wasm from "vite-plugin-wasm"; +import topLevelAwait from "vite-plugin-top-level-await"; + +export default defineConfig({ + plugins: [ + wasm(), + topLevelAwait() + ] +}); diff --git a/web/yarn.lock b/web/yarn.lock new file mode 100644 index 00000000..badfa304 --- /dev/null +++ b/web/yarn.lock @@ -0,0 +1,395 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@esbuild/aix-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" + integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== + +"@esbuild/android-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" + integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== + +"@esbuild/android-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" + integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== + +"@esbuild/android-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" + integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== + +"@esbuild/darwin-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" + integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== + +"@esbuild/darwin-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" + integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== + +"@esbuild/freebsd-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" + integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== + +"@esbuild/freebsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" + integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== + +"@esbuild/linux-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" + integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== + +"@esbuild/linux-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" + integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== + +"@esbuild/linux-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" + integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== + +"@esbuild/linux-loong64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" + integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== + +"@esbuild/linux-mips64el@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" + integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== + +"@esbuild/linux-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" + integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== + +"@esbuild/linux-riscv64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" + integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== + +"@esbuild/linux-s390x@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" + integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== + +"@esbuild/linux-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" + integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== + +"@esbuild/netbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" + integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== + +"@esbuild/openbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" + integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== + +"@esbuild/sunos-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" + integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== + +"@esbuild/win32-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" + integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== + +"@esbuild/win32-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" + integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== + +"@esbuild/win32-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" + integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== + +"@rollup/plugin-virtual@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz#17e17eeecb4c9fa1c0a6e72c9e5f66382fddbb82" + integrity sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A== + +"@rollup/rollup-android-arm-eabi@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz#b98786c1304b4ff8db3a873180b778649b5dff2b" + integrity sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg== + +"@rollup/rollup-android-arm64@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz#8833679af11172b1bf1ab7cb3bad84df4caf0c9e" + integrity sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q== + +"@rollup/rollup-darwin-arm64@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz#ef02d73e0a95d406e0eb4fd61a53d5d17775659b" + integrity sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g== + +"@rollup/rollup-darwin-x64@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz#3ce5b9bcf92b3341a5c1c58a3e6bcce0ea9e7455" + integrity sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg== + +"@rollup/rollup-linux-arm-gnueabihf@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz#3d3d2c018bdd8e037c6bfedd52acfff1c97e4be4" + integrity sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ== + +"@rollup/rollup-linux-arm64-gnu@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz#5fc8cc978ff396eaa136d7bfe05b5b9138064143" + integrity sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w== + +"@rollup/rollup-linux-arm64-musl@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz#f2ae7d7bed416ffa26d6b948ac5772b520700eef" + integrity sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw== + +"@rollup/rollup-linux-riscv64-gnu@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz#303d57a328ee9a50c85385936f31cf62306d30b6" + integrity sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA== + +"@rollup/rollup-linux-x64-gnu@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz#f672f6508f090fc73f08ba40ff76c20b57424778" + integrity sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA== + +"@rollup/rollup-linux-x64-musl@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz#d2f34b1b157f3e7f13925bca3288192a66755a89" + integrity sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw== + +"@rollup/rollup-win32-arm64-msvc@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz#8ffecc980ae4d9899eb2f9c4ae471a8d58d2da6b" + integrity sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA== + +"@rollup/rollup-win32-ia32-msvc@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz#a7505884f415662e088365b9218b2b03a88fc6f2" + integrity sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw== + +"@rollup/rollup-win32-x64-msvc@4.13.0": + version "4.13.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz#6abd79db7ff8d01a58865ba20a63cfd23d9e2a10" + integrity sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw== + +"@swc/core-darwin-arm64@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.8.tgz#2fb702e209310c2da2bc712b0757c011b583a60d" + integrity sha512-hhQCffRTgzpTIbngSnC30vV6IJVTI9FFBF954WEsshsecVoCGFiMwazBbrkLG+RwXENTrMhgeREEFh6R3KRgKQ== + +"@swc/core-darwin-x64@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.4.8.tgz#a5bcbec6830800ca8acafbda1944464ca8421804" + integrity sha512-P3ZBw8Jr8rKhY/J8d+6WqWriqngGTgHwtFeJ8MIakQJTbdYbFgXSZxcvDiERg3psbGeFXaUaPI0GO6BXv9k/OQ== + +"@swc/core-linux-arm-gnueabihf@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.8.tgz#0bf6ae3793bbb7dd0e47c3d153350d31b7e63cf9" + integrity sha512-PP9JIJt19bUWhAGcQW6qMwTjZOcMyzkvZa0/LWSlDm0ORYVLmDXUoeQbGD3e0Zju9UiZxyulnpjEN0ZihJgPTA== + +"@swc/core-linux-arm64-gnu@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.8.tgz#8d3d3e698fc243d4a55c01a968b7297547aa6275" + integrity sha512-HvEWnwKHkoVUr5iftWirTApFJ13hGzhAY2CMw4lz9lur2m+zhPviRRED0FCI6T95Knpv7+8eUOr98Z7ctrG6DQ== + +"@swc/core-linux-arm64-musl@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.8.tgz#ace70bbb650ceb70609987c5b07ff34462960b9e" + integrity sha512-kY8+qa7k/dEeBq9p0Hrta18QnJPpsiJvDQSLNaTIFpdM3aEM9zbkshWz8gaX5VVGUEALowCBUWqmzO4VaqM+2w== + +"@swc/core-linux-x64-gnu@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.8.tgz#76e7fb06e5b6a14ed6dbc0fd00743706d022eb02" + integrity sha512-0WWyIw432wpO/zeGblwq4f2YWam4pn8Z/Ig4KzHMgthR/KmiLU3f0Z7eo45eVmq5vcU7Os1zi/Zb65OOt09q/w== + +"@swc/core-linux-x64-musl@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.8.tgz#a6e03fe6207fcb9715250c7af260e5ee1bf43c5a" + integrity sha512-p4yxvVS05rBNCrBaSTa20KK88vOwtg8ifTW7ec/yoab0bD5EwzzB8KbDmLLxE6uziFa0sdjF0dfRDwSZPex37Q== + +"@swc/core-win32-arm64-msvc@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.8.tgz#5daa44087324c49c64fdbb48fdb3aa00218de03b" + integrity sha512-jKuXihxAaqUnbFfvPxtmxjdJfs87F1GdBf33il+VUmSyWCP4BE6vW+/ReDAe8sRNsKyrZ3UH1vI5q1n64csBUA== + +"@swc/core-win32-ia32-msvc@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.8.tgz#0f1186d2d8bf60c12cfe8ac013b8a520fd850f2e" + integrity sha512-O0wT4AGHrX8aBeH6c2ADMHgagAJc5Kf6W48U5moyYDAkkVnKvtSc4kGhjWhe1Yl0sI0cpYh2In2FxvYsb44eWw== + +"@swc/core-win32-x64-msvc@1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.8.tgz#0bf080132a52e332c7c221d1087a311824746d76" + integrity sha512-C2AYc3A2o+ECciqsJWRgIpp83Vk5EaRzHe7ed/xOWzVd0MsWR+fweEsyOjlmzHfpUxJSi46Ak3/BIZJlhZbXbg== + +"@swc/core@^1.3.100": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.4.8.tgz#de859373a01f499ed27744f6848b28bbb977e81c" + integrity sha512-uY2RSJcFPgNOEg12RQZL197LZX+MunGiKxsbxmh22VfVxrOYGRvh4mPANFlrD1yb38CgmW1wI6YgIi8LkIwmWg== + dependencies: + "@swc/counter" "^0.1.2" + "@swc/types" "^0.1.5" + optionalDependencies: + "@swc/core-darwin-arm64" "1.4.8" + "@swc/core-darwin-x64" "1.4.8" + "@swc/core-linux-arm-gnueabihf" "1.4.8" + "@swc/core-linux-arm64-gnu" "1.4.8" + "@swc/core-linux-arm64-musl" "1.4.8" + "@swc/core-linux-x64-gnu" "1.4.8" + "@swc/core-linux-x64-musl" "1.4.8" + "@swc/core-win32-arm64-msvc" "1.4.8" + "@swc/core-win32-ia32-msvc" "1.4.8" + "@swc/core-win32-x64-msvc" "1.4.8" + +"@swc/counter@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/types@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a" + integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw== + +"@types/estree@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +esbuild@^0.19.3: + version "0.19.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" + integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.19.12" + "@esbuild/android-arm" "0.19.12" + "@esbuild/android-arm64" "0.19.12" + "@esbuild/android-x64" "0.19.12" + "@esbuild/darwin-arm64" "0.19.12" + "@esbuild/darwin-x64" "0.19.12" + "@esbuild/freebsd-arm64" "0.19.12" + "@esbuild/freebsd-x64" "0.19.12" + "@esbuild/linux-arm" "0.19.12" + "@esbuild/linux-arm64" "0.19.12" + "@esbuild/linux-ia32" "0.19.12" + "@esbuild/linux-loong64" "0.19.12" + "@esbuild/linux-mips64el" "0.19.12" + "@esbuild/linux-ppc64" "0.19.12" + "@esbuild/linux-riscv64" "0.19.12" + "@esbuild/linux-s390x" "0.19.12" + "@esbuild/linux-x64" "0.19.12" + "@esbuild/netbsd-x64" "0.19.12" + "@esbuild/openbsd-x64" "0.19.12" + "@esbuild/sunos-x64" "0.19.12" + "@esbuild/win32-arm64" "0.19.12" + "@esbuild/win32-ia32" "0.19.12" + "@esbuild/win32-x64" "0.19.12" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss@^8.4.35: + version "8.4.35" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7" + integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +rollup@^4.2.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.0.tgz#dd2ae144b4cdc2ea25420477f68d4937a721237a" + integrity sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.13.0" + "@rollup/rollup-android-arm64" "4.13.0" + "@rollup/rollup-darwin-arm64" "4.13.0" + "@rollup/rollup-darwin-x64" "4.13.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.13.0" + "@rollup/rollup-linux-arm64-gnu" "4.13.0" + "@rollup/rollup-linux-arm64-musl" "4.13.0" + "@rollup/rollup-linux-riscv64-gnu" "4.13.0" + "@rollup/rollup-linux-x64-gnu" "4.13.0" + "@rollup/rollup-linux-x64-musl" "4.13.0" + "@rollup/rollup-win32-arm64-msvc" "4.13.0" + "@rollup/rollup-win32-ia32-msvc" "4.13.0" + "@rollup/rollup-win32-x64-msvc" "4.13.0" + fsevents "~2.3.2" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +typescript@^5.2.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + +"typst_geshihua@file:../pkg": + version "0.11.0-rc1-0" + +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +vanjs-core@^1.5.0-rc.1: + version "1.5.0-rc.1" + resolved "https://registry.yarnpkg.com/vanjs-core/-/vanjs-core-1.5.0-rc.1.tgz#8f0831daf4f65b56c26d1bf1b9a60eb5955bdf71" + integrity sha512-UAyL/uaKa7w9aGUBd8OZs7+46f6bxWhkMMQjms0lbbRNhtVoeDfUBZzdJ9aAGBH8YyQMXRXJwUjAtFhynnKQrQ== + +vite-plugin-top-level-await@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.4.1.tgz#607dfe084157550fa33df18062b99ceea774cd9c" + integrity sha512-hogbZ6yT7+AqBaV6lK9JRNvJDn4/IJvHLu6ET06arNfo0t2IsyCaon7el9Xa8OumH+ESuq//SDf8xscZFE0rWw== + dependencies: + "@rollup/plugin-virtual" "^3.0.2" + "@swc/core" "^1.3.100" + uuid "^9.0.1" + +vite-plugin-wasm@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/vite-plugin-wasm/-/vite-plugin-wasm-3.3.0.tgz#2908ef2529bf8f33f4e549c8c6fda26ad273ca15" + integrity sha512-tVhz6w+W9MVsOCHzxo6SSMSswCeIw4HTrXEi6qL3IRzATl83jl09JVO1djBqPSwfjgnpVHNLYcaMbaDX5WB/pg== + +vite@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.6.tgz#706dae5fab9e97f57578469eef1405fc483943e4" + integrity sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA== + dependencies: + esbuild "^0.19.3" + postcss "^8.4.35" + rollup "^4.2.0" + optionalDependencies: + fsevents "~2.3.3"