diff --git a/.cargo/config.toml b/.cargo/config.toml index bd6886f..c83caff 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,5 @@ -[target.wasm32-unknown-emscripten] -rustflags = ["-C", "link-args=--js-library lib.js -O3 -s MODULARIZE=1 -s EXPORT_NAME=MeowScript -s -s EXPORTED_RUNTIME_METHODS=[FS,intArrayFromString,writeArrayToMemory,_malloc,UTF8ToString]"] \ No newline at end of file +# The interpreter recurses on the stack, so give the WebAssembly build +# more room than the 1 MiB default. Linear memory grows on demand, so the +# cost is reserved address space, not RAM. +[target.wasm32-unknown-unknown] +rustflags = ["-C", "link-arg=-zstack-size=33554432"] diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..39cc72e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.{ts,tsx,js,mjs,json,css,md,yml,yaml}] +indent_size = 2 + +[*.meow] +indent_size = 4 + +[Makefile] +indent_style = tab diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..40149c8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + rust: + name: Interpreter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + targets: wasm32-unknown-unknown + - uses: Swatinem/rust-cache@v2 + - name: Format + run: cargo fmt --all --check + - name: Clippy + run: cargo clippy --workspace --all-targets -- -D warnings + - name: Clippy (wasm) + run: cargo clippy -p meowscript-wasm --target wasm32-unknown-unknown -- -D warnings + - name: Test + run: cargo test --workspace + - name: Generated site tables are up to date + working-directory: site + run: | + node scripts/sync-examples.mjs + node scripts/sync-stdlib.mjs + git diff --exit-code -- src/generated + + site: + name: Site + runs-on: ubuntu-latest + defaults: + run: + working-directory: site + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: site/pnpm-lock.yaml + - run: pnpm install --frozen-lockfile + - run: pnpm typecheck + - run: pnpm lint + - run: pnpm build diff --git a/.gitignore b/.gitignore index ccb5166..92d5234 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target -.vscode \ No newline at end of file +.vscode +.idea +*.tsbuildinfo diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a0487f6..72e6fd2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,49 +1,64 @@ -# Contributing to Meowscript 🐾 +# Contributing to MeowScript -## Getting Started +How the project fits together, and how to change it without breaking anything. -1. **Fork the Repository**: - - Navigate to the [Meowscript GitHub repository](https://github.com/AlenVelocity/MeowScript). - - Click on the "Fork" button in the top right corner to create a copy of the repository in your GitHub account. +## Setup -2. **Clone Your Fork**: - ```bash - git clone https://github.com//MeowScript - cd MeowScript - ``` +You need a Rust toolchain (stable, 1.88 or newer) and, for the site, Node 22 with pnpm. On Windows the GNU toolchain works without Visual Studio: `rustup-init --default-host x86_64-pc-windows-gnu`. -3. **Create a New Branch**: - ```bash - git checkout -b - ``` +```bash +git clone https://github.com/AlenVelocity/MeowScript +cd MeowScript +cargo test --workspace +``` + +## Where things live + +| Path | What | +| --- | --- | +| `crates/meowscript/src/lexer.rs` | text to tokens, with byte spans | +| `crates/meowscript/src/parser.rs` | tokens to AST (`ast.rs`); Pratt parser for operators | +| `crates/meowscript/src/interpreter.rs` | evaluates the AST; control flow travels as `Interrupt` | +| `crates/meowscript/src/value.rs` | runtime values and how they print | +| `crates/meowscript/src/stdlib/` | the prelude and the `nya:` pawckages, one file each | +| `crates/meowscript/src/host.rs` | the `Host` trait: printing, files, sleeping, randomness | +| `crates/meowscript-cli` | the `meowscript` binary | +| `crates/meowscript-wasm` | the browser entry point (`run`, `version`, `keywords`) | +| `examples/` | programs run by the test suite; a `.out` file is a snapshot | +| `site/` | the Next.js playground and docs | + +## Making changes -## Writing Code +**Keywords and syntax.** Add the token in `token.rs` (both `keyword()` and `KEYWORDS`), lex it, parse it, evaluate it, and add a test next to the others in each file. Then add it to the cheat sheet in `site/src/components/CheatSheet.tsx`, the reference in `site/content/docs.md`, and the highlighter's keyword list in `site/src/lib/meowscript-language.ts`. -- Ensure your code adheres to the cat-themed nature of Meowscript, replacing traditional keywords with feline-inspired terms. -- Maintain the paw-some (although not easily readable) syntax of Meowscript. -- Feel free to expand the standard library with more cat-themed functions and utilities. -- Before pushing code, ensure it is well-commented and consistent with the existing code style. +**Built-in functions.** Add a row to the right pawckage's table in `crates/meowscript/src/stdlib/`. The `arity` is checked before your function runs, so indexing `args` inside it is safe. The helpers in `stdlib/mod.rs` (`number`, `string`, `array`, `callable`) pull typed arguments with consistent error messages. Functions that take callbacks call `interp.call(f, args, None)`. The docs site generates its library reference from these tables, so the `doc` string is what people read. -## Submitting Changes +**Examples.** Drop a `.meow` file in `examples/`. Run `UPDATE_SNAPSHOTS=1 cargo test -p meowscript --test examples` to write its `.out` file, then read the `.out` to check it is what you meant. Programs that sleep or read input get a `// test: skip` comment instead. To show it in the playground, add its name to `ORDER` in `site/scripts/sync-examples.mjs`. -1. **Commit Your Changes**: - ```bash - git commit -m "Describe your changes" - ``` +**Error messages.** They start with a cat exclamation chosen by `ErrorKind`, then say what went wrong and, where possible, what to do instead. -2. **Push Your Changes**: - ```bash - git push origin - ``` +**Comments.** Only where the code can't say why. A comment that repeats the function name or the next line gets removed in review. -3. **Open a Pull Request**: - - Navigate to the [Meowscript GitHub repository](https://github.com/AlenVelocity/MeowScript). - - Click on "New Pull Request" and compare your branch to the main Meowscript repository. - - Provide a detailed description of your changes. +## Before you push -## Code Review +```bash +cargo fmt --all +cargo clippy --workspace --all-targets -- -D warnings +cargo clippy -p meowscript-wasm --target wasm32-unknown-unknown -- -D warnings +cargo test --workspace +``` -- Once your pull request is submitted, maintainers and contributors can review your proposed changes and request any necessary modifications. +If you touched the interpreter or the standard library, also refresh what the site ships: -Thank you for contributing to Meowscript! Your efforts help make coding a paw-sitive experience. +```bash +cd site +pnpm build:wasm # needs wasm-pack +pnpm sync # regenerates src/generated/* +pnpm typecheck && pnpm lint && pnpm build ``` + +and commit the results in `site/public/wasm` and `site/src/generated`. CI checks that the generated tables match the code. + +## Pull requests + +Say what changed and why. If it changes the language, show a before and after. diff --git a/Cargo.lock b/Cargo.lock index 1478ea6..fd625e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,1475 +1,234 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "addr2line" -version = "0.20.0" +name = "anstyle" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "time", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "chrono-tz" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", -] - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "cpufeatures" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "encoding_rs" -version = "0.8.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-io", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gimli" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" - -[[package]] -name = "h2" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.2", - "libc", - "windows-sys", -] - -[[package]] -name = "ipnet" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "log" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "meowscript" -version = "0.1.0" -dependencies = [ - "chrono", - "chrono-tz", - "lazy_static", - "pest", - "pest_derive", - "rand", - "reqwest", - "structopt", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.2", - "libc", -] - -[[package]] -name = "object" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl" -version = "0.10.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.26", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parse-zoneinfo" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" -dependencies = [ - "regex", -] - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pest" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" -dependencies = [ - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.26", -] - -[[package]] -name = "pest_meta" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", - "uncased", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" - -[[package]] -name = "reqwest" -version = "0.11.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.37.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys", -] +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] -name = "security-framework" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.173" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f" - -[[package]] -name = "serde_json" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "siphasher" -version = "0.3.10" +name = "bumpalo" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] -name = "slab" -version = "0.4.8" +name = "cfg-if" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", -] +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] -name = "socket2" -version = "0.4.9" +name = "clap" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ - "libc", - "winapi", + "clap_builder", + "clap_derive", ] [[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.26" +name = "clap_builder" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ - "clap", - "lazy_static", - "structopt-derive", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "structopt-derive" -version = "0.4.18" +name = "clap_derive" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" dependencies = [ "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" -dependencies = [ "proc-macro2", "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" -dependencies = [ - "autocfg", - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys", + "syn", ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "clap_lex" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] -name = "thiserror" -version = "1.0.43" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" -dependencies = [ - "thiserror-impl", -] +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "thiserror-impl" -version = "1.0.43" +name = "futures-core" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.26", -] +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] -name = "time" -version = "0.1.45" +name = "futures-task" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] -name = "tinyvec" -version = "1.6.0" +name = "futures-util" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ - "tinyvec_macros", + "futures-core", + "futures-task", + "pin-project-lite", + "slab", ] [[package]] -name = "tinyvec_macros" -version = "0.1.1" +name = "hashbrown" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] -name = "tokio" -version = "1.29.1" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" -dependencies = [ - "autocfg", - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "pin-project-lite", - "socket2", - "windows-sys", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "indexmap" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ - "native-tls", - "tokio", + "equivalent", + "hashbrown", ] [[package]] -name = "tokio-util" -version = "0.7.8" +name = "js-sys" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", + "cfg-if", + "futures-util", + "wasm-bindgen", ] [[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +name = "meowscript" +version = "1.0.0" dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", + "indexmap", ] [[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +name = "meowscript-cli" +version = "1.0.0" dependencies = [ - "once_cell", + "clap", + "meowscript", ] [[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "ucd-trie" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" - -[[package]] -name = "uncased" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" +name = "meowscript-wasm" +version = "1.0.0" dependencies = [ - "version_check", + "js-sys", + "meowscript", + "wasm-bindgen", ] [[package]] -name = "unicode-bidi" -version = "0.3.13" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "unicode-ident" -version = "1.0.11" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] -name = "unicode-normalization" -version = "0.1.22" +name = "proc-macro2" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ - "tinyvec", + "unicode-ident", ] [[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "url" -version = "2.4.0" +name = "quote" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", + "proc-macro2", ] [[package]] -name = "vcpkg" -version = "0.2.15" +name = "rustversion" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] -name = "vec_map" -version = "0.8.2" +name = "slab" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] -name = "version_check" -version = "0.9.4" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "want" -version = "0.3.1" +name = "syn" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" dependencies = [ - "try-lock", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "unicode-ident" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" dependencies = [ "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", "once_cell", - "proc-macro2", - "quote", - "syn 2.0.26", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1477,135 +236,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.26", - "wasm-bindgen-backend", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", + "unicode-ident", ] diff --git a/Cargo.toml b/Cargo.toml index 209d54f..00d07b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,23 @@ -[package] -name = "meowscript" -version = "0.1.0" -edition = "2021" +[workspace] +resolver = "2" +members = [ + "crates/meowscript", + "crates/meowscript-cli", + "crates/meowscript-wasm", +] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace.package] +version = "1.0.0" +edition = "2024" +repository = "https://github.com/AlenVelocity/MeowScript" +rust-version = "1.88" -[dependencies] -pest = "2.1" -pest_derive = "2.1" -rand = "0.8.5" -lazy_static = "1.4.0" -reqwest = { version = "0.11.10", features = ["blocking", "json"] } +[workspace.dependencies] +meowscript = { path = "crates/meowscript", version = "1.0.0" } +indexmap = "2" -[[bin]] -name = "meowscript" -path = "src/main.rs" - -[target.'cfg(not(target_os = "emscripten"))'.dependencies] -structopt = "0.3.23" -chrono = "0.4.19" -chrono-tz = "0.6.0" +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +strip = true diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..38453a1 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,76 @@ +# Design notes for the MeowScript site + +The site at `site/` is a playground first and a landing page second. These notes record the choices so later changes stay consistent. Tokens live in `site/src/app/globals.css`. + +## Brief + +**Subject.** A toy programming language whose keywords are cat puns, with a real tree-walking interpreter written in Rust and compiled to WebAssembly. Its world is terminals, warm fur, yarn, and late-night tinkering. Playful, and still a working tool: the interpreter runs and the errors are specific. + +**Audience.** Developers arriving from GitHub or a tweet with about thirty seconds of curiosity. Mostly on a desktop, sometimes on a phone. They want to see a program run and understand the puns. + +**Job.** Run a MeowScript program and watch the cat answer. Then learn what the keywords mean. + +**Surface.** A working tool with a thin marketing wrapper. The playground sits at the top of the page, not below a hero and feature cards. + +## Plan + +**Color.** Dark only, because it is a code playground and the content is syntax-highlighted code. The neutrals are warm, tinted toward amber like a tabby, rather than blue-grey. + +| Token | Value | Role | +| --- | --- | --- | +| `bg` | `#171310` | page | +| `surface` | `#201a15` | editor, output, code listings | +| `surface-2` | `#2a231c` | inline code, hover rows | +| `line` | `#3b3128` | borders and table rules | +| `text` | `#f1e8d8` | body (15:1 on `bg`) | +| `text-soft` | `#cdbfab` | secondary prose, operators in code | +| `muted` | `#a09078` | labels, hints, comments (5.3:1 on `bg`) | +| `accent` | `#f0a048` | tabby orange: the Run button, the paw marks, keywords, link hover | +| `paw` | `#e9a9bd` | strings in code only | +| `catnip` | `#a7d79c` | numbers and `purrfect`/`clawful`/`mew` in code only | +| `danger` | `#f0846f` | errors in output, the Stop button, the squiggle | + +The accent appears in four places: the primary button, the paw marks, keywords in code, and link hover. Headings and borders stay neutral so it keeps meaning something. + +**Type.** Baloo 2 (700, 800) for headings: rounded and a little chunky, which reads as soft and cat-like without becoming a children's book. Fira Code (400) for body and code, self-hosted. Setting prose in the code font says "everything here is code" and carries the old site's identity forward; ligatures are turned off outside code so prose doesn't get `=>` arrows. Scale: 13 / 14 / 15 / 18 / 24 / 40 (52 on wide screens). + +**Layout.** One left-aligned column, 1120px wide at most, 72 characters for docs prose. Narrow layout first: the editor stacks above the output, and on large screens they sit side by side at 3:2. + +``` +[paw meowscript Docs GitHub] + +The purrfect programming language. . . +One paragraph. . . . + . . +Example [yarn.meow v] Clear [paw Run] ++------------------------------+ +-----------------+ +| editor | | output | +| | | | ++------------------------------+ | Ready v1.0.0 | + +-----------------+ +Cat to human (table) +Batteries, in a bag of nya (package list) +Run it on your own machine +footer +``` + +**Signature.** The output panel's voice. Every line a program prints with `meow` starts with `Meow!`, and the site sets that word in the accent with a small paw in front of it, so the program's output is visibly the cat talking. The status bar speaks the same way: "Playing…" while a program runs, "Purring" when it finishes, "Hissed" when it fails, and an error's cat exclamation ("Hiss!", "Meowch!") is set in the display face. + +**Small jokes, placed once each.** A trail of faint paw prints walks from the headline toward the Run button on wide screens. "purrfect" in the headline carries a spellchecker squiggle, because it is misspelled on purpose. The paw on the logo and on the Run button tilts on hover. The 404 page is headed "Meow-sterious." None of these repeat elsewhere. + +## Checked against the defaults + +No gradients, no centered hero with three cards, no emoji as icons (the paw is one inline SVG, reused by reference), no uppercase letter-spaced labels, no numbered markers, no scroll animations. The one near-default is "dark background with one warm accent"; it stays because the accent is tied to the subject (an orange tabby) and the surfaces are tinted toward it rather than neutral. + +## States + +- Interpreter loading: Run reads "Loading…" and is disabled; the output panel says so. +- Empty output: a faint paw and "Press Run, or Ctrl+Enter in the editor, to hear from the cat." +- Running: Run becomes Stop (outlined, `danger`). Stop terminates the worker and starts a fresh one. +- Error: the interpreter's rendered error, with its caret line, in `danger` and preserved whitespace. +- Worker failed to start: an explanation and a link to the issue tracker. +- Output over 3000 lines: the oldest are trimmed with a note. + +## Motion + +The paw trail fades in once on load, staggered, 240ms per print. Hover tilts on the two paws, 150ms. Button presses nudge one pixel. `scroll-behavior: smooth` for in-page links. All of it is off under `prefers-reduced-motion`. diff --git a/README.md b/README.md index 19b3d8b..5814f15 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,101 @@ -
- -# Meowscript 🐾 -Meowscript is an simple interpurrter inspired buy our feline friends +# MeowScript -
+A small scripting language where the keywords are cat puns. `purrhaps` is if, `pawction` is function, `tail` is return, and every program announces itself with a `meow`. The interpreter is written in Rust and also runs in the browser as WebAssembly. -Try it out [here](https://meowscript.vercel.app/) +Try it at [meowscript.vercel.app](https://meowscript.vercel.app). -## Features +```meow +pawckage "nya:furrball"; -- **Cat inspired keywords**: Meowscript replaces traditional programming keywords with cat-related terms. Like `purrhaps`, `pawction`, `hiss` ect. (Bonus points if you can guess what these ones do) +scratch cats = ["Tom", "Luna", "Salem"]; -- **Paw-some syntax**: Meowscript's syntax is not really designed to be easy to read. But it's fun.. I guess +pawction introduce(cat) { + purrhaps cat == "Salem" { + tail cat + " (a witch's familiar)"; + } + tail cat; +} -- **Adorable standard library**: Meowscript comes with a standard library filled with cat-themed functions and utilities. From `scratch` to `meow`, the standard library adds makes your coding experience much cuter -## Running Locally +fur cat ~ cats { + meow("This is", introduce(cat)); +} +``` -To get started with Meowscript, follow these steps: +``` +Meow! This is Tom +Meow! This is Luna +Meow! This is Salem (a witch's familiar) +``` -1. **Installation**: Clone the repository +## The language in one table + +| Cat | Human | +| --- | --- | +| `scratch x = 1;` | declare | +| `amew x = 2;` | assign (also `amew cat's age = 4;` and `amew arr[0] = 1;`) | +| `pawction f(a, b) { tail a + b; }` | function and return | +| `purrhaps … { } meowtually { }` | if / else (an expression) | +| `furrever { }`, `furrever cond { }` | loop forever, loop while | +| `fur item ~ things { }` | for each (furrballs, whiskers, object keys, or `0..n`) | +| `hiss;` / `continue;` | break / continue | +| `purrfect`, `clawful`, `mew` | true, false, null | +| `furreal x` | typeof: `"number"`, `"whiskers"`, `"furrball"`, … | +| `cat's name`, `cat["name"]` | property access | +| `x ~ things` | membership | +| `pawckage "nya:furrball";` | import a built-in library, or `"./file.meow"` | + +Strings are *whiskers*, arrays are *furrballs*. Operators follow Python's precedence (`6 & 3 == 2` is `(6 & 3) == 2`), only `mew` and `clawful` are falsy, and dividing by zero is an error. The reference is in the [docs](https://meowscript.vercel.app/docs), or at [`site/content/docs.md`](site/content/docs.md). + +Errors point at the problem: -```bash -git clone https://github.com/AlenVelocity/MeowScript -cd MeowScript +``` +Meow-sterious! name error: `cuont` hasn't been `scratch`ed yet; did you mean `count`? + --> toys.meow:3:6 + | + 3 | meow(cuont); + | ^^^^^ ``` -2. **Writing Meowscript Code**: Create a new file with the `.ms` extension and start writing your cueteejnjeejnfkjnwdwnfnqf Meowscript code. +## Install - ```rust - scratch main = pawction () { - scratch x = 10; - scratch y = 5; +With a Rust toolchain: - purrhaps (x > y) { - meow("Meow! x is greater than y!"); - } meowtually { - meow("Meow! x is not greater than y!"); - } - }; +```bash +cargo install --git https://github.com/AlenVelocity/MeowScript meowscript-cli +``` + +``` +meowscript # the REPL +meowscript hello.meow # run a file +meowscript eval "1 + 2" # evaluate a snippet +meowscript packages # what the nya: pawckages contain +``` - main(); - ``` +## Layout -3. **Running Meowscript Code**: For now you have to build your own binary or use cargo to run MeowScript +``` +crates/meowscript the language: lexer, parser, interpreter, standard library +crates/meowscript-cli the `meowscript` binary (runner and REPL) +crates/meowscript-wasm the wasm-bindgen entry point for the browser +examples/ programs; those with a .out file are snapshot-tested +site/ the playground and docs (Next.js) +``` - ``` - cargo run run your_file.meow - ``` +The interpreter reaches the outside world only through a `Host` trait. The CLI gives it a terminal, the tests give it a buffer, and the browser build gives it a callback that posts lines to the page. - > There are 2 'run's 'cause 1st "run" is required by cargo and the 2nd one is for the built binary. This will make much more sense in the future - - You can also try the REPL by just running: - ``` - cargo run - ``` +## Development ---- - -The main purpose of this project was for me to learn/understand rust better so it's not had to see some inconsistencies with my code. Feel free to conttibute and make MeowScript more purrfect +```bash +cargo test --workspace # unit tests, doctests, and every example +cargo run -p meowscript-cli -- examples/yarn.meow +cargo clippy --workspace --all-targets -- -D warnings +cargo fmt --all +``` +For the site, see [site/README.md](site/README.md). After changing the Rust code, run `pnpm build:wasm && pnpm sync` there to refresh the WebAssembly and the generated tables. +The first version of this interpreter is in the git history before the rewrite. This one replaces it with a byte-indexed lexer that records spans, a Pratt parser that reports where it got stuck, an evaluator that returns `Result` instead of error values, and a browser build on stable Rust with wasm-bindgen instead of Emscripten. +## Contributing - +See [CONTRIBUTING.md](CONTRIBUTING.md). Cat puns welcome. diff --git a/crates/meowscript-cli/Cargo.toml b/crates/meowscript-cli/Cargo.toml new file mode 100644 index 0000000..8c94230 --- /dev/null +++ b/crates/meowscript-cli/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "meowscript-cli" +description = "Command line runner and REPL for MeowScript" +version.workspace = true +edition.workspace = true +repository.workspace = true +rust-version.workspace = true + +[[bin]] +name = "meowscript" +path = "src/main.rs" + +[dependencies] +meowscript.workspace = true +# Colour output is left off on purpose: it pulls in `windows-sys`, which +# needs `dlltool` on the windows-gnu toolchain. Everything else in clap's +# default set is kept. +clap = { version = "4", default-features = false, features = [ + "std", + "derive", + "help", + "usage", + "error-context", + "suggestions", +] } diff --git a/crates/meowscript-cli/src/main.rs b/crates/meowscript-cli/src/main.rs new file mode 100644 index 0000000..f6bbdc6 --- /dev/null +++ b/crates/meowscript-cli/src/main.rs @@ -0,0 +1,236 @@ +use clap::{Parser, Subcommand}; +use meowscript::host::NativeHost; +use meowscript::{Interpreter, Value}; +use std::path::PathBuf; +use std::process::ExitCode; + +// The evaluator recurses on the Rust stack, so run it on a thread with room to spare. +const STACK_SIZE: usize = 256 * 1024 * 1024; + +#[derive(Parser)] +#[command( + name = "meowscript", + version, + about = "The purrfect programming language 🐾" +)] +struct Cli { + #[command(subcommand)] + command: Option, + + /// A .meow file to run (same as `meowscript run FILE`). + file: Option, +} + +#[derive(Subcommand)] +enum Command { + /// Run a .meow file. + Run { file: PathBuf }, + /// Evaluate a snippet of MeowScript and print its value. + Eval { code: String }, + /// Start the interactive prompt (the default with no arguments). + Repl, + /// List the built-in `nya:` pawckages and what they contain. + Packages { + /// Print as JSON, for tooling such as the docs site. + #[arg(long)] + json: bool, + }, +} + +fn main() -> ExitCode { + let cli = Cli::parse(); + let command = match (cli.command, cli.file) { + (Some(c), _) => c, + (None, Some(file)) => Command::Run { file }, + (None, None) => Command::Repl, + }; + + let worker = std::thread::Builder::new() + .name("meowscript".into()) + .stack_size(STACK_SIZE) + .spawn(move || match command { + Command::Run { file } => run_file(&file), + Command::Eval { code } => eval(&code), + Command::Repl => repl::start(), + Command::Packages { json } => { + if json { + packages_json(); + } else { + packages(); + } + ExitCode::SUCCESS + } + }) + .expect("spawn interpreter thread"); + + worker.join().unwrap_or(ExitCode::FAILURE) +} + +fn run_file(path: &PathBuf) -> ExitCode { + let source = match std::fs::read_to_string(path) { + Ok(s) => s, + Err(e) => { + eprintln!("Scratched! could not read `{}`: {e}", path.display()); + return ExitCode::FAILURE; + } + }; + let mut interp = Interpreter::new(NativeHost); + interp.set_base_dir(path.parent().map(|p| p.to_string_lossy().into_owned())); + match interp.run(&source) { + Ok(_) => ExitCode::SUCCESS, + Err(e) => { + eprintln!("{}", e.render(&source, Some(&path.display().to_string()))); + ExitCode::FAILURE + } + } +} + +fn eval(code: &str) -> ExitCode { + let mut interp = Interpreter::new(NativeHost); + match interp.run(code) { + Ok(Value::Null) => ExitCode::SUCCESS, + Ok(value) => { + println!("{}", value.repr()); + ExitCode::SUCCESS + } + Err(e) => { + eprintln!("{}", e.render(code, None)); + ExitCode::FAILURE + } + } +} + +fn packages() { + println!("Always available:"); + for b in meowscript::stdlib::PRELUDE { + println!(" {:<14} {}", b.name, b.doc); + } + for pkg in meowscript::stdlib::PACKAGES { + println!("\npawckage \"{}\"; {}", pkg.name, pkg.doc); + for b in pkg.builtins { + println!(" {:<14} {}", b.name, b.doc); + } + for (name, _) in pkg.constants { + println!(" {:<14} constant", name); + } + } +} + +// Hand-rolled so the binary doesn't need a JSON crate; the shape is small and stable. +fn packages_json() { + fn quote(s: &str) -> String { + let mut out = String::with_capacity(s.len() + 2); + out.push('"'); + for c in s.chars() { + match c { + '"' => out.push_str("\\\""), + '\\' => out.push_str("\\\\"), + '\n' => out.push_str("\\n"), + c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)), + c => out.push(c), + } + } + out.push('"'); + out + } + fn builtin(b: &meowscript::value::Builtin) -> String { + format!( + "{{\"name\":{},\"arity\":{},\"doc\":{}}}", + quote(b.name), + quote(&b.arity.describe()), + quote(b.doc) + ) + } + + let prelude: Vec = meowscript::stdlib::PRELUDE.iter().map(builtin).collect(); + let packages: Vec = meowscript::stdlib::PACKAGES + .iter() + .map(|pkg| { + let functions: Vec = pkg.builtins.iter().map(builtin).collect(); + let constants: Vec = pkg + .constants + .iter() + .map(|(name, value)| { + // JSON has no infinity. + let value = if value.is_finite() { + value.to_string() + } else { + quote(&meowscript::value::format_number(*value)) + }; + format!("{{\"name\":{},\"value\":{value}}}", quote(name)) + }) + .collect(); + format!( + "{{\"name\":{},\"doc\":{},\"functions\":[{}],\"constants\":[{}]}}", + quote(pkg.name), + quote(pkg.doc), + functions.join(","), + constants.join(",") + ) + }) + .collect(); + println!( + "{{\"version\":{},\"prelude\":[{}],\"packages\":[{}]}}", + quote(meowscript::VERSION), + prelude.join(","), + packages.join(",") + ); +} + +// Unfinished input (an open `{`, say) carries over to the next line. +mod repl { + use super::*; + use std::io::{BufRead, Write}; + + pub fn start() -> ExitCode { + println!( + "MeowScript {}. Type a line to run it. An empty line clears unfinished input; `scram` leaves.", + meowscript::VERSION + ); + let stdin = std::io::stdin(); + let mut stdout = std::io::stdout(); + let mut interp = Interpreter::new(NativeHost); + let mut pending = String::new(); + + loop { + let prompt = if pending.is_empty() { ">> " } else { ".. " }; + let _ = write!(stdout, "{prompt}"); + let _ = stdout.flush(); + + let mut line = String::new(); + match stdin.lock().read_line(&mut line) { + Ok(0) => { + println!("\nBye! 🐾"); + return ExitCode::SUCCESS; + } + Ok(_) => {} + Err(e) => { + eprintln!("could not read input: {e}"); + return ExitCode::FAILURE; + } + } + let line = line.trim_end_matches(['\n', '\r']); + + if line.trim().is_empty() { + pending.clear(); + continue; + } + if pending.is_empty() && line.trim() == "scram" { + println!("Bye! 🐾"); + return ExitCode::SUCCESS; + } + if !pending.is_empty() { + pending.push('\n'); + } + pending.push_str(line); + + match interp.run(&pending) { + Ok(Value::Null) => {} + Ok(value) => println!("{}", value.repr()), + Err(e) if e.incomplete => continue, + Err(e) => eprintln!("{}", e.render(&pending, None)), + } + pending.clear(); + } + } +} diff --git a/crates/meowscript-wasm/Cargo.toml b/crates/meowscript-wasm/Cargo.toml new file mode 100644 index 0000000..a5e94a6 --- /dev/null +++ b/crates/meowscript-wasm/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "meowscript-wasm" +description = "MeowScript compiled to WebAssembly for the browser playground" +version.workspace = true +edition.workspace = true +repository.workspace = true +rust-version.workspace = true +publish = false + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +meowscript.workspace = true +wasm-bindgen = "0.2" +js-sys = "0.3" + +# Rust emits bulk-memory and non-trapping float-to-int instructions by +# default now; the wasm-opt that wasm-pack downloads must be told to allow them. +[package.metadata.wasm-pack.profile.release] +wasm-opt = ["-O3", "--enable-bulk-memory", "--enable-nontrapping-float-to-int", "--enable-sign-ext", "--enable-mutable-globals"] diff --git a/crates/meowscript-wasm/src/lib.rs b/crates/meowscript-wasm/src/lib.rs new file mode 100644 index 0000000..42d3522 --- /dev/null +++ b/crates/meowscript-wasm/src/lib.rs @@ -0,0 +1,68 @@ +//! Browser entry point, built with `wasm-pack build --target web`. The playground calls `run` +//! from a Web Worker so an endless loop can be stopped by terminating the worker. + +use meowscript::{Host, Interpreter}; +use wasm_bindgen::prelude::*; + +struct JsHost { + on_output: js_sys::Function, +} + +impl Host for JsHost { + fn print(&mut self, line: &str) { + let _ = self + .on_output + .call1(&JsValue::NULL, &JsValue::from_str(line)); + } + + // Workers have no blocking sleep. Spinning is fine off the main thread, and output already + // posted keeps flowing. + fn sleep(&mut self, millis: f64) { + let end = js_sys::Date::now() + millis; + while js_sys::Date::now() < end { + std::hint::spin_loop(); + } + } + + fn now_millis(&mut self) -> f64 { + js_sys::Date::now() + } + + fn read_line(&mut self, _prompt: &str) -> meowscript::Result { + Err(meowscript::Error::io( + "`kibble` can't read input in the browser playground yet", + )) + } + + fn random_seed(&mut self) -> u64 { + let time = js_sys::Date::now() as u64; + let noise = (js_sys::Math::random() * (1u64 << 53) as f64) as u64; + time.rotate_left(17) ^ noise + } +} + +/// Calls `on_output` once per printed line. Rejects with the rendered error text on failure. +#[wasm_bindgen] +pub fn run(source: &str, on_output: &js_sys::Function) -> Result<(), JsValue> { + let host = JsHost { + on_output: on_output.clone(), + }; + let mut interp = Interpreter::new(host); + interp + .run(source) + .map(|_| ()) + .map_err(|e| JsValue::from_str(&e.render(source, None))) +} + +#[wasm_bindgen] +pub fn version() -> String { + meowscript::VERSION.to_string() +} + +#[wasm_bindgen] +pub fn keywords() -> Vec { + meowscript::token::TokenKind::KEYWORDS + .iter() + .map(|k| k.to_string()) + .collect() +} diff --git a/crates/meowscript/Cargo.toml b/crates/meowscript/Cargo.toml new file mode 100644 index 0000000..af5a754 --- /dev/null +++ b/crates/meowscript/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "meowscript" +description = "The purrfect programming language: a cat-themed scripting language and its interpreter" +version.workspace = true +edition.workspace = true +repository.workspace = true +rust-version.workspace = true + +[dependencies] +indexmap.workspace = true + +[dev-dependencies] diff --git a/crates/meowscript/src/ast.rs b/crates/meowscript/src/ast.rs new file mode 100644 index 0000000..5be9825 --- /dev/null +++ b/crates/meowscript/src/ast.rs @@ -0,0 +1,223 @@ +use crate::span::Span; +use std::fmt; +use std::rc::Rc; + +#[derive(Clone, Debug, PartialEq)] +pub struct Program { + pub stmts: Vec, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Block { + pub stmts: Vec, + pub span: Span, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Ident { + pub name: Rc, + pub span: Span, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Stmt { + pub kind: StmtKind, + pub span: Span, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum StmtKind { + Let { + name: Ident, + value: Expr, + }, + /// `target` is an `Ident`, `Index`, or `Member` expression; the parser checks. + Assign { + target: Expr, + value: Expr, + }, + Return { + value: Option, + }, + Import { + path: String, + span: Span, + }, + Break, + Continue, + FnDecl { + name: Ident, + func: Rc, + }, + Loop { + cond: Option, + body: Block, + }, + ForIn { + var: Ident, + iter: Expr, + body: Block, + }, + Expr(Expr), +} + +/// Shared through `Rc` so closures don't clone the body on every evaluation of a `pawction` expression. +#[derive(Clone, Debug, PartialEq)] +pub struct FuncDef { + pub name: Option>, + pub params: Vec, + pub body: Block, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Expr { + pub kind: ExprKind, + pub span: Span, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum ExprKind { + Null, + Bool(bool), + Number(f64), + Str(Rc), + Ident(Rc), + Array(Vec), + Object(Vec<(Expr, Expr)>), + Unary { + op: UnaryOp, + operand: Box, + }, + Binary { + op: BinaryOp, + left: Box, + right: Box, + }, + If { + cond: Box, + then: Block, + otherwise: Option>, + }, + Function(Rc), + Call { + callee: Box, + args: Vec, + }, + Index { + object: Box, + index: Box, + }, + Member { + object: Box, + name: Ident, + }, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Else { + If(Expr), + Block(Block), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum UnaryOp { + Neg, + Not, + Typeof, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum BinaryOp { + Add, + Sub, + Mul, + Div, + Rem, + Eq, + NotEq, + Lt, + Gt, + LtEq, + GtEq, + BitAnd, + BitOr, + BitXor, + Shl, + Shr, + And, + Or, + In, +} + +impl BinaryOp { + /// Left and right binding powers. Right is one higher so every operator is left-associative. + pub fn binding_power(self) -> (u8, u8) { + use BinaryOp::*; + let base = match self { + Or => 1, + And => 3, + Eq | NotEq => 5, + Lt | Gt | LtEq | GtEq | In => 7, + BitOr => 9, + BitXor => 11, + BitAnd => 13, + Shl | Shr => 15, + Add | Sub => 17, + Mul | Div | Rem => 19, + }; + (base, base + 1) + } + + pub fn symbol(self) -> &'static str { + use BinaryOp::*; + match self { + Add => "+", + Sub => "-", + Mul => "*", + Div => "/", + Rem => "%", + Eq => "==", + NotEq => "!=", + Lt => "<", + Gt => ">", + LtEq => "<=", + GtEq => ">=", + BitAnd => "&", + BitOr => "|", + BitXor => "^", + Shl => "<<", + Shr => ">>", + And => "&&", + Or => "||", + In => "~", + } + } +} + +impl UnaryOp { + pub fn symbol(self) -> &'static str { + match self { + UnaryOp::Neg => "-", + UnaryOp::Not => "!", + UnaryOp::Typeof => "furreal", + } + } +} + +impl fmt::Display for BinaryOp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.symbol()) + } +} + +impl fmt::Display for UnaryOp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.symbol()) + } +} + +impl Expr { + pub fn ends_with_block(&self) -> bool { + matches!(self.kind, ExprKind::If { .. } | ExprKind::Function(_)) + } +} diff --git a/crates/meowscript/src/env.rs b/crates/meowscript/src/env.rs new file mode 100644 index 0000000..30610c2 --- /dev/null +++ b/crates/meowscript/src/env.rs @@ -0,0 +1,112 @@ +//! `scratch` defines in the innermost scope; `amew` updates the nearest scope that has the name. + +use crate::value::Value; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +#[derive(Clone)] +pub struct Env(Rc>); + +struct Scope { + vars: HashMap, Value>, + parent: Option, +} + +impl Default for Env { + fn default() -> Self { + Self::new() + } +} + +impl Env { + pub fn new() -> Env { + Env(Rc::new(RefCell::new(Scope { + vars: HashMap::new(), + parent: None, + }))) + } + + pub fn child(&self) -> Env { + Env(Rc::new(RefCell::new(Scope { + vars: HashMap::new(), + parent: Some(self.clone()), + }))) + } + + pub fn define(&self, name: impl Into>, value: Value) { + self.0.borrow_mut().vars.insert(name.into(), value); + } + + pub fn get(&self, name: &str) -> Option { + let mut current = Some(self.clone()); + while let Some(env) = current { + let scope = env.0.borrow(); + if let Some(v) = scope.vars.get(name) { + return Some(v.clone()); + } + current = scope.parent.clone(); + } + None + } + + pub fn assign(&self, name: &str, value: Value) -> bool { + let mut current = Some(self.clone()); + while let Some(env) = current { + let mut scope = env.0.borrow_mut(); + if let Some(slot) = scope.vars.get_mut(name) { + *slot = value; + return true; + } + current = scope.parent.clone(); + } + false + } + + pub fn has_local(&self, name: &str) -> bool { + self.0.borrow().vars.contains_key(name) + } + + pub fn local_bindings(&self) -> Vec<(Rc, Value)> { + self.0 + .borrow() + .vars + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect() + } + + pub fn visible_names(&self) -> Vec> { + let mut names = Vec::new(); + let mut current = Some(self.clone()); + while let Some(env) = current { + let scope = env.0.borrow(); + names.extend(scope.vars.keys().cloned()); + current = scope.parent.clone(); + } + names + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lookups_fall_through_and_assignments_update_the_owner() { + let global = Env::new(); + global.define("x", Value::from(1.0)); + let inner = global.child(); + assert_eq!(inner.get("x"), Some(Value::from(1.0))); + + inner.define("x", Value::from(2.0)); + assert_eq!(inner.get("x"), Some(Value::from(2.0))); + assert_eq!(global.get("x"), Some(Value::from(1.0))); + + let deeper = inner.child(); + assert!(deeper.assign("x", Value::from(3.0))); + assert_eq!(inner.get("x"), Some(Value::from(3.0))); + assert_eq!(global.get("x"), Some(Value::from(1.0))); + assert!(!deeper.assign("nope", Value::Null)); + } +} diff --git a/crates/meowscript/src/error.rs b/crates/meowscript/src/error.rs new file mode 100644 index 0000000..ea3da34 --- /dev/null +++ b/crates/meowscript/src/error.rs @@ -0,0 +1,153 @@ +use crate::span::{Span, line_text, position}; +use std::fmt; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ErrorKind { + Syntax, + Name, + Type, + Arity, + Import, + Io, + Runtime, +} + +impl ErrorKind { + pub fn label(self) -> &'static str { + match self { + ErrorKind::Syntax => "syntax error", + ErrorKind::Name => "name error", + ErrorKind::Type => "type error", + ErrorKind::Arity => "arity error", + ErrorKind::Import => "import error", + ErrorKind::Io => "io error", + ErrorKind::Runtime => "runtime error", + } + } + + pub fn exclamation(self) -> &'static str { + match self { + ErrorKind::Syntax => "Meowch!", + ErrorKind::Name => "Meow-sterious!", + ErrorKind::Type => "Furbidden!", + ErrorKind::Arity => "Paws off!", + ErrorKind::Import => "Lost kitten!", + ErrorKind::Io => "Scratched!", + ErrorKind::Runtime => "Hiss!", + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Error { + pub kind: ErrorKind, + pub message: String, + pub span: Option, + /// The parser ran out of input mid-construct. The REPL keeps reading lines when it sees this. + pub incomplete: bool, +} + +impl Error { + pub fn new(kind: ErrorKind, message: impl Into) -> Self { + Self { + kind, + message: message.into(), + span: None, + incomplete: false, + } + } + + pub fn syntax(message: impl Into, span: Span) -> Self { + Self::new(ErrorKind::Syntax, message).at(span) + } + + pub fn name(message: impl Into) -> Self { + Self::new(ErrorKind::Name, message) + } + + pub fn type_(message: impl Into) -> Self { + Self::new(ErrorKind::Type, message) + } + + pub fn arity(message: impl Into) -> Self { + Self::new(ErrorKind::Arity, message) + } + + pub fn import(message: impl Into) -> Self { + Self::new(ErrorKind::Import, message) + } + + pub fn io(message: impl Into) -> Self { + Self::new(ErrorKind::Io, message) + } + + pub fn runtime(message: impl Into) -> Self { + Self::new(ErrorKind::Runtime, message) + } + + pub fn at(mut self, span: Span) -> Self { + self.span = Some(span); + self + } + + /// Only fills in a missing span, so the innermost expression keeps its position. + pub fn or_at(mut self, span: Span) -> Self { + self.span.get_or_insert(span); + self + } + + pub fn incomplete(mut self) -> Self { + self.incomplete = true; + self + } + + pub fn render(&self, source: &str, filename: Option<&str>) -> String { + let mut out = self.to_string(); + let Some(span) = self.span else { + return out; + }; + let pos = position(source, span.start); + let line = line_text(source, span.start); + let gutter = pos.line.to_string(); + let pad = " ".repeat(gutter.len()); + let name = filename.unwrap_or(""); + let remaining = line.chars().count().saturating_sub(pos.column - 1).max(1); + let width = span.len().clamp(1, remaining); + out.push_str(&format!( + "\n {pad}--> {name}:{pos}\n {pad} |\n {gutter} | {line}\n {pad} | {caret_pad}{carets}", + caret_pad = " ".repeat(pos.column - 1), + carets = "^".repeat(width), + )); + out + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} {}: {}", + self.kind.exclamation(), + self.kind.label(), + self.message + ) + } +} + +impl std::error::Error for Error {} + +pub type Result = std::result::Result; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn render_points_at_the_span() { + let src = "scratch x = ;"; + let err = Error::syntax("expected an expression, found `;`", Span::new(12, 13)); + let text = err.render(src, Some("test.meow")); + assert!(text.contains("test.meow:1:13"), "{text}"); + assert!(text.ends_with('^'), "{text}"); + } +} diff --git a/crates/meowscript/src/host.rs b/crates/meowscript/src/host.rs new file mode 100644 index 0000000..6c96383 --- /dev/null +++ b/crates/meowscript/src/host.rs @@ -0,0 +1,163 @@ +//! The interpreter reaches the outside world only through a `Host`, which is what lets the same +//! crate run on the command line, in tests, and in a browser. + +use crate::error::{Error, Result}; +use std::cell::RefCell; +use std::rc::Rc; + +pub trait Host { + /// `line` has no trailing newline. + fn print(&mut self, line: &str); + + fn read_line(&mut self, prompt: &str) -> Result { + let _ = prompt; + Err(Error::io("there is no keyboard to read from here")) + } + + fn sleep(&mut self, millis: f64) { + let _ = millis; + } + + fn now_millis(&mut self) -> f64 { + 0.0 + } + + fn read_file(&mut self, path: &str) -> Result { + let _ = path; + Err(Error::io("there is no scratchpad (filesystem) here")) + } + + fn write_file(&mut self, path: &str, contents: &str, append: bool) -> Result<()> { + let _ = (path, contents, append); + Err(Error::io("there is no scratchpad (filesystem) here")) + } + + fn file_exists(&mut self, path: &str) -> bool { + let _ = path; + false + } + + fn random_seed(&mut self) -> u64 { + 0x9E37_79B9_7F4A_7C15 + } +} + +/// Collects output in memory. Clones share the buffer, so keep one and give the other to the +/// interpreter. +#[derive(Clone, Default)] +pub struct BufferHost { + lines: Rc>>, + seed: u64, +} + +impl BufferHost { + pub fn new() -> Self { + Self::default() + } + + pub fn with_seed(seed: u64) -> Self { + Self { + seed, + ..Self::default() + } + } + + pub fn lines(&self) -> Vec { + self.lines.borrow().clone() + } + + pub fn output(&self) -> String { + self.lines.borrow().join("\n") + } + + pub fn take(&self) -> Vec { + std::mem::take(&mut *self.lines.borrow_mut()) + } +} + +impl Host for BufferHost { + fn print(&mut self, line: &str) { + self.lines.borrow_mut().push(line.to_string()); + } + + fn random_seed(&mut self) -> u64 { + self.seed + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub struct NativeHost; + +#[cfg(not(target_arch = "wasm32"))] +impl Host for NativeHost { + fn print(&mut self, line: &str) { + use std::io::Write; + let stdout = std::io::stdout(); + let mut lock = stdout.lock(); + let _ = writeln!(lock, "{line}"); + let _ = lock.flush(); + } + + fn read_line(&mut self, prompt: &str) -> Result { + use std::io::{BufRead, Write}; + let mut stdout = std::io::stdout(); + let _ = write!(stdout, "{prompt}"); + let _ = stdout.flush(); + let mut line = String::new(); + std::io::stdin() + .lock() + .read_line(&mut line) + .map_err(|e| Error::io(format!("could not read input: {e}")))?; + while line.ends_with(['\n', '\r']) { + line.pop(); + } + Ok(line) + } + + fn sleep(&mut self, millis: f64) { + if millis > 0.0 { + std::thread::sleep(std::time::Duration::from_secs_f64(millis / 1000.0)); + } + } + + fn now_millis(&mut self) -> f64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs_f64() * 1000.0) + .unwrap_or(0.0) + } + + fn read_file(&mut self, path: &str) -> Result { + std::fs::read_to_string(path) + .map_err(|e| Error::io(format!("could not read `{path}`: {e}"))) + } + + fn write_file(&mut self, path: &str, contents: &str, append: bool) -> Result<()> { + use std::io::Write; + let mut file = std::fs::OpenOptions::new() + .create(true) + .write(true) + .append(append) + .truncate(!append) + .open(path) + .map_err(|e| Error::io(format!("could not open `{path}`: {e}")))?; + file.write_all(contents.as_bytes()) + .map_err(|e| Error::io(format!("could not write `{path}`: {e}"))) + } + + fn file_exists(&mut self, path: &str) -> bool { + std::path::Path::new(path).exists() + } + + fn random_seed(&mut self) -> u64 { + use std::hash::{BuildHasher, Hasher}; + let mut hasher = std::collections::hash_map::RandomState::new().build_hasher(); + hasher.write_u128( + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_nanos()) + .unwrap_or(0), + ); + hasher.finish() + } +} diff --git a/crates/meowscript/src/interpreter.rs b/crates/meowscript/src/interpreter.rs new file mode 100644 index 0000000..594cc8e --- /dev/null +++ b/crates/meowscript/src/interpreter.rs @@ -0,0 +1,953 @@ +//! Tree-walking evaluator. `tail`, `hiss`, `continue`, and errors travel up through the `Err` +//! side of [`Flow`], so the happy path only deals with values. + +use crate::ast::*; +use crate::env::Env; +use crate::error::{Error, Result}; +use crate::host::Host; +use crate::parser::parse; +use crate::rng::Rng; +use crate::span::Span; +use crate::stdlib; +use crate::value::{Closure, Value, format_number}; +use indexmap::IndexMap; +use std::rc::Rc; + +pub const MAX_CALL_DEPTH: usize = 1000; +const MAX_IMPORT_DEPTH: usize = 32; + +enum Interrupt { + Return(Value), + Break(Span), + Continue(Span), + Error(Error), +} + +impl From for Interrupt { + fn from(e: Error) -> Self { + Interrupt::Error(e) + } +} + +type Flow = std::result::Result; + +pub struct Interpreter { + host: Box, + prelude: Env, + env: Env, + rng: Rng, + call_depth: usize, + import_depth: usize, + base_dir: Option, +} + +impl Interpreter { + pub fn new(host: impl Host + 'static) -> Self { + Self::with_boxed_host(Box::new(host)) + } + + pub fn with_boxed_host(mut host: Box) -> Self { + let seed = host.random_seed(); + let prelude = Env::new(); + stdlib::install_prelude(&prelude); + let env = prelude.child(); + Self { + host, + prelude, + env, + rng: Rng::seeded(seed), + call_depth: 0, + import_depth: 0, + base_dir: None, + } + } + + pub fn host(&mut self) -> &mut dyn Host { + &mut *self.host + } + + pub fn rng(&mut self) -> &mut Rng { + &mut self.rng + } + + pub fn reseed(&mut self, seed: u64) { + self.rng = Rng::seeded(seed); + } + + /// Where relative `pawckage "./file.meow"` paths resolve from. + pub fn set_base_dir(&mut self, dir: Option) { + self.base_dir = dir; + } + + /// Runs in the current global scope, so a REPL can call it repeatedly. Returns the value of + /// the last expression statement. + pub fn run(&mut self, source: &str) -> Result { + let program = parse(source)?; + self.exec_program(&program) + } + + pub fn call(&mut self, callee: Value, args: Vec, span: Option) -> Result { + let attach = |e: Error| match span { + Some(s) => e.or_at(s), + None => e, + }; + match callee { + Value::Builtin(b) => { + if !b.arity.accepts(args.len()) { + return Err(attach(Error::arity(format!( + "`{}` takes {}, but got {}", + b.name, + b.arity.describe(), + args.len() + )))); + } + (b.func)(self, args).map_err(attach) + } + Value::Function(closure) => { + let def = &closure.def; + let name = def + .name + .as_deref() + .map_or("this pawction".to_string(), |n| format!("`{n}`")); + if def.params.len() != args.len() { + let n = def.params.len(); + return Err(attach(Error::arity(format!( + "{name} takes {n} argument{}, but got {}", + if n == 1 { "" } else { "s" }, + args.len() + )))); + } + if self.call_depth >= MAX_CALL_DEPTH { + return Err(attach(Error::runtime(format!( + "pawctions are nested more than {MAX_CALL_DEPTH} calls deep; is there a recursion with no way out?" + )))); + } + let env = closure.env.child(); + for (param, arg) in def.params.iter().zip(args) { + env.define(param.name.clone(), arg); + } + self.call_depth += 1; + let saved = std::mem::replace(&mut self.env, env); + let result = self.exec_stmts(&def.body.stmts); + self.env = saved; + self.call_depth -= 1; + match result { + Ok(v) | Err(Interrupt::Return(v)) => Ok(v), + Err(Interrupt::Error(e)) => Err(e), + Err(Interrupt::Break(s)) => { + Err(Error::runtime("`hiss` only works inside a loop").at(s)) + } + Err(Interrupt::Continue(s)) => { + Err(Error::runtime("`continue` only works inside a loop").at(s)) + } + } + } + other => Err(attach(Error::type_(format!( + "only pawctions can be called, and this is a {}", + other.type_name() + )))), + } + } + + pub fn print(&mut self, line: &str) { + self.host.print(line); + } + + fn exec_program(&mut self, program: &Program) -> Result { + match self.exec_stmts(&program.stmts) { + Ok(v) | Err(Interrupt::Return(v)) => Ok(v), + Err(Interrupt::Error(e)) => Err(e), + Err(Interrupt::Break(s)) => { + Err(Error::runtime("`hiss` only works inside a loop").at(s)) + } + Err(Interrupt::Continue(s)) => { + Err(Error::runtime("`continue` only works inside a loop").at(s)) + } + } + } + + // A block's value is its last statement's, which is how `purrhaps` works as an expression + // and how a pawction returns without `tail`. + fn exec_stmts(&mut self, stmts: &[Stmt]) -> Flow { + let mut last = Value::Null; + for stmt in stmts { + last = self.exec_stmt(stmt)?; + } + Ok(last) + } + + fn exec_block(&mut self, block: &Block) -> Flow { + let child = self.env.child(); + let saved = std::mem::replace(&mut self.env, child); + let result = self.exec_stmts(&block.stmts); + self.env = saved; + result + } + + fn exec_stmt(&mut self, stmt: &Stmt) -> Flow { + match &stmt.kind { + StmtKind::Let { name, value } => { + let v = self.eval(value)?; + self.env.define(name.name.clone(), v); + Ok(Value::Null) + } + StmtKind::Assign { target, value } => { + let v = self.eval(value)?; + self.assign(target, v)?; + Ok(Value::Null) + } + StmtKind::Return { value } => { + let v = match value { + Some(e) => self.eval(e)?, + None => Value::Null, + }; + Err(Interrupt::Return(v)) + } + StmtKind::Import { path, span } => { + self.import(path, *span)?; + Ok(Value::Null) + } + StmtKind::Break => Err(Interrupt::Break(stmt.span)), + StmtKind::Continue => Err(Interrupt::Continue(stmt.span)), + StmtKind::FnDecl { name, func } => { + let closure = Closure { + def: func.clone(), + env: self.env.clone(), + }; + self.env + .define(name.name.clone(), Value::Function(Rc::new(closure))); + Ok(Value::Null) + } + StmtKind::Loop { cond, body } => { + loop { + if let Some(cond) = cond + && !self.eval(cond)?.is_truthy() + { + break; + } + match self.exec_block(body) { + Ok(_) | Err(Interrupt::Continue(_)) => {} + Err(Interrupt::Break(_)) => break, + Err(other) => return Err(other), + } + } + Ok(Value::Null) + } + StmtKind::ForIn { var, iter, body } => { + let iterable = self.eval(iter)?; + let items = self.iterate(&iterable).map_err(|e| e.at(iter.span))?; + for item in items { + let scope = self.env.child(); + scope.define(var.name.clone(), item); + let saved = std::mem::replace(&mut self.env, scope); + let result = self.exec_block(body); + self.env = saved; + match result { + Ok(_) | Err(Interrupt::Continue(_)) => {} + Err(Interrupt::Break(_)) => break, + Err(other) => return Err(other), + } + } + Ok(Value::Null) + } + StmtKind::Expr(expr) => self.eval(expr), + } + } + + fn iterate(&self, value: &Value) -> Result> { + Ok(match value { + Value::Array(items) => items.borrow().clone(), + Value::Str(s) => s.chars().map(|c| Value::str(c.to_string())).collect(), + Value::Object(map) => map.borrow().keys().map(|k| Value::Str(k.clone())).collect(), + Value::Number(n) if *n >= 0.0 && n.fract() == 0.0 => { + (0..*n as u64).map(|i| Value::Number(i as f64)).collect() + } + Value::Number(n) => { + return Err(Error::type_(format!( + "`fur` over a number counts from 0 up to it, so it needs a whole number of at least 0, not {}", + format_number(*n) + ))); + } + other => { + return Err(Error::type_(format!( + "`fur` can walk over a furrball, whiskers, object, or number, not a {}", + other.type_name() + ))); + } + }) + } + + fn assign(&mut self, target: &Expr, value: Value) -> Flow<()> { + match &target.kind { + ExprKind::Ident(name) => { + if self.env.assign(name, value) { + Ok(()) + } else { + Err(Error::name(format!( + "can't `amew {name}` because `{name}` was never `scratch`ed{}", + self.suggestion(name) + )) + .at(target.span) + .into()) + } + } + ExprKind::Index { object, index } => { + let obj = self.eval(object)?; + let idx = self.eval(index)?; + self.set_index(&obj, &idx, value) + .map_err(|e| e.or_at(target.span).into()) + } + ExprKind::Member { object, name } => { + let obj = self.eval(object)?; + let key = Value::Str(name.name.clone()); + self.set_index(&obj, &key, value) + .map_err(|e| e.or_at(target.span).into()) + } + _ => Err(Error::syntax("this can't be assigned to", target.span).into()), + } + } + + fn set_index(&mut self, obj: &Value, index: &Value, value: Value) -> Result<()> { + match (obj, index) { + (Value::Array(items), Value::Number(n)) => { + let mut items = items.borrow_mut(); + let len = items.len(); + let i = array_index(*n, len).ok_or_else(|| out_of_bounds(*n, len))?; + items[i] = value; + Ok(()) + } + (Value::Array(_), other) => Err(Error::type_(format!( + "furrball indexes are numbers, not {}", + other.type_name() + ))), + (Value::Object(map), key) => { + let key = object_key(key)?; + map.borrow_mut().insert(key, value); + Ok(()) + } + (Value::Str(_), _) => Err(Error::type_( + "whiskers can't be changed in place; build a new string with `+` or `replace` instead", + )), + (other, _) => Err(Error::type_(format!( + "can't assign into a {}", + other.type_name() + ))), + } + } + + // Errors with no position yet get this expression's span, so the innermost culprit wins. + fn eval(&mut self, expr: &Expr) -> Flow { + self.eval_inner(expr).map_err(|i| match i { + Interrupt::Error(e) => Interrupt::Error(e.or_at(expr.span)), + other => other, + }) + } + + fn eval_inner(&mut self, expr: &Expr) -> Flow { + Ok(match &expr.kind { + ExprKind::Null => Value::Null, + ExprKind::Bool(b) => Value::Bool(*b), + ExprKind::Number(n) => Value::Number(*n), + ExprKind::Str(s) => Value::Str(s.clone()), + ExprKind::Ident(name) => match self.env.get(name) { + Some(v) => v, + None => { + return Err(Error::name(format!( + "`{name}` hasn't been `scratch`ed yet{}", + self.suggestion(name) + )) + .into()); + } + }, + ExprKind::Array(items) => { + let mut out = Vec::with_capacity(items.len()); + for item in items { + out.push(self.eval(item)?); + } + Value::array(out) + } + ExprKind::Object(entries) => { + let mut map = IndexMap::with_capacity(entries.len()); + for (key, value) in entries { + let k = self.eval(key)?; + let k = object_key(&k).map_err(|e| e.at(key.span))?; + let v = self.eval(value)?; + map.insert(k, v); + } + Value::object(map) + } + ExprKind::Unary { op, operand } => { + let v = self.eval(operand)?; + match op { + UnaryOp::Not => Value::Bool(!v.is_truthy()), + UnaryOp::Typeof => Value::str(v.type_name()), + UnaryOp::Neg => match v { + Value::Number(n) => Value::Number(-n), + other => { + return Err(Error::type_(format!( + "`-` needs a number, not a {}", + other.type_name() + )) + .into()); + } + }, + } + } + ExprKind::Binary { + op: BinaryOp::And, + left, + right, + } => { + let l = self.eval(left)?; + if l.is_truthy() { self.eval(right)? } else { l } + } + ExprKind::Binary { + op: BinaryOp::Or, + left, + right, + } => { + let l = self.eval(left)?; + if l.is_truthy() { l } else { self.eval(right)? } + } + ExprKind::Binary { op, left, right } => { + let l = self.eval(left)?; + let r = self.eval(right)?; + binary(*op, &l, &r)? + } + ExprKind::If { + cond, + then, + otherwise, + } => { + if self.eval(cond)?.is_truthy() { + self.exec_block(then)? + } else { + match otherwise.as_deref() { + Some(Else::If(e)) => self.eval(e)?, + Some(Else::Block(b)) => self.exec_block(b)?, + None => Value::Null, + } + } + } + ExprKind::Function(def) => Value::Function(Rc::new(Closure { + def: def.clone(), + env: self.env.clone(), + })), + ExprKind::Call { callee, args } => { + let f = self.eval(callee)?; + let mut values = Vec::with_capacity(args.len()); + for arg in args { + values.push(self.eval(arg)?); + } + self.call(f, values, Some(expr.span))? + } + ExprKind::Index { object, index } => { + let obj = self.eval(object)?; + let idx = self.eval(index)?; + get_index(&obj, &idx)? + } + ExprKind::Member { object, name } => { + let obj = self.eval(object)?; + get_index(&obj, &Value::Str(name.name.clone()))? + } + }) + } + + fn import(&mut self, path: &str, span: Span) -> Result<()> { + if let Some(name) = path.strip_prefix("nya:") { + let Some(pkg) = stdlib::package(name) else { + let names: Vec<_> = stdlib::PACKAGES + .iter() + .map(|p| format!("`{}`", p.name)) + .collect(); + return Err(Error::import(format!( + "there is no built-in pawckage called `nya:{name}`; the ones I know are {}", + names.join(", ") + )) + .at(span)); + }; + pkg.install(&self.env); + return Ok(()); + } + + if self.import_depth >= MAX_IMPORT_DEPTH { + return Err(Error::import( + "pawckages are importing each other in a circle (or nested absurdly deep)", + ) + .at(span)); + } + + let resolved = self.resolve_path(path); + let source = self.host.read_file(&resolved).map_err(|e| { + Error::import(format!("couldn't load pawckage `{path}`: {}", e.message)).at(span) + })?; + let program = parse(&source).map_err(|e| { + Error::import(format!( + "inside pawckage `{path}`:\n{}", + e.render(&source, Some(&resolved)) + )) + .at(span) + })?; + + let module_env = self.prelude.child(); + let saved_env = std::mem::replace(&mut self.env, module_env.clone()); + let saved_dir = std::mem::replace(&mut self.base_dir, parent_dir(&resolved)); + self.import_depth += 1; + let result = self.exec_program(&program); + self.import_depth -= 1; + self.base_dir = saved_dir; + self.env = saved_env; + result.map_err(|e| { + Error::import(format!( + "inside pawckage `{path}`:\n{}", + e.render(&source, Some(&resolved)) + )) + .at(span) + })?; + + // A module's own `nya:` imports stay private to it. + for (name, value) in module_env.local_bindings() { + if !stdlib::is_package_provided(&name, &value) { + self.env.define(name, value); + } + } + Ok(()) + } + + fn resolve_path(&self, path: &str) -> String { + let mut p = std::path::PathBuf::from(path); + if p.extension().is_none() { + p.set_extension("meow"); + } + if p.is_absolute() { + return p.to_string_lossy().into_owned(); + } + match &self.base_dir { + Some(dir) if !dir.is_empty() => std::path::Path::new(dir) + .join(p) + .to_string_lossy() + .into_owned(), + _ => p.to_string_lossy().into_owned(), + } + } + + fn suggestion(&self, name: &str) -> String { + let mut candidates: Vec> = self.env.visible_names(); + candidates.sort(); + candidates.dedup(); + let best = candidates + .iter() + .map(|c| (edit_distance(name, c), c)) + .filter(|(d, c)| *d <= 2 && c.len() > 1) + .min_by_key(|(d, _)| *d); + match best { + Some((_, c)) => format!("; did you mean `{c}`?"), + None => String::new(), + } + } +} + +fn binary(op: BinaryOp, l: &Value, r: &Value) -> Result { + use BinaryOp::*; + use Value::*; + let v = match (op, l, r) { + (Add, Number(a), Number(b)) => Number(a + b), + (Add, Str(a), _) => Value::str(format!("{a}{r}")), + (Add, _, Str(b)) => Value::str(format!("{l}{b}")), + (Add, Array(a), Array(b)) => { + let mut items = a.borrow().clone(); + items.extend(b.borrow().iter().cloned()); + Value::array(items) + } + (Sub, Number(a), Number(b)) => Number(a - b), + (Mul, Number(a), Number(b)) => Number(a * b), + (Mul, Str(s), Number(n)) | (Mul, Number(n), Str(s)) => { + if *n < 0.0 || n.fract() != 0.0 { + return Err(Error::type_(format!( + "whiskers can be repeated a whole number of times, not {}", + format_number(*n) + ))); + } + Value::str(s.repeat(*n as usize)) + } + (Div, Number(a), Number(b)) => { + if *b == 0.0 { + return Err(Error::runtime("can't divide by zero")); + } + Number(a / b) + } + (Rem, Number(a), Number(b)) => { + if *b == 0.0 { + return Err(Error::runtime( + "can't take the remainder of dividing by zero", + )); + } + Number(a % b) + } + (Eq, _, _) => Bool(l == r), + (NotEq, _, _) => Bool(l != r), + (Lt, Number(a), Number(b)) => Bool(a < b), + (Gt, Number(a), Number(b)) => Bool(a > b), + (LtEq, Number(a), Number(b)) => Bool(a <= b), + (GtEq, Number(a), Number(b)) => Bool(a >= b), + (Lt, Str(a), Str(b)) => Bool(a < b), + (Gt, Str(a), Str(b)) => Bool(a > b), + (LtEq, Str(a), Str(b)) => Bool(a <= b), + (GtEq, Str(a), Str(b)) => Bool(a >= b), + (BitAnd, Number(a), Number(b)) => Number((*a as i64 & *b as i64) as f64), + (BitOr, Number(a), Number(b)) => Number((*a as i64 | *b as i64) as f64), + (BitXor, Number(a), Number(b)) => Number((*a as i64 ^ *b as i64) as f64), + (Shl, Number(a), Number(b)) => Number((*a as i64).wrapping_shl(*b as u32) as f64), + (Shr, Number(a), Number(b)) => Number((*a as i64).wrapping_shr(*b as u32) as f64), + (In, _, Array(items)) => Bool(items.borrow().contains(l)), + (In, _, Object(map)) => Bool(map.borrow().contains_key(&*object_key(l)?)), + (In, Str(needle), Str(hay)) => Bool(hay.contains(&**needle)), + (And | Or, _, _) => unreachable!("short-circuit operators are handled by the evaluator"), + _ => { + return Err(Error::type_(format!( + "`{op}` doesn't work between {} and {}", + article(l.type_name()), + article(r.type_name()) + ))); + } + }; + Ok(v) +} + +fn get_index(obj: &Value, index: &Value) -> Result { + match (obj, index) { + (Value::Array(items), Value::Number(n)) => { + let items = items.borrow(); + array_index(*n, items.len()) + .map(|i| items[i].clone()) + .ok_or_else(|| out_of_bounds(*n, items.len())) + } + (Value::Str(s), Value::Number(n)) => { + let len = s.chars().count(); + array_index(*n, len) + .and_then(|i| s.chars().nth(i)) + .map(|c| Value::str(c.to_string())) + .ok_or_else(|| out_of_bounds(*n, len)) + } + (Value::Object(map), key) => { + let key = object_key(key)?; + Ok(map.borrow().get(&*key).cloned().unwrap_or(Value::Null)) + } + (Value::Array(_) | Value::Str(_), other) => Err(Error::type_(format!( + "{} indexes are numbers, not {}", + obj.type_name(), + article(other.type_name()) + ))), + (other, _) => Err(Error::type_(format!( + "can't index into {}", + article(other.type_name()) + ))), + } +} + +/// Negative indexes count from the end. +pub(crate) fn array_index(n: f64, len: usize) -> Option { + if n.fract() != 0.0 || n.is_nan() { + return None; + } + let i = n as i64; + let i = if i < 0 { i + len as i64 } else { i }; + (0..len as i64).contains(&i).then_some(i as usize) +} + +fn out_of_bounds(n: f64, len: usize) -> Error { + if n.fract() != 0.0 { + Error::type_(format!( + "indexes are whole numbers, not {}", + format_number(n) + )) + } else if len == 0 { + Error::runtime(format!( + "index {} is out of bounds; this one is empty", + format_number(n) + )) + } else { + Error::runtime(format!( + "index {} is out of bounds; valid indexes are 0 to {} (or -1 to -{} from the end)", + format_number(n), + len - 1, + len + )) + } +} + +/// Object keys are always strings; numbers and booleans are converted. +pub(crate) fn object_key(v: &Value) -> Result> { + match v { + Value::Str(s) => Ok(s.clone()), + Value::Number(_) | Value::Bool(_) => Ok(v.to_string().into()), + other => Err(Error::type_(format!( + "object keys are whiskers, not {}", + article(other.type_name()) + ))), + } +} + +fn article(type_name: &str) -> String { + match type_name { + "mew" => "mew".to_string(), + "whiskers" => "whiskers".to_string(), + "object" => "an object".to_string(), + other => format!("a {other}"), + } +} + +fn parent_dir(path: &str) -> Option { + std::path::Path::new(path) + .parent() + .map(|p| p.to_string_lossy().into_owned()) +} + +fn edit_distance(a: &str, b: &str) -> usize { + let a: Vec = a.chars().collect(); + let b: Vec = b.chars().collect(); + let mut prev: Vec = (0..=b.len()).collect(); + let mut cur = vec![0; b.len() + 1]; + for (i, ca) in a.iter().enumerate() { + cur[0] = i + 1; + for (j, cb) in b.iter().enumerate() { + let cost = usize::from(ca != cb); + cur[j + 1] = (prev[j] + cost).min(prev[j + 1] + 1).min(cur[j] + 1); + } + std::mem::swap(&mut prev, &mut cur); + } + prev[b.len()] +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::host::BufferHost; + + fn run(src: &str) -> (Result, Vec) { + let host = BufferHost::new(); + let mut interp = Interpreter::new(host.clone()); + let result = interp.run(src); + (result, host.take()) + } + + fn eval(src: &str) -> Value { + run(src).0.unwrap() + } + + fn output(src: &str) -> Vec { + let (r, lines) = run(src); + r.unwrap(); + lines + } + + fn error(src: &str) -> Error { + run(src).0.unwrap_err() + } + + #[test] + fn arithmetic_and_precedence() { + assert_eq!(eval("1 + 2 * 3"), Value::from(7.0)); + assert_eq!(eval("(1 + 2) * 3"), Value::from(9.0)); + assert_eq!(eval("10 % 3"), Value::from(1.0)); + assert_eq!(eval("-2 * -3"), Value::from(6.0)); + assert_eq!(eval("1 + 2 << 1"), Value::from(6.0)); + assert_eq!(eval("6 & 3 == 2"), Value::from(true)); + } + + #[test] + fn strings_concatenate_with_anything() { + assert_eq!( + eval(r#""a" + 1 + purrfect + mew"#), + Value::from("a1purrfectmew") + ); + assert_eq!(eval(r#""ab" * 3"#), Value::from("ababab")); + assert_eq!(eval(r#""b" > "a""#), Value::from(true)); + } + + #[test] + fn variables_and_scopes() { + assert_eq!(eval("scratch x = 1; amew x = x + 1; x"), Value::from(2.0)); + assert_eq!( + eval("scratch x = 1; purrhaps purrfect { amew x = 5; } x"), + Value::from(5.0) + ); + assert_eq!( + eval("scratch x = 1; purrhaps purrfect { scratch x = 5; } x"), + Value::from(1.0) + ); + let e = error("amew y = 1;"); + assert_eq!(e.kind, crate::error::ErrorKind::Name); + let e = error("scratch count = 1; meow(cuont);"); + assert!(e.message.contains("did you mean `count`"), "{}", e.message); + } + + #[test] + fn functions_closures_and_recursion() { + assert_eq!( + eval("pawction add(a, b) { tail a + b; } add(2, 3)"), + Value::from(5.0) + ); + assert_eq!( + eval("scratch f = pawction(x) { x * 2 }; f(4)"), + Value::from(8.0) + ); + assert_eq!( + eval( + "pawction fib(n) { purrhaps n < 2 { tail n; } tail fib(n - 1) + fib(n - 2); } fib(15)" + ), + Value::from(610.0) + ); + let src = "pawction counter() { scratch n = 0; tail pawction() { amew n = n + 1; tail n; }; } \ + scratch c = counter(); c(); c(); c()"; + assert_eq!(eval(src), Value::from(3.0)); + let e = error("pawction f(a) {} f(1, 2)"); + assert!( + e.message.contains("`f` takes 1 argument, but got 2"), + "{}", + e.message + ); + } + + #[test] + fn deep_recursion_is_an_error_not_a_crash() { + let handle = std::thread::Builder::new() + .stack_size(64 * 1024 * 1024) + .spawn(|| error("pawction down(n) { tail down(n + 1); } down(0)")) + .unwrap(); + let e = handle.join().unwrap(); + assert!(e.message.contains("recursion"), "{}", e.message); + } + + #[test] + fn if_is_an_expression() { + assert_eq!( + eval("purrhaps clawful { 1 } meowtually purrhaps purrfect { 2 } meowtually { 3 }"), + Value::from(2.0) + ); + assert_eq!( + eval("scratch x = purrhaps (1 > 2) { \"big\" } meowtually { \"small\" }; x"), + Value::from("small") + ); + assert_eq!(eval("purrhaps clawful { 1 }"), Value::Null); + } + + #[test] + fn truthiness() { + assert_eq!(eval("!mew"), Value::from(true)); + assert_eq!(eval("!0"), Value::from(false)); + assert_eq!(eval(r#"!"""#), Value::from(false)); + assert_eq!(eval("mew || 3"), Value::from(3.0)); + assert_eq!(eval("1 && 2"), Value::from(2.0)); + assert_eq!(eval("clawful && undefined_name"), Value::from(false)); + } + + #[test] + fn loops() { + assert_eq!( + output( + "scratch i = 0; furrever { purrhaps i == 3 { hiss; } purr(i); amew i = i + 1; }" + ), + vec!["0", "1", "2"] + ); + assert_eq!( + output("scratch i = 0; furrever i < 2 { purr(i); amew i = i + 1; }"), + vec!["0", "1"] + ); + assert_eq!( + output("fur x ~ [1, 2, 3] { purrhaps x == 2 { continue; } purr(x); }"), + vec!["1", "3"] + ); + assert_eq!(output("fur c ~ \"ab\" { purr(c); }"), vec!["a", "b"]); + assert_eq!( + output("fur k ~ { a: 1, b: 2 } { purr(k); }"), + vec!["a", "b"] + ); + assert_eq!(output("fur i ~ 3 { purr(i); }"), vec!["0", "1", "2"]); + assert!(error("hiss;").message.contains("inside a loop")); + assert!( + error("pawction f() { hiss; } furrever { f(); }") + .message + .contains("inside a loop") + ); + } + + #[test] + fn furrballs_are_shared_and_indexable() { + assert_eq!(eval("scratch a = [1, 2, 3]; a[-1]"), Value::from(3.0)); + assert_eq!( + eval("scratch a = [1, 2, 3]; scratch b = a; amew b[0] = 9; a[0]"), + Value::from(9.0) + ); + assert_eq!( + eval("[1, 2] + [3]"), + Value::array(vec![1.0.into(), 2.0.into(), 3.0.into()]) + ); + assert_eq!(eval("2 ~ [1, 2]"), Value::from(true)); + assert_eq!(eval("\"b\"[0]"), Value::from("b")); + let e = error("[1, 2][5]"); + assert!(e.message.contains("out of bounds"), "{}", e.message); + assert!(error("[1][0.5]").message.contains("whole")); + } + + #[test] + fn objects_and_possessives() { + let src = r#"scratch cat = { name: "Tom", "age": 3 }; amew cat's age = 4; cat's age + cat["age"]"#; + assert_eq!(eval(src), Value::from(8.0)); + assert_eq!(eval("scratch o = {}; amew o's x = 1; o"), eval("{ x: 1 }")); + assert_eq!(eval("{ a: 1 }'s missing"), Value::Null); + assert_eq!(eval("\"a\" ~ { a: 1 }"), Value::from(true)); + assert_eq!(eval("scratch n = \"k\"; { [n]: 1 }'s k"), Value::from(1.0)); + assert_eq!(eval("scratch k = 2; { k }"), eval("{ k: 2 }")); + assert_eq!(eval("furreal { }"), Value::from("object")); + } + + #[test] + fn typeof_names() { + assert_eq!(eval("furreal mew"), Value::from("mew")); + assert_eq!(eval("furreal 1"), Value::from("number")); + assert_eq!(eval("furreal \"\""), Value::from("whiskers")); + assert_eq!(eval("furreal []"), Value::from("furrball")); + assert_eq!(eval("furreal purrfect"), Value::from("boolean")); + assert_eq!(eval("furreal pawction() {}"), Value::from("pawction")); + assert_eq!(eval("furreal meow"), Value::from("pawction")); + } + + #[test] + fn meow_prefixes_and_purr_does_not() { + assert_eq!( + output("meow(\"hi\", 1); purr(\"hi\", 1); meow();"), + vec!["Meow! hi 1", "hi 1", "Meow!"] + ); + } + + #[test] + fn errors_carry_positions() { + let src = "scratch x = 1;\nscratch y = x / 0;"; + let e = error(src); + assert_eq!( + e.span.map(|s| crate::span::position(src, s.start).line), + Some(2) + ); + let e = error("meow(nope)"); + assert_eq!(e.span, Some(Span::new(5, 9))); + } + + #[test] + fn packages() { + assert_eq!( + eval("pawckage \"nya:catculator\"; floor(PI)"), + Value::from(3.0) + ); + let e = error("pawckage \"nya:dogs\";"); + assert!(e.message.contains("nya:furrball"), "{}", e.message); + assert!(error("floor(1)").message.contains("hasn't been")); + } + + #[test] + fn return_value_of_a_program_is_its_last_expression() { + assert_eq!(eval("1; 2; scratch x = 3;"), Value::Null); + assert_eq!(eval("1; 2"), Value::from(2.0)); + assert_eq!(eval("tail 7; 8"), Value::from(7.0)); + } +} diff --git a/crates/meowscript/src/lexer.rs b/crates/meowscript/src/lexer.rs new file mode 100644 index 0000000..aa6cc28 --- /dev/null +++ b/crates/meowscript/src/lexer.rs @@ -0,0 +1,432 @@ +use crate::error::{Error, Result}; +use crate::span::Span; +use crate::token::{Token, TokenKind}; + +pub fn tokenize(source: &str) -> Result> { + Lexer { + src: source, + pos: 0, + } + .run() +} + +struct Lexer<'a> { + src: &'a str, + pos: usize, +} + +impl<'a> Lexer<'a> { + fn run(mut self) -> Result> { + let mut tokens = Vec::new(); + loop { + self.skip_trivia()?; + let start = self.pos; + let Some(c) = self.peek() else { + tokens.push(Token { + kind: TokenKind::Eof, + span: Span::new(start, start), + }); + return Ok(tokens); + }; + let kind = match c { + '"' => self.string()?, + '\'' => self.possessive()?, + c if c.is_ascii_digit() => self.number()?, + c if is_ident_start(c) => self.ident(), + _ => self.punct()?, + }; + tokens.push(Token { + kind, + span: Span::new(start, self.pos), + }); + } + } + + fn peek(&self) -> Option { + self.src[self.pos..].chars().next() + } + + fn peek_at(&self, n: usize) -> Option { + self.src[self.pos..].chars().nth(n) + } + + fn bump(&mut self) -> Option { + let c = self.peek()?; + self.pos += c.len_utf8(); + Some(c) + } + + fn eat(&mut self, expected: char) -> bool { + if self.peek() == Some(expected) { + self.pos += expected.len_utf8(); + true + } else { + false + } + } + + fn skip_trivia(&mut self) -> Result<()> { + loop { + match (self.peek(), self.peek_at(1)) { + (Some(c), _) if c.is_whitespace() => { + self.bump(); + } + (Some('/'), Some('/')) => { + while let Some(c) = self.peek() { + if c == '\n' { + break; + } + self.bump(); + } + } + (Some('/'), Some('*')) => { + let start = self.pos; + self.pos += 2; + loop { + match (self.peek(), self.peek_at(1)) { + (Some('*'), Some('/')) => { + self.pos += 2; + break; + } + (None, _) => { + return Err(Error::syntax( + "this block comment never closes; it needs a `*/`", + Span::new(start, self.pos), + ) + .incomplete()); + } + _ => { + self.bump(); + } + } + } + } + _ => return Ok(()), + } + } + } + + fn ident(&mut self) -> TokenKind { + let start = self.pos; + while let Some(c) = self.peek() { + if is_ident_continue(c) { + self.bump(); + } else { + break; + } + } + let text = &self.src[start..self.pos]; + TokenKind::keyword(text).unwrap_or_else(|| TokenKind::Ident(text.to_string())) + } + + // A fraction needs digits on both sides of the dot, so `1.` and `arr[0].x` are reported + // rather than mis-lexed. + fn number(&mut self) -> Result { + let start = self.pos; + self.digits(); + if self.peek() == Some('.') && self.peek_at(1).is_some_and(|c| c.is_ascii_digit()) { + self.bump(); + self.digits(); + } + if matches!(self.peek(), Some('e' | 'E')) { + let save = self.pos; + self.bump(); + if matches!(self.peek(), Some('+' | '-')) { + self.bump(); + } + if self.peek().is_some_and(|c| c.is_ascii_digit()) { + self.digits(); + } else { + self.pos = save; + } + } + let text: String = self.src[start..self.pos] + .chars() + .filter(|&c| c != '_') + .collect(); + text.parse::().map(TokenKind::Number).map_err(|_| { + Error::syntax( + format!("`{text}` is not a number I understand"), + Span::new(start, self.pos), + ) + }) + } + + fn digits(&mut self) { + while let Some(c) = self.peek() { + if c.is_ascii_digit() || c == '_' { + self.bump(); + } else { + break; + } + } + } + + fn string(&mut self) -> Result { + let start = self.pos; + self.bump(); + let mut text = String::new(); + loop { + let Some(c) = self.bump() else { + return Err(Error::syntax( + "this string never closes; it needs a closing `\"`", + Span::new(start, self.pos), + ) + .incomplete()); + }; + match c { + '"' => return Ok(TokenKind::Str(text)), + '\\' => { + let escape_start = self.pos - 1; + let Some(e) = self.bump() else { + return Err(Error::syntax( + "this string never closes; it needs a closing `\"`", + Span::new(start, self.pos), + ) + .incomplete()); + }; + match e { + 'n' => text.push('\n'), + 't' => text.push('\t'), + 'r' => text.push('\r'), + '0' => text.push('\0'), + '\\' => text.push('\\'), + '"' => text.push('"'), + '\'' => text.push('\''), + 'u' => text.push(self.unicode_escape(escape_start)?), + other => { + return Err(Error::syntax( + format!( + "`\\{other}` is not an escape I know; try \\n, \\t, \\\", \\\\ or \\u{{…}}" + ), + Span::new(escape_start, self.pos), + )); + } + } + } + c => text.push(c), + } + } + } + + fn unicode_escape(&mut self, escape_start: usize) -> Result { + let bad = |end: usize| { + Error::syntax( + "unicode escapes look like \\u{1F431}", + Span::new(escape_start, end), + ) + }; + if !self.eat('{') { + return Err(bad(self.pos)); + } + let digits_start = self.pos; + while self.peek().is_some_and(|c| c.is_ascii_hexdigit()) { + self.bump(); + } + let digits = &self.src[digits_start..self.pos]; + if !self.eat('}') || digits.is_empty() || digits.len() > 6 { + return Err(bad(self.pos)); + } + u32::from_str_radix(digits, 16) + .ok() + .and_then(char::from_u32) + .ok_or_else(|| bad(self.pos)) + } + + fn possessive(&mut self) -> Result { + let start = self.pos; + self.bump(); + if self.peek() == Some('s') && !self.peek_at(1).is_some_and(is_ident_continue) { + self.bump(); + return Ok(TokenKind::Possessive); + } + Err(Error::syntax( + "a lone `'` doesn't mean anything; strings use double quotes and property access is `'s`", + Span::new(start, self.pos), + )) + } + + fn punct(&mut self) -> Result { + let start = self.pos; + let c = self + .bump() + .expect("punct is only called with a char available"); + let kind = match c { + '=' if self.eat('=') => TokenKind::Eq, + '=' => TokenKind::Assign, + '!' if self.eat('=') => TokenKind::NotEq, + '!' => TokenKind::Bang, + '<' if self.eat('<') => TokenKind::Shl, + '<' if self.eat('=') => TokenKind::LtEq, + '<' => TokenKind::Lt, + '>' if self.eat('>') => TokenKind::Shr, + '>' if self.eat('=') => TokenKind::GtEq, + '>' => TokenKind::Gt, + '&' if self.eat('&') => TokenKind::AndAnd, + '&' => TokenKind::Amp, + '|' if self.eat('|') => TokenKind::OrOr, + '|' => TokenKind::Pipe, + '+' => TokenKind::Plus, + '-' => TokenKind::Minus, + '*' => TokenKind::Star, + '/' => TokenKind::Slash, + '%' => TokenKind::Percent, + '^' => TokenKind::Caret, + '~' => TokenKind::Tilde, + '(' => TokenKind::LParen, + ')' => TokenKind::RParen, + '{' => TokenKind::LBrace, + '}' => TokenKind::RBrace, + '[' => TokenKind::LBracket, + ']' => TokenKind::RBracket, + ',' => TokenKind::Comma, + ':' => TokenKind::Colon, + ';' => TokenKind::Semicolon, + other => { + return Err(Error::syntax( + format!("I don't know what to do with `{other}`"), + Span::new(start, self.pos), + )); + } + }; + Ok(kind) + } +} + +fn is_ident_start(c: char) -> bool { + c == '_' || c.is_alphabetic() +} + +fn is_ident_continue(c: char) -> bool { + c == '_' || c.is_alphanumeric() +} + +#[cfg(test)] +mod tests { + use super::*; + + fn kinds(src: &str) -> Vec { + tokenize(src).unwrap().into_iter().map(|t| t.kind).collect() + } + + #[test] + fn empty_input_is_just_eof() { + assert_eq!(kinds(""), vec![TokenKind::Eof]); + assert_eq!(kinds(" \n\t"), vec![TokenKind::Eof]); + } + + #[test] + fn keywords_and_identifiers() { + assert_eq!( + kinds("scratch cat = purrfect;"), + vec![ + TokenKind::Scratch, + TokenKind::Ident("cat".into()), + TokenKind::Assign, + TokenKind::Purrfect, + TokenKind::Semicolon, + TokenKind::Eof + ] + ); + assert_eq!( + kinds("scratchy"), + vec![TokenKind::Ident("scratchy".into()), TokenKind::Eof] + ); + assert_eq!( + kinds("cat_2"), + vec![TokenKind::Ident("cat_2".into()), TokenKind::Eof] + ); + } + + #[test] + fn numbers() { + assert_eq!(kinds("42"), vec![TokenKind::Number(42.0), TokenKind::Eof]); + assert_eq!(kinds("3.5"), vec![TokenKind::Number(3.5), TokenKind::Eof]); + assert_eq!( + kinds("1_000"), + vec![TokenKind::Number(1000.0), TokenKind::Eof] + ); + assert_eq!( + kinds("2e3"), + vec![TokenKind::Number(2000.0), TokenKind::Eof] + ); + } + + #[test] + fn strings_with_escapes() { + assert_eq!( + kinds(r#""meow\n\"purr\" \u{1F431}""#), + vec![TokenKind::Str("meow\n\"purr\" 🐱".into()), TokenKind::Eof] + ); + } + + #[test] + fn unterminated_string_is_incomplete() { + let err = tokenize("\"meow").unwrap_err(); + assert!(err.incomplete); + assert_eq!(err.span, Some(Span::new(0, 5))); + } + + #[test] + fn possessive() { + assert_eq!( + kinds("cat's name"), + vec![ + TokenKind::Ident("cat".into()), + TokenKind::Possessive, + TokenKind::Ident("name".into()), + TokenKind::Eof + ] + ); + assert!(tokenize("cat'sname").is_err()); + assert!(tokenize("'hello'").is_err()); + } + + #[test] + fn operators() { + assert_eq!( + kinds("a <= b << c && d || !e != f"), + vec![ + TokenKind::Ident("a".into()), + TokenKind::LtEq, + TokenKind::Ident("b".into()), + TokenKind::Shl, + TokenKind::Ident("c".into()), + TokenKind::AndAnd, + TokenKind::Ident("d".into()), + TokenKind::OrOr, + TokenKind::Bang, + TokenKind::Ident("e".into()), + TokenKind::NotEq, + TokenKind::Ident("f".into()), + TokenKind::Eof + ] + ); + } + + #[test] + fn comments_are_skipped() { + assert_eq!( + kinds("1 // one\n/* two\nlines */ 2"), + vec![ + TokenKind::Number(1.0), + TokenKind::Number(2.0), + TokenKind::Eof + ] + ); + assert!(tokenize("/* open").unwrap_err().incomplete); + } + + #[test] + fn spans_are_byte_ranges() { + let toks = tokenize("ab \"c\"").unwrap(); + assert_eq!(toks[0].span, Span::new(0, 2)); + assert_eq!(toks[1].span, Span::new(4, 7)); + } + + #[test] + fn unknown_character() { + let err = tokenize("a @ b").unwrap_err(); + assert_eq!(err.span, Some(Span::new(2, 3))); + } +} diff --git a/crates/meowscript/src/lib.rs b/crates/meowscript/src/lib.rs new file mode 100644 index 0000000..fec05b7 --- /dev/null +++ b/crates/meowscript/src/lib.rs @@ -0,0 +1,50 @@ +//! MeowScript, a small cat-themed scripting language. +//! +//! ``` +//! use meowscript::{BufferHost, Interpreter}; +//! +//! let host = BufferHost::new(); +//! let mut interp = Interpreter::new(host.clone()); +//! interp.run(r#" +//! scratch cat = { name: "Whiskers", lives: 9 }; +//! meow(cat's name, "has", cat's lives, "lives"); +//! "#).unwrap(); +//! assert_eq!(host.output(), "Meow! Whiskers has 9 lives"); +//! ``` + +pub mod ast; +pub mod env; +pub mod error; +pub mod host; +pub mod interpreter; +pub mod lexer; +pub mod parser; +pub mod rng; +pub mod span; +pub mod stdlib; +pub mod token; +pub mod value; + +pub use error::{Error, ErrorKind, Result}; +pub use host::{BufferHost, Host}; +pub use interpreter::Interpreter; +pub use value::Value; + +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Runs a program; the error, if any, comes back rendered with its source excerpt. +pub fn run_with_host( + source: &str, + host: impl Host + 'static, +) -> std::result::Result { + let mut interp = Interpreter::new(host); + interp.run(source).map_err(|e| e.render(source, None)) +} + +/// Runs a program and returns what it printed, plus the rendered error if it failed. +pub fn capture(source: &str) -> (Vec, Option) { + let host = BufferHost::new(); + let mut interp = Interpreter::new(host.clone()); + let result = interp.run(source); + (host.take(), result.err().map(|e| e.render(source, None))) +} diff --git a/crates/meowscript/src/parser.rs b/crates/meowscript/src/parser.rs new file mode 100644 index 0000000..5990b1d --- /dev/null +++ b/crates/meowscript/src/parser.rs @@ -0,0 +1,784 @@ +//! Recursive descent with Pratt precedence climbing. Stops at the first error. + +use crate::ast::*; +use crate::error::{Error, Result}; +use crate::lexer::tokenize; +use crate::span::Span; +use crate::token::{Token, TokenKind}; +use std::rc::Rc; + +pub fn parse(source: &str) -> Result { + let tokens = tokenize(source)?; + Parser { tokens, pos: 0 }.program() +} + +struct Parser { + tokens: Vec, + pos: usize, +} + +impl Parser { + fn peek(&self) -> &Token { + &self.tokens[self.pos.min(self.tokens.len() - 1)] + } + + fn peek_kind(&self) -> &TokenKind { + &self.peek().kind + } + + fn peek_at(&self, n: usize) -> &TokenKind { + &self.tokens[(self.pos + n).min(self.tokens.len() - 1)].kind + } + + fn at_eof(&self) -> bool { + matches!(self.peek_kind(), TokenKind::Eof) + } + + fn advance(&mut self) -> Token { + let tok = self.peek().clone(); + if !self.at_eof() { + self.pos += 1; + } + tok + } + + fn at(&self, kind: &TokenKind) -> bool { + self.peek_kind() == kind + } + + fn eat(&mut self, kind: &TokenKind) -> Option { + if self.at(kind) { + Some(self.advance()) + } else { + None + } + } + + fn expect(&mut self, kind: &TokenKind, context: &str) -> Result { + if self.at(kind) { + Ok(self.advance()) + } else { + Err(self.error_here(format!( + "expected `{}` {context}, found {}", + kind.symbol(), + self.peek_kind() + ))) + } + } + + fn expect_ident(&mut self, context: &str) -> Result { + match self.peek_kind() { + TokenKind::Ident(_) => { + let tok = self.advance(); + let TokenKind::Ident(name) = tok.kind else { + unreachable!() + }; + Ok(Ident { + name: name.into(), + span: tok.span, + }) + } + found => { + let msg = match found { + k if TokenKind::keyword(k.symbol()).is_some() => format!( + "expected a name {context}, found the keyword `{}` (keywords can't be used as names)", + k.symbol() + ), + k => format!("expected a name {context}, found {k}"), + }; + Err(self.error_here(msg)) + } + } + } + + fn error_here(&self, message: impl Into) -> Error { + let tok = self.peek(); + let err = Error::syntax(message, tok.span); + if self.at_eof() { err.incomplete() } else { err } + } + + fn program(&mut self) -> Result { + let mut stmts = Vec::new(); + while !self.at_eof() { + stmts.push(self.statement()?); + } + Ok(Program { stmts }) + } + + fn block(&mut self, context: &str) -> Result { + let open = self.expect(&TokenKind::LBrace, context)?; + let mut stmts = Vec::new(); + while !self.at(&TokenKind::RBrace) { + if self.at_eof() { + return Err( + Error::syntax("this block never closes; it needs a `}`", open.span) + .incomplete(), + ); + } + stmts.push(self.statement()?); + } + let close = self.advance(); + Ok(Block { + stmts, + span: open.span.to(close.span), + }) + } + + fn statement(&mut self) -> Result { + let start = self.peek().span; + let kind = match self.peek_kind() { + TokenKind::Scratch => self.let_stmt()?, + TokenKind::Amew => self.assign_stmt()?, + TokenKind::Tail => self.return_stmt()?, + TokenKind::Pawckage => self.import_stmt()?, + TokenKind::Hiss => { + self.advance(); + self.end_statement("`hiss`")?; + StmtKind::Break + } + TokenKind::Continue => { + self.advance(); + self.end_statement("`continue`")?; + StmtKind::Continue + } + TokenKind::Pawction if matches!(self.peek_at(1), TokenKind::Ident(_)) => { + self.fn_decl()? + } + TokenKind::Furrever => self.loop_stmt()?, + TokenKind::Fur => self.for_stmt()?, + TokenKind::Semicolon => { + return Err(self.error_here("stray `;`; there is no statement before it")); + } + _ => { + let expr = self.expression(0)?; + if expr.ends_with_block() { + self.eat(&TokenKind::Semicolon); + } else { + self.end_statement("this expression")?; + } + StmtKind::Expr(expr) + } + }; + let end = self.tokens[self.pos.saturating_sub(1)].span; + Ok(Stmt { + kind, + span: start.to(end), + }) + } + + // The `;` may be left out before a closing `}` and at the end of the input. + fn end_statement(&mut self, what: &str) -> Result<()> { + if self.eat(&TokenKind::Semicolon).is_some() || self.at(&TokenKind::RBrace) || self.at_eof() + { + return Ok(()); + } + let prev_end = self.tokens[self.pos.saturating_sub(1)].span.end; + Err(Error::syntax( + format!("expected `;` after {what}, found {}", self.peek_kind()), + Span::new(prev_end, prev_end), + )) + } + + fn let_stmt(&mut self) -> Result { + self.advance(); + let name = self.expect_ident("after `scratch`")?; + self.expect( + &TokenKind::Assign, + &format!("after `scratch {}`", name.name), + )?; + let value = self.expression(0)?; + self.end_statement(&format!("`scratch {} = ...`", name.name))?; + Ok(StmtKind::Let { name, value }) + } + + fn assign_stmt(&mut self) -> Result { + self.advance(); + let target = self.postfix_chain()?; + if !matches!( + target.kind, + ExprKind::Ident(_) | ExprKind::Index { .. } | ExprKind::Member { .. } + ) { + return Err(Error::syntax( + "`amew` can only assign to a variable, `thing's key`, or `thing[index]`", + target.span, + )); + } + self.expect(&TokenKind::Assign, "after the `amew` target")?; + let value = self.expression(0)?; + self.end_statement("the `amew` assignment")?; + Ok(StmtKind::Assign { target, value }) + } + + fn return_stmt(&mut self) -> Result { + self.advance(); + let value = + if self.at(&TokenKind::Semicolon) || self.at(&TokenKind::RBrace) || self.at_eof() { + None + } else { + Some(self.expression(0)?) + }; + self.end_statement("`tail`")?; + Ok(StmtKind::Return { value }) + } + + fn import_stmt(&mut self) -> Result { + self.advance(); + let tok = self.advance(); + let TokenKind::Str(path) = tok.kind else { + return Err(Error::syntax( + format!( + "`pawckage` needs a quoted name like \"nya:furrball\" or \"./cat.meow\", found {}", + tok.kind + ), + tok.span, + )); + }; + self.end_statement("`pawckage`")?; + Ok(StmtKind::Import { + path, + span: tok.span, + }) + } + + fn fn_decl(&mut self) -> Result { + self.advance(); + let name = self.expect_ident("after `pawction`")?; + let params = self.params()?; + let body = self.block("to start the pawction body")?; + self.eat(&TokenKind::Semicolon); + let func = Rc::new(FuncDef { + name: Some(name.name.clone()), + params, + body, + }); + Ok(StmtKind::FnDecl { name, func }) + } + + fn loop_stmt(&mut self) -> Result { + self.advance(); + let cond = if self.at(&TokenKind::LBrace) { + None + } else { + Some(self.expression(0)?) + }; + let body = self.block("to start the `furrever` body")?; + Ok(StmtKind::Loop { cond, body }) + } + + fn for_stmt(&mut self) -> Result { + self.advance(); + let parens = self.eat(&TokenKind::LParen).is_some(); + let var = self.expect_ident("after `fur`")?; + if self.eat(&TokenKind::Tilde).is_none() { + return Err(self.error_here(format!( + "expected `~` after `fur {}` (as in `fur toy ~ toys`), found {}", + var.name, + self.peek_kind() + ))); + } + let iter = self.expression(0)?; + if parens { + self.expect(&TokenKind::RParen, "to close the `fur (...)`")?; + } + let body = self.block("to start the `fur` body")?; + Ok(StmtKind::ForIn { var, iter, body }) + } + + fn expression(&mut self, min_bp: u8) -> Result { + let mut left = self.unary()?; + while let Some(op) = binary_op(self.peek_kind()) { + let (lbp, rbp) = op.binding_power(); + if lbp < min_bp { + break; + } + self.advance(); + let right = self.expression(rbp)?; + let span = left.span.to(right.span); + left = Expr { + kind: ExprKind::Binary { + op, + left: Box::new(left), + right: Box::new(right), + }, + span, + }; + } + Ok(left) + } + + fn unary(&mut self) -> Result { + let op = match self.peek_kind() { + TokenKind::Minus => UnaryOp::Neg, + TokenKind::Bang => UnaryOp::Not, + TokenKind::Furreal => UnaryOp::Typeof, + _ => return self.postfix_chain(), + }; + let start = self.advance().span; + let operand = self.unary()?; + let span = start.to(operand.span); + Ok(Expr { + kind: ExprKind::Unary { + op, + operand: Box::new(operand), + }, + span, + }) + } + + fn postfix_chain(&mut self) -> Result { + let mut expr = self.primary()?; + loop { + expr = match self.peek_kind() { + TokenKind::LParen => { + self.advance(); + let args = self.comma_list( + &TokenKind::RParen, + "to close the call", + Self::expression0, + )?; + let end = self.tokens[self.pos - 1].span; + let span = expr.span.to(end); + Expr { + kind: ExprKind::Call { + callee: Box::new(expr), + args, + }, + span, + } + } + TokenKind::LBracket => { + self.advance(); + let index = self.expression(0)?; + let close = self.expect(&TokenKind::RBracket, "to close the index")?; + let span = expr.span.to(close.span); + Expr { + kind: ExprKind::Index { + object: Box::new(expr), + index: Box::new(index), + }, + span, + } + } + TokenKind::Possessive => { + self.advance(); + let name = self.expect_ident("after `'s`")?; + let span = expr.span.to(name.span); + Expr { + kind: ExprKind::Member { + object: Box::new(expr), + name, + }, + span, + } + } + _ => return Ok(expr), + }; + } + } + + fn expression0(&mut self) -> Result { + self.expression(0) + } + + fn primary(&mut self) -> Result { + let tok = self.peek().clone(); + let span = tok.span; + let kind = match tok.kind { + TokenKind::Number(n) => { + self.advance(); + ExprKind::Number(n) + } + TokenKind::Str(s) => { + self.advance(); + ExprKind::Str(s.into()) + } + TokenKind::Ident(name) => { + self.advance(); + ExprKind::Ident(name.into()) + } + TokenKind::Purrfect => { + self.advance(); + ExprKind::Bool(true) + } + TokenKind::Clawful => { + self.advance(); + ExprKind::Bool(false) + } + TokenKind::Mew => { + self.advance(); + ExprKind::Null + } + TokenKind::LParen => { + self.advance(); + let inner = self.expression(0)?; + let close = self.expect(&TokenKind::RParen, "to close the parenthesis")?; + return Ok(Expr { + kind: inner.kind, + span: span.to(close.span), + }); + } + TokenKind::LBracket => { + self.advance(); + let items = self.comma_list( + &TokenKind::RBracket, + "to close the furrball", + Self::expression0, + )?; + let end = self.tokens[self.pos - 1].span; + return Ok(Expr { + kind: ExprKind::Array(items), + span: span.to(end), + }); + } + TokenKind::LBrace => return self.object_literal(), + TokenKind::Pawction => return self.function_expr(), + TokenKind::Purrhaps => return self.if_expr(), + TokenKind::Meowtually => { + return Err(self.error_here("`meowtually` needs a `purrhaps` before it")); + } + TokenKind::Eof => { + return Err(self.error_here("expected an expression, found end of input")); + } + other => { + let hint = match other { + TokenKind::Amew => " (did you mean `scratch` to declare a new variable?)", + TokenKind::Assign => " (use `==` to compare, `amew` to assign)", + _ => "", + }; + return Err(self.error_here(format!("expected an expression, found {other}{hint}"))); + } + }; + Ok(Expr { kind, span }) + } + + fn if_expr(&mut self) -> Result { + let start = self.advance().span; + let cond = self.expression(0)?; + let then = self.block("to start the `purrhaps` body")?; + let mut end = then.span; + let otherwise = if self.eat(&TokenKind::Meowtually).is_some() { + if self.at(&TokenKind::Purrhaps) { + let nested = self.if_expr()?; + end = nested.span; + Some(Box::new(Else::If(nested))) + } else { + let block = self.block("after `meowtually`")?; + end = block.span; + Some(Box::new(Else::Block(block))) + } + } else { + None + }; + Ok(Expr { + kind: ExprKind::If { + cond: Box::new(cond), + then, + otherwise, + }, + span: start.to(end), + }) + } + + fn function_expr(&mut self) -> Result { + let start = self.advance().span; + let name = match self.peek_kind() { + TokenKind::Ident(_) => Some(self.expect_ident("")?.name), + _ => None, + }; + let params = self.params()?; + let body = self.block("to start the pawction body")?; + let span = start.to(body.span); + Ok(Expr { + kind: ExprKind::Function(Rc::new(FuncDef { name, params, body })), + span, + }) + } + + fn params(&mut self) -> Result> { + self.expect(&TokenKind::LParen, "to start the parameter list")?; + let params = self.comma_list(&TokenKind::RParen, "to close the parameter list", |p| { + p.expect_ident("in the parameter list") + })?; + let mut seen: Vec<&str> = Vec::new(); + for p in ¶ms { + if seen.contains(&&*p.name) { + return Err(Error::syntax( + format!("parameter `{}` is listed twice", p.name), + p.span, + )); + } + seen.push(&p.name); + } + Ok(params) + } + + fn object_literal(&mut self) -> Result { + let start = self.advance().span; + let mut entries = Vec::new(); + loop { + if self.at(&TokenKind::RBrace) { + break; + } + let key_tok = self.advance(); + let key = match key_tok.kind { + TokenKind::Ident(name) => { + // `{ name }` is shorthand for `{ name: name }`. + if self.at(&TokenKind::Comma) || self.at(&TokenKind::RBrace) { + let key = Expr { + kind: ExprKind::Str(name.clone().into()), + span: key_tok.span, + }; + let value = Expr { + kind: ExprKind::Ident(name.into()), + span: key_tok.span, + }; + entries.push((key, value)); + if self.eat(&TokenKind::Comma).is_none() { + break; + } + continue; + } + Expr { + kind: ExprKind::Str(name.into()), + span: key_tok.span, + } + } + TokenKind::Str(s) => Expr { + kind: ExprKind::Str(s.into()), + span: key_tok.span, + }, + TokenKind::Number(n) => Expr { + kind: ExprKind::Str(crate::value::format_number(n).into()), + span: key_tok.span, + }, + TokenKind::LBracket => { + let inner = self.expression(0)?; + let close = self.expect(&TokenKind::RBracket, "to close the computed key")?; + Expr { + kind: inner.kind, + span: key_tok.span.to(close.span), + } + } + TokenKind::Eof => { + return Err( + Error::syntax("this object never closes; it needs a `}`", start) + .incomplete(), + ); + } + other => { + return Err(Error::syntax( + format!("object keys are names or strings, found {other}"), + key_tok.span, + )); + } + }; + self.expect(&TokenKind::Colon, "after the object key")?; + let value = self.expression(0)?; + entries.push((key, value)); + if self.eat(&TokenKind::Comma).is_none() { + break; + } + } + let close = self.expect(&TokenKind::RBrace, "to close the object")?; + Ok(Expr { + kind: ExprKind::Object(entries), + span: start.to(close.span), + }) + } + + // Allows a trailing comma and an empty list. + fn comma_list( + &mut self, + close: &TokenKind, + context: &str, + mut item: impl FnMut(&mut Self) -> Result, + ) -> Result> { + let mut items = Vec::new(); + loop { + if self.eat(close).is_some() { + return Ok(items); + } + if self.at_eof() { + return Err(self.error_here(format!("expected `{}` {context}", close.symbol()))); + } + items.push(item(self)?); + if self.eat(&TokenKind::Comma).is_none() { + self.expect(close, context)?; + return Ok(items); + } + } + } +} + +fn binary_op(kind: &TokenKind) -> Option { + Some(match kind { + TokenKind::Plus => BinaryOp::Add, + TokenKind::Minus => BinaryOp::Sub, + TokenKind::Star => BinaryOp::Mul, + TokenKind::Slash => BinaryOp::Div, + TokenKind::Percent => BinaryOp::Rem, + TokenKind::Eq => BinaryOp::Eq, + TokenKind::NotEq => BinaryOp::NotEq, + TokenKind::Lt => BinaryOp::Lt, + TokenKind::Gt => BinaryOp::Gt, + TokenKind::LtEq => BinaryOp::LtEq, + TokenKind::GtEq => BinaryOp::GtEq, + TokenKind::Amp => BinaryOp::BitAnd, + TokenKind::Pipe => BinaryOp::BitOr, + TokenKind::Caret => BinaryOp::BitXor, + TokenKind::Shl => BinaryOp::Shl, + TokenKind::Shr => BinaryOp::Shr, + TokenKind::AndAnd => BinaryOp::And, + TokenKind::OrOr => BinaryOp::Or, + TokenKind::Tilde => BinaryOp::In, + _ => return None, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn parse_expr(src: &str) -> Expr { + let program = parse(src).unwrap(); + match program.stmts.into_iter().next().unwrap().kind { + StmtKind::Expr(e) => e, + other => panic!("expected expression statement, got {other:?}"), + } + } + + fn show(e: &Expr) -> String { + match &e.kind { + ExprKind::Number(n) => crate::value::format_number(*n), + ExprKind::Ident(i) => i.to_string(), + ExprKind::Str(s) => format!("{s:?}"), + ExprKind::Bool(b) => b.to_string(), + ExprKind::Null => "mew".into(), + ExprKind::Unary { op, operand } => format!("({op} {})", show(operand)), + ExprKind::Binary { op, left, right } => { + format!("({} {op} {})", show(left), show(right)) + } + ExprKind::Call { callee, args } => { + let args: Vec<_> = args.iter().map(show).collect(); + format!("{}({})", show(callee), args.join(", ")) + } + ExprKind::Index { object, index } => format!("{}[{}]", show(object), show(index)), + ExprKind::Member { object, name } => format!("{}'s {}", show(object), name.name), + ExprKind::Array(items) => { + let items: Vec<_> = items.iter().map(show).collect(); + format!("[{}]", items.join(", ")) + } + other => format!("{other:?}"), + } + } + + #[test] + fn precedence_matches_python_not_c() { + assert_eq!(show(&parse_expr("1 + 2 * 3;")), "(1 + (2 * 3))"); + assert_eq!(show(&parse_expr("1 & 2 == 3;")), "((1 & 2) == 3)"); + assert_eq!(show(&parse_expr("1 + 2 << 3;")), "((1 + 2) << 3)"); + assert_eq!(show(&parse_expr("a || b && c;")), "(a || (b && c))"); + assert_eq!(show(&parse_expr("a < b == c > d;")), "((a < b) == (c > d))"); + assert_eq!(show(&parse_expr("1 - 2 - 3;")), "((1 - 2) - 3)"); + assert_eq!(show(&parse_expr("x ~ xs && y;")), "((x ~ xs) && y)"); + } + + #[test] + fn unary_binds_tighter_than_binary_but_looser_than_postfix() { + assert_eq!(show(&parse_expr("-a[0] + 1;")), "((- a[0]) + 1)"); + assert_eq!(show(&parse_expr("!f(x)'s ok;")), "(! f(x)'s ok)"); + assert_eq!(show(&parse_expr("furreal x + 1;")), "((furreal x) + 1)"); + } + + #[test] + fn postfix_chains() { + assert_eq!( + show(&parse_expr("cats[0]'s toys[1](2);")), + "cats[0]'s toys[1](2)" + ); + } + + #[test] + fn statements_need_semicolons_except_before_brace_or_eof() { + assert!(parse("scratch x = 1").is_ok()); + assert!(parse("scratch x = 1; scratch y = 2").is_ok()); + let err = parse("scratch x = 1 scratch y = 2;").unwrap_err(); + assert!(err.message.contains("expected `;`"), "{}", err.message); + assert!(parse("pawction f() { tail 1 }").is_ok()); + assert!(parse("purrhaps (x) { 1 } meowtually { 2 } meow(1);").is_ok()); + } + + #[test] + fn if_else_chains() { + let e = parse_expr("purrhaps a { 1 } meowtually purrhaps b { 2 } meowtually { 3 }"); + let ExprKind::If { + otherwise: Some(else1), + .. + } = e.kind + else { + panic!() + }; + let Else::If(nested) = *else1 else { panic!() }; + let ExprKind::If { + otherwise: Some(else2), + .. + } = nested.kind + else { + panic!() + }; + assert!(matches!(*else2, Else::Block(_))); + } + + #[test] + fn function_declaration_and_expression() { + let p = parse("pawction add(a, b) { tail a + b; } scratch f = pawction(x) { x };").unwrap(); + assert!(matches!(p.stmts[0].kind, StmtKind::FnDecl { .. })); + assert!(matches!(p.stmts[1].kind, StmtKind::Let { .. })); + assert!( + parse("pawction f(a, a) {}") + .unwrap_err() + .message + .contains("twice") + ); + } + + #[test] + fn assignment_targets() { + assert!(parse("amew x = 1;").is_ok()); + assert!(parse("amew cat's age = 4;").is_ok()); + assert!(parse("amew arr[0] = 4;").is_ok()); + assert!(parse("amew f() = 4;").is_err()); + assert!(parse("amew 1 = 4;").is_err()); + } + + #[test] + fn loops() { + assert!(parse("furrever { hiss; }").is_ok()); + assert!(parse("furrever i < 3 { amew i = i + 1; }").is_ok()); + assert!(parse("furrever (i < 3) { continue; }").is_ok()); + assert!(parse("fur x ~ xs { meow(x); }").is_ok()); + assert!(parse("fur (x ~ xs) { meow(x); }").is_ok()); + assert!(parse("fur x in xs {}").unwrap_err().message.contains("`~`")); + } + + #[test] + fn object_literals() { + assert!(parse(r#"scratch c = { name: "Tom", "age": 3, 1: 2, [k]: v, short, };"#).is_ok()); + assert!(parse("scratch c = {};").is_ok()); + assert!(parse("scratch c = { 1 + 1: 2 };").is_err()); + } + + #[test] + fn incomplete_input_is_flagged() { + assert!(parse("pawction f() {").unwrap_err().incomplete); + assert!(parse("scratch x = [1, 2").unwrap_err().incomplete); + assert!(parse("scratch x = ").unwrap_err().incomplete); + assert!(!parse("scratch x = )").unwrap_err().incomplete); + } + + #[test] + fn keyword_as_name_gets_a_hint() { + let err = parse("scratch tail = 1;").unwrap_err(); + assert!(err.message.contains("keyword"), "{}", err.message); + } +} diff --git a/crates/meowscript/src/rng.rs b/crates/meowscript/src/rng.rs new file mode 100644 index 0000000..e0ce60f --- /dev/null +++ b/crates/meowscript/src/rng.rs @@ -0,0 +1,99 @@ +//! xoshiro256**. Fine for picking a toy out of the toy box, not for cryptography. + +pub struct Rng { + state: [u64; 4], +} + +impl Rng { + pub fn seeded(seed: u64) -> Self { + // splitmix64 spreads a weak seed (such as a small integer) across the whole state. + let mut x = seed; + let mut next = || { + x = x.wrapping_add(0x9E37_79B9_7F4A_7C15); + let mut z = x; + z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9); + z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB); + z ^ (z >> 31) + }; + Self { + state: [next(), next(), next(), next()], + } + } + + pub fn next_u64(&mut self) -> u64 { + let s = &mut self.state; + let result = s[1].wrapping_mul(5).rotate_left(7).wrapping_mul(9); + let t = s[1] << 17; + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + s[2] ^= t; + s[3] = s[3].rotate_left(45); + result + } + + pub fn next_f64(&mut self) -> f64 { + (self.next_u64() >> 11) as f64 * (1.0 / (1u64 << 53) as f64) + } + + pub fn range_f64(&mut self, lo: f64, hi: f64) -> f64 { + let (lo, hi) = if lo <= hi { (lo, hi) } else { (hi, lo) }; + lo + (hi - lo) * self.next_f64() + } + + /// Inclusive on both ends. + pub fn range_i64(&mut self, lo: i64, hi: i64) -> i64 { + let (lo, hi) = if lo <= hi { (lo, hi) } else { (hi, lo) }; + let width = (hi - lo) as u64 + 1; + lo + (self.next_u64() % width) as i64 + } + + pub fn index(&mut self, len: usize) -> usize { + (self.next_u64() % len as u64) as usize + } + + pub fn shuffle(&mut self, items: &mut [T]) { + for i in (1..items.len()).rev() { + let j = self.index(i + 1); + items.swap(i, j); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn same_seed_same_sequence() { + let mut a = Rng::seeded(42); + let mut b = Rng::seeded(42); + for _ in 0..10 { + assert_eq!(a.next_u64(), b.next_u64()); + } + } + + #[test] + fn floats_stay_in_range() { + let mut rng = Rng::seeded(7); + for _ in 0..10_000 { + let f = rng.next_f64(); + assert!((0.0..1.0).contains(&f)); + let r = rng.range_f64(5.0, 10.0); + assert!((5.0..10.0).contains(&r)); + let i = rng.range_i64(-3, 3); + assert!((-3..=3).contains(&i)); + } + } + + #[test] + fn shuffle_keeps_every_item() { + let mut rng = Rng::seeded(1); + let mut items: Vec<_> = (0..20).collect(); + rng.shuffle(&mut items); + let mut sorted = items.clone(); + sorted.sort(); + assert_eq!(sorted, (0..20).collect::>()); + } +} diff --git a/crates/meowscript/src/span.rs b/crates/meowscript/src/span.rs new file mode 100644 index 0000000..4871cc7 --- /dev/null +++ b/crates/meowscript/src/span.rs @@ -0,0 +1,83 @@ +use std::fmt; + +/// Half-open byte range `[start, end)` into the source text. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +pub struct Span { + pub start: usize, + pub end: usize, +} + +impl Span { + pub const fn new(start: usize, end: usize) -> Self { + Self { start, end } + } + + pub fn to(self, other: Span) -> Span { + Span::new(self.start, other.end.max(self.start)) + } + + pub fn len(self) -> usize { + self.end.saturating_sub(self.start) + } + + pub fn is_empty(self) -> bool { + self.len() == 0 + } +} + +/// 1-based line and column. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Position { + pub line: usize, + pub column: usize, +} + +impl fmt::Display for Position { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}", self.line, self.column) + } +} + +/// Columns count characters, not bytes, so they match what an editor shows. +pub fn position(source: &str, offset: usize) -> Position { + let offset = offset.min(source.len()); + let before = &source[..offset]; + let line = before.matches('\n').count() + 1; + let line_start = before.rfind('\n').map_or(0, |i| i + 1); + let column = before[line_start..].chars().count() + 1; + Position { line, column } +} + +pub fn line_text(source: &str, offset: usize) -> &str { + let offset = offset.min(source.len()); + let start = source[..offset].rfind('\n').map_or(0, |i| i + 1); + let end = source[offset..] + .find('\n') + .map_or(source.len(), |i| offset + i); + source[start..end].trim_end_matches('\r') +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn positions_are_one_based() { + let src = "ab\ncd"; + assert_eq!(position(src, 0), Position { line: 1, column: 1 }); + assert_eq!(position(src, 1), Position { line: 1, column: 2 }); + assert_eq!(position(src, 3), Position { line: 2, column: 1 }); + assert_eq!(position(src, 4), Position { line: 2, column: 2 }); + } + + #[test] + fn columns_count_chars() { + let src = "🐱x"; + assert_eq!(position(src, 4).column, 2); + } + + #[test] + fn line_text_strips_newline() { + assert_eq!(line_text("one\ntwo\r\nthree", 5), "two"); + } +} diff --git a/crates/meowscript/src/stdlib/array.rs b/crates/meowscript/src/stdlib/array.rs new file mode 100644 index 0000000..4ed1571 --- /dev/null +++ b/crates/meowscript/src/stdlib/array.rs @@ -0,0 +1,388 @@ +//! `push`, `pounce`, and `shuffle` change the furrball they are given. Everything else returns a +//! new one. + +use super::{Package, array, callable, number, slice_bound, wrong_type}; +use crate::error::{Error, Result}; +use crate::interpreter::Interpreter; +use crate::value::{Arity, Builtin, Value, format_number}; +use std::cmp::Ordering; + +pub const INCLUDES: Builtin = Builtin { + name: "includes", + arity: Arity::Exact(2), + func: includes, + doc: "Whether a furrball has an item, or whiskers contain a substring. Same as `~`.", +}; + +pub const INDEX_OF: Builtin = Builtin { + name: "index_of", + arity: Arity::Exact(2), + func: index_of, + doc: "Where an item (or substring) first appears, or -1.", +}; + +pub const REVERSE: Builtin = Builtin { + name: "reverse", + arity: Arity::Exact(1), + func: reverse, + doc: "A reversed copy of a furrball or whiskers.", +}; + +pub const SLICE: Builtin = Builtin { + name: "slice", + arity: Arity::Between(2, 3), + func: slice, + doc: "A copy of part of a furrball or whiskers, from `start` up to (not including) `end`. Negative counts from the end.", +}; + +pub static PACKAGE: Package = Package { + name: "nya:furrball", + doc: "Everything for furrballs (arrays).", + builtins: &[ + Builtin { + name: "push", + arity: Arity::AtLeast(2), + func: push, + doc: "Add items to the end of a furrball. Changes it in place and returns it.", + }, + Builtin { + name: "pounce", + arity: Arity::Exact(1), + func: pounce, + doc: "Remove and return the last item, or mew if the furrball is empty.", + }, + Builtin { + name: "top", + arity: Arity::Exact(1), + func: top, + doc: "The first item, or mew.", + }, + Builtin { + name: "last", + arity: Arity::Exact(1), + func: last, + doc: "The last item, or mew.", + }, + Builtin { + name: "bottom", + arity: Arity::Exact(1), + func: bottom, + doc: "A new furrball with everything but the first item.", + }, + INCLUDES, + INDEX_OF, + Builtin { + name: "map", + arity: Arity::Exact(2), + func: map, + doc: "A new furrball made by calling the pawction on each item.", + }, + Builtin { + name: "filter", + arity: Arity::Exact(2), + func: filter, + doc: "A new furrball of the items the pawction says purrfect to.", + }, + Builtin { + name: "reduce", + arity: Arity::Between(2, 3), + func: reduce, + doc: "Fold a furrball into one value with `pawction(total, item)`, starting from the optional initial value.", + }, + Builtin { + name: "each", + arity: Arity::Exact(2), + func: each, + doc: "Call the pawction on every item. Returns mew.", + }, + Builtin { + name: "find", + arity: Arity::Exact(2), + func: find, + doc: "The first item the pawction says purrfect to, or mew.", + }, + Builtin { + name: "range", + arity: Arity::Between(1, 3), + func: range, + doc: "Numbers from `start` (default 0) up to but not including `end`, in `step`s (default 1).", + }, + REVERSE, + Builtin { + name: "sort", + arity: Arity::Between(1, 2), + func: sort, + doc: "A sorted copy. Give a `pawction(a, b)` returning a number to decide the order.", + }, + Builtin { + name: "join", + arity: Arity::Between(1, 2), + func: join, + doc: "Glue the items into whiskers with a separator (default none).", + }, + SLICE, + Builtin { + name: "concat", + arity: Arity::AtLeast(1), + func: concat, + doc: "A new furrball with the items of all the given furrballs.", + }, + ], + constants: &[], +}; + +fn push(_: &mut Interpreter, args: Vec) -> Result { + let arr = array("push", &args, 0)?; + arr.borrow_mut().extend(args[1..].iter().cloned()); + Ok(args[0].clone()) +} + +fn pounce(_: &mut Interpreter, args: Vec) -> Result { + let arr = array("pounce", &args, 0)?; + let popped = arr.borrow_mut().pop(); + Ok(popped.unwrap_or(Value::Null)) +} + +fn top(_: &mut Interpreter, args: Vec) -> Result { + let arr = array("top", &args, 0)?; + let first = arr.borrow().first().cloned(); + Ok(first.unwrap_or(Value::Null)) +} + +fn last(_: &mut Interpreter, args: Vec) -> Result { + let arr = array("last", &args, 0)?; + let last = arr.borrow().last().cloned(); + Ok(last.unwrap_or(Value::Null)) +} + +fn bottom(_: &mut Interpreter, args: Vec) -> Result { + let arr = array("bottom", &args, 0)?; + let rest = arr.borrow().iter().skip(1).cloned().collect(); + Ok(Value::array(rest)) +} + +fn includes(_: &mut Interpreter, args: Vec) -> Result { + Ok(match (&args[0], &args[1]) { + (Value::Array(a), item) => Value::Bool(a.borrow().contains(item)), + (Value::Str(s), Value::Str(needle)) => Value::Bool(s.contains(&**needle)), + (Value::Str(_), other) => return Err(wrong_type("includes", 1, "whiskers", other)), + (other, _) => return Err(wrong_type("includes", 0, "a furrball or whiskers", other)), + }) +} + +fn index_of(_: &mut Interpreter, args: Vec) -> Result { + let found = match (&args[0], &args[1]) { + (Value::Array(a), item) => a.borrow().iter().position(|v| v == item), + (Value::Str(s), Value::Str(needle)) => { + s.find(&**needle).map(|byte| s[..byte].chars().count()) + } + (Value::Str(_), other) => return Err(wrong_type("index_of", 1, "whiskers", other)), + (other, _) => return Err(wrong_type("index_of", 0, "a furrball or whiskers", other)), + }; + Ok(Value::Number(found.map_or(-1.0, |i| i as f64))) +} + +fn map(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("map", &args, 0)?; + let f = callable("map", &args, 1)?; + let items = arr.borrow().clone(); + let mut out = Vec::with_capacity(items.len()); + for item in items { + out.push(interp.call(f.clone(), vec![item], None)?); + } + Ok(Value::array(out)) +} + +fn filter(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("filter", &args, 0)?; + let f = callable("filter", &args, 1)?; + let items = arr.borrow().clone(); + let mut out = Vec::new(); + for item in items { + if interp + .call(f.clone(), vec![item.clone()], None)? + .is_truthy() + { + out.push(item); + } + } + Ok(Value::array(out)) +} + +fn reduce(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("reduce", &args, 0)?; + let f = callable("reduce", &args, 1)?; + let items = arr.borrow().clone(); + let mut iter = items.into_iter(); + let mut total = match args.get(2) { + Some(initial) => initial.clone(), + None => iter.next().ok_or_else(|| { + Error::runtime("`reduce` of an empty furrball needs an initial value") + })?, + }; + for item in iter { + total = interp.call(f.clone(), vec![total, item], None)?; + } + Ok(total) +} + +fn each(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("each", &args, 0)?; + let f = callable("each", &args, 1)?; + let items = arr.borrow().clone(); + for item in items { + interp.call(f.clone(), vec![item], None)?; + } + Ok(Value::Null) +} + +fn find(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("find", &args, 0)?; + let f = callable("find", &args, 1)?; + let items = arr.borrow().clone(); + for item in items { + if interp + .call(f.clone(), vec![item.clone()], None)? + .is_truthy() + { + return Ok(item); + } + } + Ok(Value::Null) +} + +fn range(_: &mut Interpreter, args: Vec) -> Result { + let (start, end, step) = match args.len() { + 1 => (0.0, number("range", &args, 0)?, 1.0), + 2 => (number("range", &args, 0)?, number("range", &args, 1)?, 1.0), + _ => ( + number("range", &args, 0)?, + number("range", &args, 1)?, + number("range", &args, 2)?, + ), + }; + if step == 0.0 { + return Err(Error::runtime( + "`range` can't step by 0; it would never arrive", + )); + } + let count = ((end - start) / step).ceil().max(0.0); + if count > 10_000_000.0 { + return Err(Error::runtime(format!( + "`range` would make {} numbers, which is more than I'm willing to hold", + format_number(count) + ))); + } + let items = (0..count as usize) + .map(|i| Value::Number(start + step * i as f64)) + .collect(); + Ok(Value::array(items)) +} + +fn reverse(_: &mut Interpreter, args: Vec) -> Result { + Ok(match &args[0] { + Value::Array(a) => Value::array(a.borrow().iter().rev().cloned().collect()), + Value::Str(s) => Value::str(s.chars().rev().collect::()), + other => return Err(wrong_type("reverse", 0, "a furrball or whiskers", other)), + }) +} + +fn sort(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("sort", &args, 0)?; + let mut items = arr.borrow().clone(); + if args.len() > 1 { + let cmp = callable("sort", &args, 1)?; + let mut failure = None; + items.sort_by(|a, b| { + if failure.is_some() { + return Ordering::Equal; + } + match interp.call(cmp.clone(), vec![a.clone(), b.clone()], None) { + Ok(Value::Number(n)) => n.partial_cmp(&0.0).unwrap_or(Ordering::Equal), + Ok(other) => { + failure = Some(Error::type_(format!( + "the `sort` pawction must return a number (negative, zero, or positive), not {}", + other.type_name() + ))); + Ordering::Equal + } + Err(e) => { + failure = Some(e); + Ordering::Equal + } + } + }); + if let Some(e) = failure { + return Err(e); + } + return Ok(Value::array(items)); + } + let all_numbers = items.iter().all(|v| matches!(v, Value::Number(_))); + let all_strings = items.iter().all(|v| matches!(v, Value::Str(_))); + if all_numbers { + items.sort_by(|a, b| match (a, b) { + (Value::Number(x), Value::Number(y)) => x.partial_cmp(y).unwrap_or(Ordering::Equal), + _ => Ordering::Equal, + }); + } else if all_strings { + items.sort_by(|a, b| match (a, b) { + (Value::Str(x), Value::Str(y)) => x.cmp(y), + _ => Ordering::Equal, + }); + } else { + return Err(Error::type_( + "`sort` can order a furrball of only numbers or only whiskers; for anything else give it a pawction(a, b)", + )); + } + Ok(Value::array(items)) +} + +fn join(_: &mut Interpreter, args: Vec) -> Result { + let arr = array("join", &args, 0)?; + let sep = match args.get(1) { + Some(v) => v.to_string(), + None => String::new(), + }; + let joined = arr + .borrow() + .iter() + .map(|v| v.to_string()) + .collect::>() + .join(&sep); + Ok(Value::from(joined)) +} + +fn slice(_: &mut Interpreter, args: Vec) -> Result { + let start = number("slice", &args, 1)?; + let end = if args.len() > 2 { + Some(number("slice", &args, 2)?) + } else { + None + }; + Ok(match &args[0] { + Value::Array(a) => { + let a = a.borrow(); + let lo = slice_bound(start, a.len()); + let hi = end.map_or(a.len(), |e| slice_bound(e, a.len())).max(lo); + Value::array(a[lo..hi].to_vec()) + } + Value::Str(s) => { + let chars: Vec = s.chars().collect(); + let lo = slice_bound(start, chars.len()); + let hi = end + .map_or(chars.len(), |e| slice_bound(e, chars.len())) + .max(lo); + Value::str(chars[lo..hi].iter().collect::()) + } + other => return Err(wrong_type("slice", 0, "a furrball or whiskers", other)), + }) +} + +fn concat(_: &mut Interpreter, args: Vec) -> Result { + let mut out = Vec::new(); + for i in 0..args.len() { + let a = array("concat", &args, i)?; + out.extend(a.borrow().iter().cloned()); + } + Ok(Value::array(out)) +} diff --git a/crates/meowscript/src/stdlib/fs.rs b/crates/meowscript/src/stdlib/fs.rs new file mode 100644 index 0000000..0d27e12 --- /dev/null +++ b/crates/meowscript/src/stdlib/fs.rs @@ -0,0 +1,60 @@ +use super::{Package, string}; +use crate::error::Result; +use crate::interpreter::Interpreter; +use crate::value::{Arity, Builtin, Value}; + +pub static PACKAGE: Package = Package { + name: "nya:scratchpad", + doc: "Reading and writing files. Not available in the browser.", + builtins: &[ + Builtin { + name: "read_file", + arity: Arity::Exact(1), + func: read_file, + doc: "The whole contents of a file as whiskers.", + }, + Builtin { + name: "write_file", + arity: Arity::Exact(2), + func: write_file, + doc: "Write whiskers to a file, replacing what was there.", + }, + Builtin { + name: "append_file", + arity: Arity::Exact(2), + func: append_file, + doc: "Add whiskers to the end of a file.", + }, + Builtin { + name: "exists", + arity: Arity::Exact(1), + func: exists, + doc: "Whether a file or directory is there.", + }, + ], + constants: &[], +}; + +fn read_file(interp: &mut Interpreter, args: Vec) -> Result { + let path = string("read_file", &args, 0)?; + interp.host().read_file(&path).map(Value::from) +} + +fn write_file(interp: &mut Interpreter, args: Vec) -> Result { + let path = string("write_file", &args, 0)?; + let contents = args[1].to_string(); + interp.host().write_file(&path, &contents, false)?; + Ok(Value::Null) +} + +fn append_file(interp: &mut Interpreter, args: Vec) -> Result { + let path = string("append_file", &args, 0)?; + let contents = args[1].to_string(); + interp.host().write_file(&path, &contents, true)?; + Ok(Value::Null) +} + +fn exists(interp: &mut Interpreter, args: Vec) -> Result { + let path = string("exists", &args, 0)?; + Ok(Value::Bool(interp.host().file_exists(&path))) +} diff --git a/crates/meowscript/src/stdlib/math.rs b/crates/meowscript/src/stdlib/math.rs new file mode 100644 index 0000000..fea14e8 --- /dev/null +++ b/crates/meowscript/src/stdlib/math.rs @@ -0,0 +1,225 @@ +use super::{Package, number}; +use crate::error::{Error, Result}; +use crate::interpreter::Interpreter; +use crate::value::{Arity, Builtin, Value}; + +pub const RANDOM: Builtin = Builtin { + name: "random", + arity: Arity::Between(0, 2), + func: random, + doc: "A random number: in [0, 1) with no arguments, [0, n) with one, or [min, max) with two.", +}; + +macro_rules! unary { + ($name:ident, $f:expr) => { + fn $name(_: &mut Interpreter, args: Vec) -> Result { + let n = number(stringify!($name), &args, 0)?; + Ok(Value::Number($f(n))) + } + }; +} + +unary!(round, f64::round); +unary!(ceil, f64::ceil); +unary!(floor, f64::floor); +unary!(trunc, f64::trunc); +unary!(abs, f64::abs); +unary!(sqrt, f64::sqrt); +unary!(sin, f64::sin); +unary!(cos, f64::cos); +unary!(tan, f64::tan); +unary!(log2, f64::log2); +unary!(log10, f64::log10); +unary!(ln, f64::ln); +unary!(exp, f64::exp); + +pub static PACKAGE: Package = Package { + name: "nya:catculator", + doc: "Maths. Angles are in radians.", + builtins: &[ + RANDOM, + Builtin { + name: "round", + arity: Arity::Exact(1), + func: round, + doc: "Round to the nearest whole number.", + }, + Builtin { + name: "ceil", + arity: Arity::Exact(1), + func: ceil, + doc: "Round up.", + }, + Builtin { + name: "floor", + arity: Arity::Exact(1), + func: floor, + doc: "Round down.", + }, + Builtin { + name: "trunc", + arity: Arity::Exact(1), + func: trunc, + doc: "Drop the fractional part.", + }, + Builtin { + name: "abs", + arity: Arity::Exact(1), + func: abs, + doc: "Distance from zero.", + }, + Builtin { + name: "sqrt", + arity: Arity::Exact(1), + func: sqrt, + doc: "Square root.", + }, + Builtin { + name: "sin", + arity: Arity::Exact(1), + func: sin, + doc: "Sine (radians).", + }, + Builtin { + name: "cos", + arity: Arity::Exact(1), + func: cos, + doc: "Cosine (radians).", + }, + Builtin { + name: "tan", + arity: Arity::Exact(1), + func: tan, + doc: "Tangent (radians).", + }, + Builtin { + name: "log2", + arity: Arity::Exact(1), + func: log2, + doc: "Logarithm base 2.", + }, + Builtin { + name: "log10", + arity: Arity::Exact(1), + func: log10, + doc: "Logarithm base 10.", + }, + Builtin { + name: "ln", + arity: Arity::Exact(1), + func: ln, + doc: "Natural logarithm.", + }, + Builtin { + name: "exp", + arity: Arity::Exact(1), + func: exp, + doc: "e raised to the power.", + }, + Builtin { + name: "pow", + arity: Arity::Exact(2), + func: pow, + doc: "`base` raised to `exponent`.", + }, + Builtin { + name: "modulo", + arity: Arity::Exact(2), + func: modulo, + doc: "Remainder that is never negative for a positive divisor, unlike `%`.", + }, + Builtin { + name: "min", + arity: Arity::AtLeast(1), + func: min, + doc: "The smallest of the numbers, or of one furrball of numbers.", + }, + Builtin { + name: "max", + arity: Arity::AtLeast(1), + func: max, + doc: "The largest of the numbers, or of one furrball of numbers.", + }, + Builtin { + name: "clamp", + arity: Arity::Exact(3), + func: clamp, + doc: "Keep a number between `low` and `high`.", + }, + ], + constants: &[ + ("PI", std::f64::consts::PI), + ("TAU", std::f64::consts::TAU), + ("E", std::f64::consts::E), + ("INFINITY", f64::INFINITY), + ], +}; + +fn random(interp: &mut Interpreter, args: Vec) -> Result { + let (lo, hi) = match args.len() { + 0 => (0.0, 1.0), + 1 => (0.0, number("random", &args, 0)?), + _ => (number("random", &args, 0)?, number("random", &args, 1)?), + }; + Ok(Value::Number(interp.rng().range_f64(lo, hi))) +} + +fn pow(_: &mut Interpreter, args: Vec) -> Result { + Ok(Value::Number( + number("pow", &args, 0)?.powf(number("pow", &args, 1)?), + )) +} + +fn modulo(_: &mut Interpreter, args: Vec) -> Result { + let a = number("modulo", &args, 0)?; + let b = number("modulo", &args, 1)?; + if b == 0.0 { + return Err(Error::runtime("can't take `modulo` by zero")); + } + Ok(Value::Number(a.rem_euclid(b))) +} + +// Accepts either `f(1, 2, 3)` or `f([1, 2, 3])`. +fn numbers(fname: &str, args: &[Value]) -> Result> { + if let [Value::Array(items)] = args { + let items = items.borrow(); + return items + .iter() + .enumerate() + .map(|(i, v)| match v { + Value::Number(n) => Ok(*n), + other => Err(Error::type_(format!( + "`{fname}` wants a furrball of numbers, but item {i} is {}", + other.type_name() + ))), + }) + .collect(); + } + (0..args.len()).map(|i| number(fname, args, i)).collect() +} + +fn min(_: &mut Interpreter, args: Vec) -> Result { + let ns = numbers("min", &args)?; + Ok(ns + .into_iter() + .reduce(f64::min) + .map_or(Value::Null, Value::Number)) +} + +fn max(_: &mut Interpreter, args: Vec) -> Result { + let ns = numbers("max", &args)?; + Ok(ns + .into_iter() + .reduce(f64::max) + .map_or(Value::Null, Value::Number)) +} + +fn clamp(_: &mut Interpreter, args: Vec) -> Result { + let x = number("clamp", &args, 0)?; + let lo = number("clamp", &args, 1)?; + let hi = number("clamp", &args, 2)?; + if lo > hi { + return Err(Error::runtime("`clamp` needs `low` to be at most `high`")); + } + Ok(Value::Number(x.clamp(lo, hi))) +} diff --git a/crates/meowscript/src/stdlib/mod.rs b/crates/meowscript/src/stdlib/mod.rs new file mode 100644 index 0000000..59ab256 --- /dev/null +++ b/crates/meowscript/src/stdlib/mod.rs @@ -0,0 +1,194 @@ +//! The prelude is always available; everything else arrives with `pawckage "nya:";`. +//! Every function is a plain Rust `fn` in a static table, so adding one means adding a row. + +mod array; +mod fs; +mod math; +mod random; +mod string; +mod util; + +use crate::env::Env; +use crate::error::{Error, Result}; +use crate::interpreter::Interpreter; +use crate::value::{Arity, Array, Builtin, Object, Value, format_number}; +use std::rc::Rc; + +pub struct Package { + pub name: &'static str, + pub doc: &'static str, + pub builtins: &'static [Builtin], + pub constants: &'static [(&'static str, f64)], +} + +impl Package { + pub fn install(&'static self, env: &Env) { + for b in self.builtins { + env.define(b.name, Value::Builtin(b)); + } + for (name, value) in self.constants { + env.define(*name, Value::Number(*value)); + } + } +} + +pub static PACKAGES: &[&Package] = &[ + &util::PACKAGE, + &array::PACKAGE, + &string::PACKAGE, + &math::PACKAGE, + &random::PACKAGE, + &fs::PACKAGE, +]; + +pub fn package(short_name: &str) -> Option<&'static Package> { + PACKAGES + .iter() + .copied() + .find(|p| p.name.strip_prefix("nya:") == Some(short_name)) +} + +/// Whether a binding came from a `nya:` package, so a file `pawckage` doesn't re-export the +/// packages it imported for itself. +pub fn is_package_provided(name: &str, value: &Value) -> bool { + match value { + Value::Builtin(_) => true, + Value::Number(n) => PACKAGES + .iter() + .flat_map(|p| p.constants) + .any(|(cname, cvalue)| *cname == name && cvalue.to_bits() == n.to_bits()), + _ => false, + } +} + +pub static PRELUDE: &[Builtin] = &[ + Builtin { + name: "meow", + arity: Arity::AtLeast(0), + func: meow, + doc: "Print the arguments on one line, announced with \"Meow!\".", + }, + Builtin { + name: "purr", + arity: Arity::AtLeast(0), + func: purr, + doc: "Print the arguments on one line, separated by spaces.", + }, + Builtin { + name: "log", + arity: Arity::AtLeast(0), + func: purr, + doc: "The same as `purr`, for people who miss JavaScript.", + }, + util::LENGTH, +]; + +pub fn install_prelude(env: &Env) { + for b in PRELUDE { + env.define(b.name, Value::Builtin(b)); + } +} + +fn join_display(args: &[Value]) -> String { + args.iter() + .map(|v| v.to_string()) + .collect::>() + .join(" ") +} + +fn meow(interp: &mut Interpreter, args: Vec) -> Result { + let line = if args.is_empty() { + "Meow!".to_string() + } else { + format!("Meow! {}", join_display(&args)) + }; + interp.print(&line); + Ok(Value::Null) +} + +fn purr(interp: &mut Interpreter, args: Vec) -> Result { + interp.print(&join_display(&args)); + Ok(Value::Null) +} + +fn wrong_type(fname: &str, index: usize, expected: &str, got: &Value) -> Error { + Error::type_(format!( + "`{fname}` wants {expected} as argument {}, but got {}", + index + 1, + got.type_name() + )) +} + +fn number(fname: &str, args: &[Value], i: usize) -> Result { + match args.get(i) { + Some(Value::Number(n)) => Ok(*n), + Some(other) => Err(wrong_type(fname, i, "a number", other)), + None => Err(Error::arity(format!( + "`{fname}` is missing argument {}", + i + 1 + ))), + } +} + +fn integer(fname: &str, args: &[Value], i: usize) -> Result { + let n = number(fname, args, i)?; + if n.fract() != 0.0 || !n.is_finite() { + return Err(Error::type_(format!( + "`{fname}` wants a whole number as argument {}, but got {}", + i + 1, + format_number(n) + ))); + } + Ok(n as i64) +} + +fn string(fname: &str, args: &[Value], i: usize) -> Result> { + match args.get(i) { + Some(Value::Str(s)) => Ok(s.clone()), + Some(other) => Err(wrong_type(fname, i, "whiskers", other)), + None => Err(Error::arity(format!( + "`{fname}` is missing argument {}", + i + 1 + ))), + } +} + +fn array(fname: &str, args: &[Value], i: usize) -> Result { + match args.get(i) { + Some(Value::Array(a)) => Ok(a.clone()), + Some(other) => Err(wrong_type(fname, i, "a furrball", other)), + None => Err(Error::arity(format!( + "`{fname}` is missing argument {}", + i + 1 + ))), + } +} + +fn object(fname: &str, args: &[Value], i: usize) -> Result { + match args.get(i) { + Some(Value::Object(o)) => Ok(o.clone()), + Some(other) => Err(wrong_type(fname, i, "an object", other)), + None => Err(Error::arity(format!( + "`{fname}` is missing argument {}", + i + 1 + ))), + } +} + +fn callable(fname: &str, args: &[Value], i: usize) -> Result { + match args.get(i) { + Some(v @ (Value::Function(_) | Value::Builtin(_))) => Ok(v.clone()), + Some(other) => Err(wrong_type(fname, i, "a pawction", other)), + None => Err(Error::arity(format!( + "`{fname}` is missing argument {}", + i + 1 + ))), + } +} + +/// Clamps a possibly negative slice bound into `0..=len`. +fn slice_bound(n: f64, len: usize) -> usize { + let i = n as i64; + let i = if i < 0 { i + len as i64 } else { i }; + i.clamp(0, len as i64) as usize +} diff --git a/crates/meowscript/src/stdlib/random.rs b/crates/meowscript/src/stdlib/random.rs new file mode 100644 index 0000000..4da3bbb --- /dev/null +++ b/crates/meowscript/src/stdlib/random.rs @@ -0,0 +1,78 @@ +use super::math::RANDOM; +use super::{Package, array, integer, number}; +use crate::error::{Error, Result}; +use crate::interpreter::Interpreter; +use crate::value::{Arity, Builtin, Value}; + +pub static PACKAGE: Package = Package { + name: "nya:rundamn", + doc: "Random numbers, choices, and shuffles.", + builtins: &[ + Builtin { + name: "seed", + arity: Arity::Exact(1), + func: seed, + doc: "Restart the random sequence from a number, so runs repeat exactly.", + }, + RANDOM, + Builtin { + name: "uniform", + arity: Arity::Exact(2), + func: uniform, + doc: "A random float in [a, b).", + }, + Builtin { + name: "randint", + arity: Arity::Exact(2), + func: randint, + doc: "A random whole number from a to b, including both ends.", + }, + Builtin { + name: "choice", + arity: Arity::Exact(1), + func: choice, + doc: "A random item from a furrball.", + }, + Builtin { + name: "shuffle", + arity: Arity::Exact(1), + func: shuffle, + doc: "Shuffle a furrball in place and return it.", + }, + ], + constants: &[], +}; + +fn seed(interp: &mut Interpreter, args: Vec) -> Result { + let n = number("seed", &args, 0)?; + interp.reseed(n.to_bits()); + Ok(Value::Null) +} + +fn uniform(interp: &mut Interpreter, args: Vec) -> Result { + let a = number("uniform", &args, 0)?; + let b = number("uniform", &args, 1)?; + Ok(Value::Number(interp.rng().range_f64(a, b))) +} + +fn randint(interp: &mut Interpreter, args: Vec) -> Result { + let a = integer("randint", &args, 0)?; + let b = integer("randint", &args, 1)?; + Ok(Value::Number(interp.rng().range_i64(a, b) as f64)) +} + +fn choice(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("choice", &args, 0)?; + let items = arr.borrow(); + if items.is_empty() { + return Err(Error::runtime("`choice` can't pick from an empty furrball")); + } + let i = interp.rng().index(items.len()); + Ok(items[i].clone()) +} + +fn shuffle(interp: &mut Interpreter, args: Vec) -> Result { + let arr = array("shuffle", &args, 0)?; + interp.rng().shuffle(&mut arr.borrow_mut()); + Ok(args[0].clone()) +} diff --git a/crates/meowscript/src/stdlib/string.rs b/crates/meowscript/src/stdlib/string.rs new file mode 100644 index 0000000..1558d59 --- /dev/null +++ b/crates/meowscript/src/stdlib/string.rs @@ -0,0 +1,208 @@ +use super::array::{INCLUDES, INDEX_OF, REVERSE, SLICE}; +use super::{Package, integer, string}; +use crate::error::{Error, Result}; +use crate::interpreter::Interpreter; +use crate::value::{Arity, Builtin, Value}; + +pub static PACKAGE: Package = Package { + name: "nya:whiskers", + doc: "Everything for whiskers (strings).", + builtins: &[ + Builtin { + name: "in_whiskers", + arity: Arity::Exact(1), + func: in_whiskers, + doc: "Turn anything into whiskers, the way `meow` would print it.", + }, + Builtin { + name: "pawrse", + arity: Arity::Exact(1), + func: pawrse, + doc: "Read a number out of whiskers, or mew if there isn't one.", + }, + Builtin { + name: "replace", + arity: Arity::Exact(3), + func: replace, + doc: "Replace every occurrence of `from` with `to`.", + }, + Builtin { + name: "split", + arity: Arity::Between(1, 2), + func: split, + doc: "Split into a furrball on a separator. With no separator, splits on whitespace.", + }, + Builtin { + name: "upper", + arity: Arity::Exact(1), + func: upper, + doc: "SHOUTING.", + }, + Builtin { + name: "lower", + arity: Arity::Exact(1), + func: lower, + doc: "whispering.", + }, + Builtin { + name: "trim", + arity: Arity::Exact(1), + func: trim, + doc: "Strip whitespace from both ends.", + }, + Builtin { + name: "starts_with", + arity: Arity::Exact(2), + func: starts_with, + doc: "Whether the whiskers begin with the given prefix.", + }, + Builtin { + name: "ends_with", + arity: Arity::Exact(2), + func: ends_with, + doc: "Whether the whiskers end with the given suffix.", + }, + INCLUDES, + INDEX_OF, + Builtin { + name: "chars", + arity: Arity::Exact(1), + func: chars, + doc: "A furrball of the individual characters.", + }, + Builtin { + name: "repeat", + arity: Arity::Exact(2), + func: repeat, + doc: "The whiskers repeated that many times. Same as `*`.", + }, + Builtin { + name: "pad_start", + arity: Arity::Between(2, 3), + func: pad_start, + doc: "Pad on the left to a width, with spaces or the given filler.", + }, + Builtin { + name: "pad_end", + arity: Arity::Between(2, 3), + func: pad_end, + doc: "Pad on the right to a width, with spaces or the given filler.", + }, + REVERSE, + SLICE, + ], + constants: &[], +}; + +fn in_whiskers(_: &mut Interpreter, args: Vec) -> Result { + Ok(Value::from(args[0].to_string())) +} + +fn pawrse(_: &mut Interpreter, args: Vec) -> Result { + Ok(match &args[0] { + Value::Number(n) => Value::Number(*n), + Value::Str(s) => s + .trim() + .parse::() + .map(Value::Number) + .unwrap_or(Value::Null), + _ => Value::Null, + }) +} + +fn replace(_: &mut Interpreter, args: Vec) -> Result { + let s = string("replace", &args, 0)?; + let from = string("replace", &args, 1)?; + let to = string("replace", &args, 2)?; + if from.is_empty() { + return Err(Error::runtime( + "`replace` can't replace an empty string; there's nothing to find", + )); + } + Ok(Value::from(s.replace(&*from, &to))) +} + +fn split(_: &mut Interpreter, args: Vec) -> Result { + let s = string("split", &args, 0)?; + let parts: Vec = match args.get(1) { + None => s.split_whitespace().map(Value::from).collect(), + Some(_) => { + let sep = string("split", &args, 1)?; + if sep.is_empty() { + s.chars().map(|c| Value::str(c.to_string())).collect() + } else { + s.split(&*sep).map(Value::from).collect() + } + } + }; + Ok(Value::array(parts)) +} + +fn upper(_: &mut Interpreter, args: Vec) -> Result { + Ok(Value::from(string("upper", &args, 0)?.to_uppercase())) +} + +fn lower(_: &mut Interpreter, args: Vec) -> Result { + Ok(Value::from(string("lower", &args, 0)?.to_lowercase())) +} + +fn trim(_: &mut Interpreter, args: Vec) -> Result { + Ok(Value::from(string("trim", &args, 0)?.trim())) +} + +fn starts_with(_: &mut Interpreter, args: Vec) -> Result { + let s = string("starts_with", &args, 0)?; + let prefix = string("starts_with", &args, 1)?; + Ok(Value::Bool(s.starts_with(&*prefix))) +} + +fn ends_with(_: &mut Interpreter, args: Vec) -> Result { + let s = string("ends_with", &args, 0)?; + let suffix = string("ends_with", &args, 1)?; + Ok(Value::Bool(s.ends_with(&*suffix))) +} + +fn chars(_: &mut Interpreter, args: Vec) -> Result { + let s = string("chars", &args, 0)?; + Ok(Value::array( + s.chars().map(|c| Value::str(c.to_string())).collect(), + )) +} + +fn repeat(_: &mut Interpreter, args: Vec) -> Result { + let s = string("repeat", &args, 0)?; + let n = integer("repeat", &args, 1)?; + if n < 0 { + return Err(Error::type_( + "`repeat` can't repeat something a negative number of times", + )); + } + Ok(Value::from(s.repeat(n as usize))) +} + +fn pad(fname: &str, args: &[Value], at_start: bool) -> Result { + let s = string(fname, args, 0)?; + let width = integer(fname, args, 1)?.max(0) as usize; + let fill = match args.get(2) { + Some(_) => string(fname, args, 2)?, + None => " ".into(), + }; + let len = s.chars().count(); + if fill.is_empty() || len >= width { + return Ok(Value::Str(s)); + } + let padding: String = fill.chars().cycle().take(width - len).collect(); + Ok(Value::from(if at_start { + format!("{padding}{s}") + } else { + format!("{s}{padding}") + })) +} + +fn pad_start(_: &mut Interpreter, args: Vec) -> Result { + pad("pad_start", &args, true) +} + +fn pad_end(_: &mut Interpreter, args: Vec) -> Result { + pad("pad_end", &args, false) +} diff --git a/crates/meowscript/src/stdlib/util.rs b/crates/meowscript/src/stdlib/util.rs new file mode 100644 index 0000000..acd6644 --- /dev/null +++ b/crates/meowscript/src/stdlib/util.rs @@ -0,0 +1,144 @@ +use super::{Package, callable, number, object, string, wrong_type}; +use crate::error::{Error, Result}; +use crate::interpreter::Interpreter; +use crate::value::{Arity, Builtin, Value}; + +pub const LENGTH: Builtin = Builtin { + name: "length", + arity: Arity::Exact(1), + func: length, + doc: "How many characters, items, or keys something has.", +}; + +pub static PACKAGE: Package = Package { + name: "nya:clawtility", + doc: "Input, timing, objects, and other everyday tools.", + builtins: &[ + LENGTH, + Builtin { + name: "kibble", + arity: Arity::Between(0, 1), + func: kibble, + doc: "Read a line of input. Shows the prompt first if you give one.", + }, + Builtin { + name: "nap", + arity: Arity::Exact(1), + func: nap, + doc: "Pause for that many milliseconds.", + }, + Builtin { + name: "now", + arity: Arity::Exact(0), + func: now, + doc: "Milliseconds since the Unix epoch.", + }, + Builtin { + name: "keys", + arity: Arity::Exact(1), + func: keys, + doc: "A furrball of an object's keys, in insertion order.", + }, + Builtin { + name: "values", + arity: Arity::Exact(1), + func: values, + doc: "A furrball of an object's values, in insertion order.", + }, + Builtin { + name: "remove", + arity: Arity::Exact(2), + func: remove, + doc: "Remove a key from an object. Returns the removed value, or mew.", + }, + Builtin { + name: "assert", + arity: Arity::Between(1, 2), + func: assert, + doc: "Stop with an error unless the first argument is truthy.", + }, + Builtin { + name: "apply", + arity: Arity::Exact(2), + func: apply, + doc: "Call a pawction with a furrball of arguments.", + }, + ], + constants: &[], +}; + +fn length(_: &mut Interpreter, args: Vec) -> Result { + Ok(match &args[0] { + Value::Str(s) => Value::from(s.chars().count()), + Value::Array(a) => Value::from(a.borrow().len()), + Value::Object(o) => Value::from(o.borrow().len()), + other => { + return Err(wrong_type( + "length", + 0, + "whiskers, a furrball, or an object", + other, + )); + } + }) +} + +fn kibble(interp: &mut Interpreter, args: Vec) -> Result { + let prompt = match args.first() { + Some(v) => v.to_string(), + None => String::new(), + }; + interp.host().read_line(&prompt).map(Value::from) +} + +fn nap(interp: &mut Interpreter, args: Vec) -> Result { + let ms = number("nap", &args, 0)?; + if ms < 0.0 { + return Err(Error::type_( + "`nap` can't sleep for a negative amount of time", + )); + } + interp.host().sleep(ms); + Ok(Value::Null) +} + +fn now(interp: &mut Interpreter, _: Vec) -> Result { + Ok(Value::Number(interp.host().now_millis())) +} + +fn keys(_: &mut Interpreter, args: Vec) -> Result { + let o = object("keys", &args, 0)?; + let keys = o.borrow().keys().map(|k| Value::Str(k.clone())).collect(); + Ok(Value::array(keys)) +} + +fn values(_: &mut Interpreter, args: Vec) -> Result { + let o = object("values", &args, 0)?; + let values = o.borrow().values().cloned().collect(); + Ok(Value::array(values)) +} + +fn remove(_: &mut Interpreter, args: Vec) -> Result { + let o = object("remove", &args, 0)?; + let key = string("remove", &args, 1)?; + let removed = o.borrow_mut().shift_remove(&*key); + Ok(removed.unwrap_or(Value::Null)) +} + +fn assert(_: &mut Interpreter, args: Vec) -> Result { + if args[0].is_truthy() { + return Ok(Value::Null); + } + let message = match args.get(1) { + Some(m) => format!("assertion failed: {m}"), + None => "assertion failed".to_string(), + }; + Err(Error::runtime(message)) +} + +fn apply(interp: &mut Interpreter, args: Vec) -> Result { + let f = callable("apply", &args, 0)?; + let call_args = super::array("apply", &args, 1)?; + let call_args = call_args.borrow().clone(); + interp.call(f, call_args, None) +} diff --git a/crates/meowscript/src/token.rs b/crates/meowscript/src/token.rs new file mode 100644 index 0000000..3afdce9 --- /dev/null +++ b/crates/meowscript/src/token.rs @@ -0,0 +1,194 @@ +use crate::span::Span; +use std::fmt; + +#[derive(Clone, Debug, PartialEq)] +pub enum TokenKind { + Ident(String), + Number(f64), + Str(String), + + /// `scratch`: declare + Scratch, + /// `amew`: assign + Amew, + /// `pawction`: function + Pawction, + /// `purrhaps`: if + Purrhaps, + /// `meowtually`: else + Meowtually, + /// `tail`: return + Tail, + /// `pawckage`: import + Pawckage, + /// `purrfect`: true + Purrfect, + /// `clawful`: false + Clawful, + /// `mew`: null + Mew, + /// `furreal`: typeof + Furreal, + /// `furrever`: loop + Furrever, + /// `fur`: for-each + Fur, + /// `hiss`: break + Hiss, + Continue, + + Assign, + Eq, + NotEq, + Lt, + Gt, + LtEq, + GtEq, + Plus, + Minus, + Star, + Slash, + Percent, + Bang, + Amp, + Pipe, + Caret, + Shl, + Shr, + AndAnd, + OrOr, + /// `~`: membership + Tilde, + /// `'s`: property access + Possessive, + + LParen, + RParen, + LBrace, + RBrace, + LBracket, + RBracket, + Comma, + Colon, + Semicolon, + + Eof, +} + +impl TokenKind { + pub fn keyword(ident: &str) -> Option { + Some(match ident { + "scratch" => TokenKind::Scratch, + "amew" => TokenKind::Amew, + "pawction" => TokenKind::Pawction, + "purrhaps" => TokenKind::Purrhaps, + "meowtually" => TokenKind::Meowtually, + "tail" => TokenKind::Tail, + "pawckage" => TokenKind::Pawckage, + "purrfect" => TokenKind::Purrfect, + "clawful" => TokenKind::Clawful, + "mew" => TokenKind::Mew, + "furreal" => TokenKind::Furreal, + "furrever" => TokenKind::Furrever, + "fur" => TokenKind::Fur, + "hiss" => TokenKind::Hiss, + "continue" => TokenKind::Continue, + _ => return None, + }) + } + + pub const KEYWORDS: &'static [&'static str] = &[ + "scratch", + "amew", + "pawction", + "purrhaps", + "meowtually", + "tail", + "pawckage", + "purrfect", + "clawful", + "mew", + "furreal", + "furrever", + "fur", + "hiss", + "continue", + ]; + + pub fn describe(&self) -> String { + match self { + TokenKind::Ident(name) => format!("identifier `{name}`"), + TokenKind::Number(n) => format!("number `{n}`"), + TokenKind::Str(_) => "a string".to_string(), + TokenKind::Eof => "end of input".to_string(), + other => format!("`{}`", other.symbol()), + } + } + + pub fn symbol(&self) -> &'static str { + match self { + TokenKind::Ident(_) => "identifier", + TokenKind::Number(_) => "number", + TokenKind::Str(_) => "string", + TokenKind::Scratch => "scratch", + TokenKind::Amew => "amew", + TokenKind::Pawction => "pawction", + TokenKind::Purrhaps => "purrhaps", + TokenKind::Meowtually => "meowtually", + TokenKind::Tail => "tail", + TokenKind::Pawckage => "pawckage", + TokenKind::Purrfect => "purrfect", + TokenKind::Clawful => "clawful", + TokenKind::Mew => "mew", + TokenKind::Furreal => "furreal", + TokenKind::Furrever => "furrever", + TokenKind::Fur => "fur", + TokenKind::Hiss => "hiss", + TokenKind::Continue => "continue", + TokenKind::Assign => "=", + TokenKind::Eq => "==", + TokenKind::NotEq => "!=", + TokenKind::Lt => "<", + TokenKind::Gt => ">", + TokenKind::LtEq => "<=", + TokenKind::GtEq => ">=", + TokenKind::Plus => "+", + TokenKind::Minus => "-", + TokenKind::Star => "*", + TokenKind::Slash => "/", + TokenKind::Percent => "%", + TokenKind::Bang => "!", + TokenKind::Amp => "&", + TokenKind::Pipe => "|", + TokenKind::Caret => "^", + TokenKind::Shl => "<<", + TokenKind::Shr => ">>", + TokenKind::AndAnd => "&&", + TokenKind::OrOr => "||", + TokenKind::Tilde => "~", + TokenKind::Possessive => "'s", + TokenKind::LParen => "(", + TokenKind::RParen => ")", + TokenKind::LBrace => "{", + TokenKind::RBrace => "}", + TokenKind::LBracket => "[", + TokenKind::RBracket => "]", + TokenKind::Comma => ",", + TokenKind::Colon => ":", + TokenKind::Semicolon => ";", + TokenKind::Eof => "end of input", + } + } +} + +impl fmt::Display for TokenKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.describe()) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Token { + pub kind: TokenKind, + pub span: Span, +} diff --git a/crates/meowscript/src/value.rs b/crates/meowscript/src/value.rs new file mode 100644 index 0000000..ab1df35 --- /dev/null +++ b/crates/meowscript/src/value.rs @@ -0,0 +1,303 @@ +//! Strings are immutable and shared. Furrballs and objects are reference types, like in +//! JavaScript: `push` on one variable is seen through every other variable holding it. + +use crate::ast::FuncDef; +use crate::env::Env; +use crate::error::Result; +use crate::interpreter::Interpreter; +use indexmap::IndexMap; +use std::cell::RefCell; +use std::fmt; +use std::rc::Rc; + +pub type Array = Rc>>; +pub type Object = Rc, Value>>>; + +#[derive(Clone)] +pub enum Value { + Null, + Bool(bool), + Number(f64), + Str(Rc), + Array(Array), + Object(Object), + Function(Rc), + Builtin(&'static Builtin), +} + +pub struct Closure { + pub def: Rc, + pub env: Env, +} + +pub struct Builtin { + pub name: &'static str, + pub arity: Arity, + pub func: BuiltinFn, + pub doc: &'static str, +} + +pub type BuiltinFn = fn(&mut Interpreter, Vec) -> Result; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Arity { + Exact(usize), + AtLeast(usize), + Between(usize, usize), +} + +impl Arity { + pub fn accepts(self, n: usize) -> bool { + match self { + Arity::Exact(k) => n == k, + Arity::AtLeast(k) => n >= k, + Arity::Between(lo, hi) => (lo..=hi).contains(&n), + } + } + + pub fn describe(self) -> String { + let plural = |n: usize| if n == 1 { "argument" } else { "arguments" }; + match self { + Arity::Exact(k) => format!("exactly {k} {}", plural(k)), + Arity::AtLeast(k) => format!("at least {k} {}", plural(k)), + Arity::Between(lo, hi) => format!("between {lo} and {hi} arguments"), + } + } +} + +impl Value { + pub fn array(items: Vec) -> Value { + Value::Array(Rc::new(RefCell::new(items))) + } + + pub fn object(map: IndexMap, Value>) -> Value { + Value::Object(Rc::new(RefCell::new(map))) + } + + pub fn str(s: impl Into>) -> Value { + Value::Str(s.into()) + } + + pub fn type_name(&self) -> &'static str { + match self { + Value::Null => "mew", + Value::Bool(_) => "boolean", + Value::Number(_) => "number", + Value::Str(_) => "whiskers", + Value::Array(_) => "furrball", + Value::Object(_) => "object", + Value::Function(_) | Value::Builtin(_) => "pawction", + } + } + + /// Zero and the empty string are truthy, so `purrhaps (count)` does not skip zero. + pub fn is_truthy(&self) -> bool { + !matches!(self, Value::Null | Value::Bool(false)) + } + + /// Like `Display`, but strings are quoted. + pub fn repr(&self) -> String { + let mut out = String::new(); + self.repr_into(&mut out, 0); + out + } + + fn repr_into(&self, out: &mut String, depth: usize) { + if depth > 24 { + out.push_str("..."); + return; + } + match self { + Value::Str(s) => { + out.push('"'); + for c in s.chars() { + match c { + '"' => out.push_str("\\\""), + '\\' => out.push_str("\\\\"), + '\n' => out.push_str("\\n"), + '\t' => out.push_str("\\t"), + '\r' => out.push_str("\\r"), + c => out.push(c), + } + } + out.push('"'); + } + Value::Array(items) => { + out.push('['); + for (i, item) in items.borrow().iter().enumerate() { + if i > 0 { + out.push_str(", "); + } + item.repr_into(out, depth + 1); + } + out.push(']'); + } + Value::Object(map) => { + out.push('{'); + for (i, (k, v)) in map.borrow().iter().enumerate() { + if i > 0 { + out.push_str(", "); + } + if is_plain_key(k) { + out.push_str(k); + } else { + Value::Str(k.clone()).repr_into(out, depth + 1); + } + out.push_str(": "); + v.repr_into(out, depth + 1); + } + out.push('}'); + } + other => out.push_str(&other.to_string()), + } + } +} + +fn is_plain_key(k: &str) -> bool { + let mut chars = k.chars(); + match chars.next() { + Some(c) if c == '_' || c.is_alphabetic() => chars.all(|c| c == '_' || c.is_alphanumeric()), + _ => false, + } +} + +pub fn format_number(n: f64) -> String { + if n.is_nan() { + "NaN".to_string() + } else if n.is_infinite() { + if n > 0.0 { + "Infinity".to_string() + } else { + "-Infinity".to_string() + } + } else if n == 0.0 { + "0".to_string() + } else { + n.to_string() + } +} + +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Value::Null => f.write_str("mew"), + Value::Bool(true) => f.write_str("purrfect"), + Value::Bool(false) => f.write_str("clawful"), + Value::Number(n) => f.write_str(&format_number(*n)), + Value::Str(s) => f.write_str(s), + Value::Array(_) | Value::Object(_) => f.write_str(&self.repr()), + Value::Function(c) => match &c.def.name { + Some(name) => write!(f, ""), + None => f.write_str(""), + }, + Value::Builtin(b) => write!(f, "", b.name), + } + } +} + +impl fmt::Debug for Value { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.repr()) + } +} + +/// Structural for data, identity for functions. +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Value::Null, Value::Null) => true, + (Value::Bool(a), Value::Bool(b)) => a == b, + (Value::Number(a), Value::Number(b)) => a == b, + (Value::Str(a), Value::Str(b)) => a == b, + (Value::Array(a), Value::Array(b)) => Rc::ptr_eq(a, b) || *a.borrow() == *b.borrow(), + (Value::Object(a), Value::Object(b)) => { + Rc::ptr_eq(a, b) || { + let (a, b) = (a.borrow(), b.borrow()); + a.len() == b.len() && a.iter().all(|(k, v)| b.get(k) == Some(v)) + } + } + (Value::Function(a), Value::Function(b)) => Rc::ptr_eq(a, b), + (Value::Builtin(a), Value::Builtin(b)) => std::ptr::eq(*a, *b), + _ => false, + } + } +} + +impl From for Value { + fn from(n: f64) -> Self { + Value::Number(n) + } +} + +impl From for Value { + fn from(n: usize) -> Self { + Value::Number(n as f64) + } +} + +impl From for Value { + fn from(b: bool) -> Self { + Value::Bool(b) + } +} + +impl From<&str> for Value { + fn from(s: &str) -> Self { + Value::Str(s.into()) + } +} + +impl From for Value { + fn from(s: String) -> Self { + Value::Str(s.into()) + } +} + +impl From> for Value { + fn from(items: Vec) -> Self { + Value::array(items) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn numbers_print_like_a_human_would_write_them() { + assert_eq!(format_number(3.0), "3"); + assert_eq!(format_number(3.5), "3.5"); + assert_eq!(format_number(-0.0), "0"); + assert_eq!(format_number(1e21), "1000000000000000000000"); + assert_eq!(format_number(f64::INFINITY), "Infinity"); + } + + #[test] + fn repr_quotes_nested_strings_only() { + let v = Value::array(vec![Value::from("a"), Value::from(1.0), Value::Null]); + assert_eq!(v.to_string(), r#"["a", 1, mew]"#); + assert_eq!(Value::from("a").to_string(), "a"); + assert_eq!(Value::from("a\"b").repr(), r#""a\"b""#); + } + + #[test] + fn objects_print_in_insertion_order() { + let mut map = IndexMap::new(); + map.insert("name".into(), Value::from("Tom")); + map.insert("has space".into(), Value::from(true)); + assert_eq!( + Value::object(map).to_string(), + r#"{name: "Tom", "has space": purrfect}"# + ); + } + + #[test] + fn equality_is_structural_for_data() { + assert_eq!( + Value::array(vec![Value::from(1.0)]), + Value::array(vec![Value::from(1.0)]) + ); + assert_ne!(Value::from(1.0), Value::from("1")); + assert_ne!(Value::Null, Value::Bool(false)); + } +} diff --git a/crates/meowscript/tests/examples.rs b/crates/meowscript/tests/examples.rs new file mode 100644 index 0000000..b8313f7 --- /dev/null +++ b/crates/meowscript/tests/examples.rs @@ -0,0 +1,99 @@ +//! Runs every program in `examples/`. One with a sibling `.out` file must print exactly that; +//! one without must only run without error. `// test: skip` marks programs that sleep or read +//! input. `UPDATE_SNAPSHOTS=1` rewrites the `.out` files. + +use meowscript::{BufferHost, Error, Host, Interpreter, Result}; +use std::path::{Path, PathBuf}; + +#[derive(Clone)] +struct ExampleHost(BufferHost); + +impl Host for ExampleHost { + fn print(&mut self, line: &str) { + self.0.print(line); + } + + fn read_file(&mut self, path: &str) -> Result { + std::fs::read_to_string(path) + .map_err(|e| Error::io(format!("could not read `{path}`: {e}"))) + } + + fn file_exists(&mut self, path: &str) -> bool { + Path::new(path).exists() + } + + fn random_seed(&mut self) -> u64 { + 1 + } +} + +fn examples_dir() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("..") + .join("examples") +} + +#[test] +fn examples_run_and_match_their_snapshots() { + let dir = examples_dir(); + let mut programs: Vec = std::fs::read_dir(&dir) + .expect("examples directory") + .filter_map(|e| e.ok().map(|e| e.path())) + .filter(|p| p.extension().is_some_and(|x| x == "meow")) + .collect(); + programs.sort(); + assert!( + !programs.is_empty(), + "no examples found in {}", + dir.display() + ); + + let update = std::env::var_os("UPDATE_SNAPSHOTS").is_some(); + let mut failures = Vec::new(); + let mut checked = 0; + + for path in programs { + let name = path.file_name().unwrap().to_string_lossy().into_owned(); + let source = std::fs::read_to_string(&path).unwrap(); + if source.contains("// test: skip") { + continue; + } + checked += 1; + + let host = ExampleHost(BufferHost::new()); + let mut interp = Interpreter::new(host.clone()); + interp.set_base_dir(Some(dir.to_string_lossy().into_owned())); + + if let Err(e) = interp.run(&source) { + failures.push(format!( + "{name} failed:\n{}", + e.render(&source, Some(&name)) + )); + continue; + } + + let snapshot = path.with_extension("out"); + let actual = { + let mut s = host.0.output(); + s.push('\n'); + s + }; + if update { + std::fs::write(&snapshot, &actual).unwrap(); + } else if snapshot.exists() { + let expected = std::fs::read_to_string(&snapshot) + .unwrap() + .replace("\r\n", "\n"); + if expected != actual { + failures.push(format!( + "{name} printed something different from {}:\n--- expected\n{expected}--- actual\n{actual}", + snapshot.file_name().unwrap().to_string_lossy() + )); + } + } + } + + assert!(checked > 0, "every example was skipped"); + assert!(failures.is_empty(), "\n{}", failures.join("\n\n")); +} diff --git a/examples/closures.meow b/examples/closures.meow new file mode 100644 index 0000000..628996b --- /dev/null +++ b/examples/closures.meow @@ -0,0 +1,17 @@ +// Pawctions remember the scope they were born in. +pawction make_counter(name) { + scratch count = 0; + tail pawction() { + amew count = count + 1; + meow(name, "has been petted", count, "times"); + tail count; + }; +} + +scratch pet_tom = make_counter("Tom"); +scratch pet_luna = make_counter("Luna"); + +pet_tom(); +pet_tom(); +pet_luna(); +pet_tom(); diff --git a/examples/closures.out b/examples/closures.out new file mode 100644 index 0000000..d42d6a1 --- /dev/null +++ b/examples/closures.out @@ -0,0 +1,4 @@ +Meow! Tom has been petted 1 times +Meow! Tom has been petted 2 times +Meow! Luna has been petted 1 times +Meow! Tom has been petted 3 times diff --git a/examples/fizzbuzz.meow b/examples/fizzbuzz.meow new file mode 100644 index 0000000..8fe0331 --- /dev/null +++ b/examples/fizzbuzz.meow @@ -0,0 +1,15 @@ +// The classic, with a cat's vocabulary. +pawction fizzbuzz(n) { + purrhaps n % 15 == 0 { + tail "FizzBuzz"; + } meowtually purrhaps n % 3 == 0 { + tail "Fizz"; + } meowtually purrhaps n % 5 == 0 { + tail "Buzz"; + } + tail n; +} + +fur i ~ 15 { + purr(fizzbuzz(i + 1)); +} diff --git a/examples/fizzbuzz.out b/examples/fizzbuzz.out new file mode 100644 index 0000000..0a934f2 --- /dev/null +++ b/examples/fizzbuzz.out @@ -0,0 +1,15 @@ +1 +2 +Fizz +4 +Buzz +Fizz +7 +8 +Fizz +Buzz +11 +Fizz +13 +14 +FizzBuzz diff --git a/examples/furrball.meow b/examples/furrball.meow new file mode 100644 index 0000000..acbca90 --- /dev/null +++ b/examples/furrball.meow @@ -0,0 +1,24 @@ +// A tour of the nya:furrball pawckage. +pawckage "nya:furrball"; + +scratch cats = ["Tom", "Garfield", "Felix", "Salem"]; +push(cats, "Luna"); +purr("We have", length(cats), "cats:", join(cats, ", ")); + +scratch shouty = map(cats, pawction(name) { name + "!" }); +purr(shouty); + +scratch short_names = filter(cats, pawction(name) { length(name) <= 4 }); +purr("Short names:", short_names); + +scratch letters = reduce(cats, pawction(total, name) { total + length(name) }, 0); +purr("Letters in all the names:", letters); + +purr("Sorted:", sort(cats)); +purr("Backwards:", reverse(cats)); +purr("The middle two:", slice(cats, 1, 3)); +purr("Is Salem here?", "Salem" ~ cats); +purr("Squares:", map(range(1, 6), pawction(n) { n * n })); + +scratch last_cat = pounce(cats); +purr(last_cat, "left, so now there are", length(cats)); diff --git a/examples/furrball.out b/examples/furrball.out new file mode 100644 index 0000000..e88397f --- /dev/null +++ b/examples/furrball.out @@ -0,0 +1,10 @@ +We have 5 cats: Tom, Garfield, Felix, Salem, Luna +["Tom!", "Garfield!", "Felix!", "Salem!", "Luna!"] +Short names: ["Tom", "Luna"] +Letters in all the names: 25 +Sorted: ["Felix", "Garfield", "Luna", "Salem", "Tom"] +Backwards: ["Luna", "Salem", "Felix", "Garfield", "Tom"] +The middle two: ["Garfield", "Felix"] +Is Salem here? purrfect +Squares: [1, 4, 9, 16, 25] +Luna left, so now there are 4 diff --git a/examples/hello.meow b/examples/hello.meow new file mode 100644 index 0000000..83d1cc1 --- /dev/null +++ b/examples/hello.meow @@ -0,0 +1,5 @@ +// Every program starts with a meow. +meow("Hello, world!"); + +// purr prints without the announcement. +purr("The cat says:", "meow", 3, "times"); diff --git a/examples/hello.out b/examples/hello.out new file mode 100644 index 0000000..60497be --- /dev/null +++ b/examples/hello.out @@ -0,0 +1,2 @@ +Meow! Hello, world! +The cat says: meow 3 times diff --git a/examples/lib/kitty_math.meow b/examples/lib/kitty_math.meow new file mode 100644 index 0000000..76a6d1e --- /dev/null +++ b/examples/lib/kitty_math.meow @@ -0,0 +1,13 @@ +// A pawckage is just a .meow file. Everything scratched at the top level +// is shared with whoever pawckages it. The nya: pawckages it uses stay private. +pawckage "nya:catculator"; + +scratch NINE_LIVES = 9; + +pawction lives_left(deaths) { + tail max(NINE_LIVES - deaths, 0); +} + +pawction circle_area(radius) { + tail round(PI * radius * radius); +} diff --git a/examples/naptime.meow b/examples/naptime.meow new file mode 100644 index 0000000..0118f15 --- /dev/null +++ b/examples/naptime.meow @@ -0,0 +1,17 @@ +// test: skip (this one sleeps) +// nap() pauses the program. In the playground, watch the output arrive live. +pawckage "nya:clawtility"; +pawckage "nya:rundamn"; + +pawction take_a_nap() { + furrever { + meow("...zZz..."); + nap(600); + purrhaps randint(1, 3) == 3 { + hiss; + } + } + meow("I woke up! ^-^"); +} + +take_a_nap(); diff --git a/examples/packages.meow b/examples/packages.meow new file mode 100644 index 0000000..7c1e343 --- /dev/null +++ b/examples/packages.meow @@ -0,0 +1,6 @@ +// Pulling in another file with pawckage. The path is relative to this file. +pawckage "./lib/kitty_math.meow"; + +purr("A cat that fell off the sofa twice has", lives_left(2), "lives left."); +purr("A round cat of radius 3 covers about", circle_area(3), "square paws."); +purr("Nine lives is", NINE_LIVES); diff --git a/examples/packages.out b/examples/packages.out new file mode 100644 index 0000000..9772e1d --- /dev/null +++ b/examples/packages.out @@ -0,0 +1,3 @@ +A cat that fell off the sofa twice has 7 lives left. +A round cat of radius 3 covers about 28 square paws. +Nine lives is 9 diff --git a/examples/recursion.meow b/examples/recursion.meow new file mode 100644 index 0000000..d8c9614 --- /dev/null +++ b/examples/recursion.meow @@ -0,0 +1,14 @@ +// Recursion, and purrhaps as an expression. +pawction fib(n) { + purrhaps n < 2 { tail n; } + tail fib(n - 1) + fib(n - 2); +} + +pawction factorial(n) { + purrhaps n <= 1 { 1 } meowtually { n * factorial(n - 1) } +} + +fur i ~ 10 { + purr("fib(" + i + ") =", fib(i)); +} +purr("10! =", factorial(10)); diff --git a/examples/recursion.out b/examples/recursion.out new file mode 100644 index 0000000..f926554 --- /dev/null +++ b/examples/recursion.out @@ -0,0 +1,11 @@ +fib(0) = 0 +fib(1) = 1 +fib(2) = 1 +fib(3) = 2 +fib(4) = 3 +fib(5) = 5 +fib(6) = 8 +fib(7) = 13 +fib(8) = 21 +fib(9) = 34 +10! = 3628800 diff --git a/examples/toy.meow b/examples/toy.meow new file mode 100644 index 0000000..546386a --- /dev/null +++ b/examples/toy.meow @@ -0,0 +1,23 @@ +// Random choices from the nya:rundamn pawckage. +pawckage "nya:rundamn"; + +scratch toy_box = ["Feather Wand", "Catnip Mouse", "Yarn Ball", "Squeaky Mouse"]; + +pawction play_with(toy) { + scratch sessions = randint(3, 6); + meow("Let's play with the", toy + "!"); + + fur session ~ sessions { + purrhaps toy == "Feather Wand" { + meow("Chasing the feather!"); + } meowtually purrhaps toy == "Squeaky Mouse" { + meow("Squeak! Squeak!"); + } meowtually { + meow("Having fun with the", toy); + } + } + + meow("I'm tired now. Time for a catnap!"); +} + +play_with(choice(toy_box)); diff --git a/examples/whiskers.meow b/examples/whiskers.meow new file mode 100644 index 0000000..8ebc8d6 --- /dev/null +++ b/examples/whiskers.meow @@ -0,0 +1,17 @@ +// A tour of the nya:whiskers pawckage. +pawckage "nya:whiskers"; + +scratch greeting = " meow meow, purr "; +purr("[" + trim(greeting) + "]"); +purr(upper(trim(greeting))); +purr(split(trim(greeting), " ")); +purr(replace(trim(greeting), "meow", "nya")); +purr(starts_with(trim(greeting), "meow"), ends_with(trim(greeting), "purr")); +purr(pawrse("42") + 1, pawrse("nine")); +purr(pad_start("7", 3, "0"), "|" + pad_end("cat", 6, ".") + "|"); +purr(reverse("stressed")); +purr(length("🐱 cat"), "characters"); + +fur letter ~ "cat" { + purr(letter, "-", letter * 3); +} diff --git a/examples/whiskers.out b/examples/whiskers.out new file mode 100644 index 0000000..956efba --- /dev/null +++ b/examples/whiskers.out @@ -0,0 +1,12 @@ +[meow meow, purr] +MEOW MEOW, PURR +["meow", "meow,", "purr"] +nya nya, purr +purrfect purrfect +43 mew +007 |cat...| +desserts +5 characters +c - ccc +a - aaa +t - ttt diff --git a/examples/yarn.meow b/examples/yarn.meow new file mode 100644 index 0000000..f3800e0 --- /dev/null +++ b/examples/yarn.meow @@ -0,0 +1,24 @@ +// Objects, the possessive 's, and a loop with a condition. +scratch cat = { + name: "Whiskers", + age: 3, + breed: "Siamese", + color: "seal point", +}; + +scratch months = cat's age * 12; +meow(cat's name, "is a", cat's color, cat's breed, "cat. He is", months, "months old."); + +pawction play_with_yarn(lives) { + meow("Let's play with yarn!"); + furrever lives > 0 { + meow(cat's name, "is playing with yarn, round", 10 - lives); + amew lives = lives - 1; + } + meow("Finished playing with yarn!"); +} + +play_with_yarn(9); + +amew cat's age = cat's age + 1; +meow("Happy birthday!", cat's name, "is now", cat's age); diff --git a/lib.js b/lib.js deleted file mode 100644 index c965486..0000000 --- a/lib.js +++ /dev/null @@ -1,4 +0,0 @@ -mergeInto(LibraryManager.library, { - bark: function() { - } -}) \ No newline at end of file diff --git a/makefile b/makefile deleted file mode 100644 index 4f7e3fd..0000000 --- a/makefile +++ /dev/null @@ -1,5 +0,0 @@ -.PHONY: -wasm: - cargo build --release --target wasm32-unknown-emscripten -Z build-std=panic_abort,std - cp target/wasm32-unknown-emscripten/release/meowscript.js site/public/meowscript.js - cp target/wasm32-unknown-emscripten/release/meowscript.wasm site/public/meowscript.wasm \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..c38c8a8 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "stable" +components = ["rustfmt", "clippy"] +targets = ["wasm32-unknown-unknown"] diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..ed49ca7 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,2 @@ +edition = "2024" +max_width = 100 diff --git a/site/.gitignore b/site/.gitignore index c87c9b3..43bcb3e 100644 --- a/site/.gitignore +++ b/site/.gitignore @@ -1,12 +1,7 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - # dependencies /node_modules /.pnp -.pnp.js - -# testing -/coverage +.pnp.* # next.js /.next/ @@ -25,8 +20,8 @@ yarn-debug.log* yarn-error.log* .pnpm-debug.log* -# local env files -.env*.local +# env files +.env* # vercel .vercel diff --git a/site/README.md b/site/README.md index 72dcdef..7042792 100644 --- a/site/README.md +++ b/site/README.md @@ -1,96 +1,18 @@ -# MeowScript -## the purrfect programming language +# MeowScript site - -Meow Script is a simple interpreter inspired by cats, designed to make programming fun and intuitive. - -## Table of Contents - -- [Introduction](#introduction) -- [Features](#features) -- [Getting Started](#getting-started) -- [Documentation](#documentation) -- [Playground](#playground) -- [Contributing](#contributing) -- [License](#license) - -## Introduction - -Welcome to the Meow Script Interpreter repository! Meow Script is a playful and easy-to-learn programming language that cat lovers will adore. This README provides an overview of the project, its features, and how to get started. - -## Features - -- 🐱 Simple and cat-themed syntax. -- 🎮 Interactive playground to experiment with Meow Script. -- 📚 Comprehensive documentation for learning and reference. -- 🚀 Built with Next.js for a fast and responsive web experience. - -## Getting Started - -Follow these steps to set up the Meow Script interpreter locally: - -1. Clone the repository: - - ```bash - git clone https://github.com/alenvelocity/meowscript.git -Install dependencies: - -bash -Copy code -cd meow-script-interpreter -npm install -Start the development server: - -bash -Copy code -npm run dev -Open your browser and navigate to http://localhost:3000 to access the MeowScript interpreter. - -Documentation -Explore our comprehensive documentation to learn more about Meow Script's syntax, features, and how to use it effectively. Whether you're a beginner or an experienced developer, our documentation will help you get started. - -Playground -Visit our interactive playground to experiment with Meow Script code in real-time. It's a great place to test your ideas and see how Meow Script works. - -Contributing -We welcome contributions from the open-source community. If you'd like to contribute to the Meow Script Interpreter project, please follow our contributing guidelines. - - -Happy coding! 😺 - - - -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: +The playground and docs at [meowscript.vercel.app](https://meowscript.vercel.app). Next.js 16, React 19, Tailwind 4, CodeMirror 6. The interpreter runs in the browser as WebAssembly, inside a Web Worker so a runaway loop can be stopped. ```bash -npm run dev -# or -yarn dev +pnpm install +pnpm dev # http://localhost:3000 ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. - -[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. - -The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel +Three things are generated and committed, so the site builds anywhere without Rust: -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +| Command | Produces | From | +| ------------------ | ---------------------------- | -------------------------------------------- | +| `pnpm build:wasm` | `public/wasm/*` | `crates/meowscript-wasm` via wasm-pack | +| `pnpm sync` | `src/generated/examples.ts` | `../examples/*.meow` | +| `pnpm sync` | `src/generated/stdlib.ts` | `meowscript packages --json` (needs cargo) | -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +`pnpm build` runs `pnpm sync` first. When the sources are not around (on Vercel, say), the sync scripts leave the committed files alone. After changing the Rust code, run `pnpm build:wasm` and `pnpm sync` and commit the results. diff --git a/site/components/Code.tsx b/site/components/Code.tsx deleted file mode 100644 index 970eebd..0000000 --- a/site/components/Code.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import 'prismjs/themes/prism-tomorrow.css' - -import classNames from 'classnames' -import Prism, { highlight } from 'prismjs' -import React, { useEffect, useRef, useState } from 'react' -import Editor from 'react-simple-code-editor' -import useBreakpoint from 'use-breakpoint' - -import { MeowScriptWorker } from '../lib/MeowScriptWorker' -import { createMeowScriptWorker } from '../lib/create_meowscript_worker' -import { examples } from '../lib/example' -import { meowScriptSyntax } from '../lib/syntax' -import CodeDropdown from './CodeDropdown' - -const BREAKPOINTS = { mobile: 0, tablet: 768, desktop: 1280 } - -const defaultText = - '

Let\'s paw-ceed with some purr-gramming!

' - -const hightlightWithLineNumbers = (input: string) => - highlight(input, meowScriptSyntax, 'meowScript') - .split('\n') - .map((line, i) => `${i + 1}${line}`) - .join('\n') - -const Code = () => { - const [code, setCode] = useState(examples.yarn) - const [terminalText, setTerminalText] = useState(defaultText) - const { breakpoint } = useBreakpoint(BREAKPOINTS, 'mobile') - - const [loaded, setLoaded] = useState(false) - const [running, setRunning] = useState(false) - const [isUpsideDown, setIsUpsideDown] = useState(false) - - const meowScriptRef = useRef() - const rightsideUpCached = useRef('') - - const switchExample = (code: string) => { - rightsideUpCached.current = code - setIsUpsideDown(false) - setCode(code) - } - - useEffect(() => { - const run = async () => { - const [meowScript, worker] = await createMeowScriptWorker() - worker.onmessage = e => { - switch (e.data.type) { - case 'stderr': { - setTerminalText( - text => - text + - `${e.data.data}` + - '
' - ) - break - } - case 'stdout': { - setTerminalText(text => text + e.data.data + '
') - break - } - } - } - meowScriptRef.current = meowScript - setLoaded(true) - } - run() - Prism.highlightAll() - }, []) - return ( -
-
-
-
- hightlightWithLineNumbers(code)} - onValueChange={(v: string) => setCode(v || '')} - value={code} - /> -
-
-
-
- - -
- -
-
-
-
-

- Running with WebAssembly (Wasm) compiled from Rust ✨ -

-
-
-
-
- ) -} - -export default Code diff --git a/site/components/CodeDropdown.tsx b/site/components/CodeDropdown.tsx deleted file mode 100644 index eb67bb9..0000000 --- a/site/components/CodeDropdown.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { Menu, Transition } from '@headlessui/react' -import { ChevronDownIcon } from '@heroicons/react/solid' -import classNames from 'classnames' -import React, { Fragment, useState } from 'react' - -import { examples } from '../lib/example' - -const exampleList = [ - 'yarn.meow', - 'fizzbuzz.meow', - 'toy.meow', - 'naptime.meow' -] - -const getExample = (name: string) => { - return examples[name.split('.')[0]] -} - -const Item = ({ - active, - name, - onClick -}: { - active: boolean - name: string - onClick: () => void -}) => { - return ( - - ) -} - -type Props = { - setCode: (s: string) => void -} - -const CodeDropdown = ({ setCode }: Props) => { - const [activeExample, setActiveExample] = useState(exampleList[0]) - return ( - -
- - {activeExample} - -
- - - -
- {exampleList.map(name => { - return ( - - {() => ( - { - setCode(getExample(name)) - setActiveExample(name) - }} - /> - )} - - ) - })} -
-
-
-
- ) -} - -export default CodeDropdown diff --git a/site/components/Features.tsx b/site/components/Features.tsx deleted file mode 100644 index 0f5952a..0000000 --- a/site/components/Features.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react' - -const features = [ - { - name: 'Cat-inspired Keywords', - description: 'From purrhaps instead of if to meowtually instead of else, Meowscript adds a whole new level of catness to your programs.', - icon: '🐈' - }, - { - name: 'Paw-some Syntax', - description: - 'While being not easy to read, the syntax makes sure you have a Paw-some time writing code.', - icon: '😼' - }, - { - name: 'Fur-midable Performance', - description: 'Meowscript may be cute, but it\'s no kitten when it comes to performance. The language is designed to be fast, well faster than Python atleast.', - icon: '🙀' - } -] - -const Features = () => { - return ( -
-
-
- {features.map((feature, i) => ( -
-
-
- {feature.icon} -
-
-
- {feature.name}{' '} -
-
-
-
- {feature.description} -
-
- ))} -
-
-
- ) -} - -export default Features diff --git a/site/components/Head.tsx b/site/components/Head.tsx deleted file mode 100644 index f28379f..0000000 --- a/site/components/Head.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import NextHead from 'next/head' -import React from 'react' - -type MetaTag = { - name: string - content: string -} - -const metaTag = (name: string, content: string) => ({ name, content }) - -const title = '🐾 MeowScript' -const description = 'The Purrfect Programming Language' -const imageUrl = '/image.png' -const author = '@alenvelocity' - -const metaTags: MetaTag[] = [ - metaTag('description', description), - metaTag('og:title', title), - metaTag('og:description', description), - metaTag('og:image', imageUrl), - metaTag('twitter:card', 'summary'), - metaTag('twitter:site', title), - metaTag('twitter:title', title), - metaTag('twitter:creator', author), - metaTag('twitter:description', description), - metaTag('twitter:image', imageUrl) -] - -const Head = () => ( - - {title} - {metaTags.map(({ name, content }) => ( - - ))} - -) - -export default Head diff --git a/site/content/docs.md b/site/content/docs.md new file mode 100644 index 0000000..f783f4a --- /dev/null +++ b/site/content/docs.md @@ -0,0 +1,255 @@ +# MeowScript reference + +MeowScript is a small, dynamically typed scripting language. Its keywords are cat puns, its values are the usual ones under different names, and its interpreter is written in Rust. This page is the whole language. + +If you just want to poke at it, the [playground](/#playground) runs everything on this page. Every listing has a *Try it* button. + +## A first program + +```meow +scratch cat = { name: "Whiskers", lives: 9 }; + +pawction describe(c) { + tail c's name + " has " + c's lives + " lives"; +} + +meow(describe(cat)); +``` + +Statements end with a semicolon. You may leave it off before a closing `}` and at the very end of a file, and after anything that already ends in a `}` such as a `purrhaps` or a `pawction` declaration. + +Comments are `// to the end of the line` or `/* anywhere in between */`. + +## Printing + +`meow` prints its arguments separated by spaces, announced with `Meow!`. `purr` prints them without the announcement. `log` is the same as `purr`, for people who miss JavaScript. + +```meow +meow("hello", 42, purrfect); // Meow! hello 42 purrfect +purr("hello", 42, purrfect); // hello 42 purrfect +``` + +## Values + +| Type | Called | Looks like | +| --- | --- | --- | +| number | `number` | `42`, `3.5`, `1_000`, `2e3` | +| string | `whiskers` | `"meow"` | +| boolean | `boolean` | `purrfect`, `clawful` | +| null | `mew` | `mew` | +| array | `furrball` | `[1, 2, 3]` | +| object | `object` | `{ name: "Tom", age: 3 }` | +| function | `pawction` | `pawction(a, b) { tail a + b; }` | + +`furreal` tells you which one you have: `furreal []` is `"furrball"`. + +### Numbers + +All numbers are 64-bit floats. Whole numbers print without a decimal point. Dividing by zero is an error rather than infinity. + +### Whiskers + +Strings use double quotes and understand `\n`, `\t`, `\"`, `\\`, and `\u{1F431}`. They may span lines. + +`+` joins whiskers with anything, converting the other side the way `meow` would print it. `*` repeats. + +```meow +purr("cats: " + 3); // cats: 3 +purr("=^.^= " * 3); // =^.^= =^.^= =^.^= +purr("meow"[0]); // m +purr("meow"[-1]); // w +``` + +### Furrballs + +Furrballs are arrays. Indexes start at 0 and negative indexes count from the end. Reading past either end is an error, not `mew`. + +```meow +scratch toys = ["yarn", "box"]; +purr(toys[0], toys[-1]); // yarn box +amew toys[1] = "sunbeam"; +purr(toys); // ["yarn", "sunbeam"] +``` + +Furrballs and objects are shared, not copied. Two variables pointing at the same furrball see the same changes, like in JavaScript or Python. `==` compares contents, though, so `[1, 2] == [1, 2]` is `purrfect`. + +### Objects + +Objects are ordered maps from whiskers to values. Keys can be written bare or quoted; `{ name }` is short for `{ name: name }`; `[expr]` computes a key. + +Read a key with `obj's key` or `obj["key"]`. A key that isn't there gives `mew`. Write one with `amew`. + +```meow +scratch cat = { name: "Tom", "fur color": "grey" }; +purr(cat's name, cat["fur color"]); +amew cat's age = 4; +purr("age" ~ cat); // purrfect +``` + +## Variables + +`scratch` declares a variable in the current scope. `amew` changes one that already exists, searching outward through enclosing scopes. Using `amew` on a name that was never scratched is an error, and so is reading one, with a *did you mean* hint when there's a close match. + +```meow +scratch lives = 9; +purrhaps purrfect { + amew lives = lives - 1; // changes the outer `lives` + scratch lives = 100; // a new, inner `lives` +} +purr(lives); // 8 +``` + +Blocks, loops, and pawction calls each open a new scope. + +## Operators + +From loosest to tightest binding. Operators on the same row are applied left to right. + +| Operators | Meaning | +| --- | --- | +| `\|\|` | or (short-circuits, returns the deciding value) | +| `&&` | and (short-circuits, returns the deciding value) | +| `==` `!=` | equal, not equal (by contents) | +| `<` `>` `<=` `>=` `~` | compare; `~` is "is in" | +| `\|` | bitwise or | +| `^` | bitwise xor | +| `&` | bitwise and | +| `<<` `>>` | shift | +| `+` `-` | add, subtract (and join whiskers or furrballs) | +| `*` `/` `%` | multiply, divide, remainder (and repeat whiskers) | +| `-x` `!x` `furreal x` | negate, not, type of | +| `f(x)` `a[i]` `a's b` | call, index, property | + +This is the ordering Python and Rust use, so `6 & 3 == 2` means `(6 & 3) == 2`. + +`~` works on all three containers: `2 ~ [1, 2]`, `"age" ~ cat`, and `"ow" ~ "meow"`. + +Only `mew` and `clawful` are falsy. `0`, `""`, and `[]` are all truthy, so `purrhaps count { ... }` doesn't skip zero. + +## Conditions + +`purrhaps` is if, `meowtually` is else. Parentheses around the condition are optional. Chains work as you'd expect. + +```meow +purrhaps hour < 6 { + meow("too early"); +} meowtually purrhaps hour < 12 { + meow("breakfast time"); +} meowtually { + meow("second breakfast time"); +} +``` + +`purrhaps` is an expression. A block's value is the value of its last statement, so you can use it on the right of a `scratch` or as the last line of a pawction. + +```meow +scratch mood = purrhaps fed { "purring" } meowtually { "plotting" }; +``` + +## Loops + +`furrever` loops forever, or while a condition holds if you give one. `hiss` breaks out; `continue` skips to the next round. + +```meow +scratch n = 0; +furrever { + amew n = n + 1; + purrhaps n % 2 == 0 { continue; } + purrhaps n > 7 { hiss; } + purr(n); +} + +furrever n > 0 { + amew n = n - 3; +} +``` + +`fur` walks over something: the items of a furrball, the characters of whiskers, the keys of an object, or the numbers from 0 up to (not including) a number. + +```meow +fur toy ~ ["yarn", "box"] { purr(toy); } +fur letter ~ "cat" { purr(letter); } +fur key ~ { a: 1, b: 2 } { purr(key); } +fur i ~ 3 { purr(i); } // 0 1 2 +``` + +## Pawctions + +Declare a named pawction, or make an anonymous one and keep it in a variable. Either way they are values: pass them around, return them, put them in furrballs. + +```meow +pawction add(a, b) { + tail a + b; +} + +scratch double = pawction(x) { x * 2 }; + +purr(add(2, 3), double(4)); +``` + +`tail` returns. If a pawction runs off the end, it returns the value of its last statement, which is why `double` above works without one. A pawction with no useful last statement returns `mew`. + +Pawctions close over the scope they were made in: + +```meow +pawction counter() { + scratch n = 0; + tail pawction() { + amew n = n + 1; + tail n; + }; +} + +scratch next = counter(); +next(); next(); +purr(next()); // 3 +``` + +Calling with the wrong number of arguments is an error. So is nesting calls more than a thousand deep, which usually means a recursion with no way out. + +## Pawckages + +`pawckage` pulls in a library. The built-in ones start with `nya:` and are listed under [Standard library](#standard-library). + +```meow +pawckage "nya:furrball"; +pawckage "nya:catculator"; + +purr(map(range(5), pawction(n) { round(sqrt(n)) })); +``` + +Any `.meow` file is also a pawckage. Everything `scratch`ed or declared at its top level becomes available to whoever imports it. Paths are relative to the importing file, and the `.meow` can be left off. + +```meow +pawckage "./lib/kitty_math"; +purr(lives_left(2)); +``` + +File pawckages need a filesystem, so they work from the command line but not in the browser playground. + +## Errors + +Every error says what went wrong and points at where: + +``` +Furbidden! type error: `-` doesn't work between whiskers and a number + --> toys.meow:4:12 + | + 4 | scratch n = "nine" - 1; + | ^^^^^^^^^^ +``` + +The exclamation tells you the kind: *Meowch!* for syntax, *Meow-sterious!* for an unknown name, *Furbidden!* for a type mismatch, *Paws off!* for the wrong number of arguments, *Lost kitten!* for a pawckage that can't be found, *Scratched!* for file trouble, and *Hiss!* for everything else at run time. + +## The command line + +``` +cargo install --git https://github.com/AlenVelocity/MeowScript meowscript-cli + +meowscript # start the REPL +meowscript hello.meow # run a file +meowscript eval "1 + 2" # evaluate a snippet +meowscript packages # list the nya: pawckages +``` + +The REPL keeps reading lines while a block is open, prints the value of each expression, and leaves when you type `scram`. diff --git a/site/eslint.config.mjs b/site/eslint.config.mjs new file mode 100644 index 0000000..51f2730 --- /dev/null +++ b/site/eslint.config.mjs @@ -0,0 +1,11 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts", "public/wasm/**", "src/generated/**"]), +]); + +export default eslintConfig; diff --git a/site/lib/MeowScriptWorker.ts b/site/lib/MeowScriptWorker.ts deleted file mode 100644 index 345dc60..0000000 --- a/site/lib/MeowScriptWorker.ts +++ /dev/null @@ -1,69 +0,0 @@ -import * as Comlink from 'comlink' - -// @ts-ignore -// eslint-disable-next-line no-undef -importScripts('/meowscript.js') - -export class MeowScriptWorker { - module: any - - async initWasm() { - // @ts-ignore - // eslint-disable-next-line no-undef - this.module = await MeowScript({ - mainScriptUrlOrBlob: '/meowscript.js', - locateFile: (path: string) => { - if (path === 'meowscript.wasm') { - return `/${path}` - } - }, - print: (t: string) => { - // @ts-ignore - postMessage({ type: 'stdout', data: t }) - }, - printErr: (t: string) => { - // @ts-ignore - postMessage({ type: 'stderr', data: t }) - } - }) - - console.log(this.module) - } - - run(code: string, isUpsideDown: boolean) { - const ptr = this.passStringToWasm(code) - - // `_interpret()` will take ownership of `ptr` and deallocate it - this.module._interpret(ptr, isUpsideDown) - } - - flip(code: string, upsideDown: boolean): string { - const ptr = this.passStringToWasm(code) - - const lenPtr = this.module._alloc(4) - const outputPtr = this.module._flip_text(ptr, lenPtr, upsideDown) - const outputLen = this.getLen(lenPtr) - - const str = this.module.UTF8ToString(outputPtr, outputLen) - - this.module._dealloc(lenPtr, 4) - this.module._dealloc(outputPtr, outputLen) - - return str - } - - passStringToWasm(str: string) { - const intArray = this.module.intArrayFromString(str) - const ptr = this.module._alloc(intArray.length) - this.module.writeArrayToMemory(intArray, ptr) - - return ptr - } - - getLen(lenPtr: number) { - const buf = new Uint8Array(this.module.HEAPU8, lenPtr, 4) - return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0] - } -} - -Comlink.expose(MeowScriptWorker) diff --git a/site/lib/create_meowscript_worker.ts b/site/lib/create_meowscript_worker.ts deleted file mode 100644 index de8eb0f..0000000 --- a/site/lib/create_meowscript_worker.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as Comlink from 'comlink' - -import type { MeowScriptWorker } from './MeowScriptWorker' - -export const createMeowScriptWorker = async (): Promise< - [wrapped: MeowScriptWorker, underlying: Worker] -> => { - // @ts-ignore - const worker = new Worker(new URL('./MeowScriptWorker.ts', import.meta.url)) - - // @ts-ignore - const WorkerClass: new ( - ..._args: ConstructorParameters - ) => // @ts-ignore - InstanceType> = Comlink.wrap(worker) - - const meowScriptWorker: MeowScriptWorker = await new WorkerClass() - await meowScriptWorker.initWasm() - - return [meowScriptWorker, worker] -} diff --git a/site/lib/docs.md b/site/lib/docs.md deleted file mode 100644 index d172251..0000000 --- a/site/lib/docs.md +++ /dev/null @@ -1,98 +0,0 @@ -# Docs -`MeowScript` is a dynamically-typed and interpreted language inspired by cat-puns - -## Keywords - -- `scratch`: Used to declare a variable. For example, `scratch x = 10;` declares a variable `x` with the value `10`. - -- `amew`: Used to reassign a new value to an existing variable. For example, `amew x = 5;` changes the value of the variable `x` to `5`. -- `pawction`: Used to define a function. For example, - ``` - scratch greet = pawction() { - meow("Meow!"); - }; - ``` -defines a function `greet` that prints "Meow!" to the console. -- `purrhaps`: Used to start an if statement. Example: - ``` - purrhaps x > y { - meow(x is greater than y!"); - } - ``` - - -- `meowtually`: Used to start the else block of an if statement. Example: - -``` -purrhaps x > y { - meow("x is greater than y!"); -} meowtually { - meow("x is not greater than y!"); -} -``` - - -- `tail`: Used to return a value from a function. Example -``` -scratch add = pawction(a, b) { - tail a + b; -} -``` - -- `pawckage`: Used to include external code from other packages. For example, -``` -pawckage "file.meow"; -``` -> NOTE: SEMICOLON IS NOT OPTIONAL - - -## Types / Variables - -All of the types are similar to other C-like languages, but we have specific names for certain types - -`whiskers` - Strings - -Eg: ```scratch say = "Meow!";``` - -Note: They must be enclosed in double quotes - -`furrball` - Arrays - -Eg: ```scratch words = ["Meow", "Nya", "Nyo"];``` - -Boolean: -- `purrfect`: Represents the boolean value `true`. -- `clawful`: Represents the boolean value `false`. - -The `furreal` operator can be used to check the type of a variable. For example, `furreal x;` checks the type of variable `x`. - -## Loops - -There's only a single type of loop in MeowScript - -The keyword `furrever` can be used to start a loop that runs indefinitely. For example, `furrever { scratch("Meow!"); }` runs the block of code inside the loop forever. - -### Loop Control -The following keywords can be used for manupilating the contorl flow of the loop - -- `hiss`: Used to break out of a loop. For example, `furrever { hiss; }` will break the loop immediately. -- `continue`: Used to skip the current iteration and continue to the next one in a loop. For example, `pawction loop() { furrever { continue; } }` will run the loop indefinitely but will skip each iteration. - -## Standard Libraries - -Meowscript comes with a lot of Builtin Functions. - -### General - - -meow() -- Prints the given values into the stdout -``` -meow([...values]) -``` - -The following will be documented soon. Refer the [src](https://github.com/AlenVelocity/MeowScript/tree/master/src/std_library) for now -### Lib 1 nya:clawtility -### Lib 2 nya:catculator -### Lib 3 nya:whiskers -### Lib 2 nya:furrball diff --git a/site/lib/docs.ts b/site/lib/docs.ts deleted file mode 100644 index d5c1957..0000000 --- a/site/lib/docs.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { readFile } from 'fs' -import { join } from 'path' - -const docs = join(process.cwd(), 'lib', 'docs.md') - -export const readDocsFile = async () => { - return new Promise((resolve, reject) => { - readFile( - docs, - { - encoding: 'utf8' - }, - (err, data) => { - if (err) return reject(err) - return resolve(data) - } - ) - }) -} diff --git a/site/lib/example.ts b/site/lib/example.ts deleted file mode 100644 index 26ac9d7..0000000 --- a/site/lib/example.ts +++ /dev/null @@ -1,133 +0,0 @@ -const naptime = ` -// --------- NOTE ---------------------------------------------------------------- -// This program will not function properly in the browser due to WASM Limitations. -// Please use a compiled Binary -// ------------------------------------------------------------------------------- -pawckage "nya:clawtility"; -pawckage "nya:catculator"; - -scratch take_a_nap = pawction () { - - scratch done = 0; - - furrever { - meow("...zZz..."); - nap(3000); - - amew done = round(random(1, 3)); - - purrhaps (done == 3) { - hiss; - } - } - - meow("I woke up! ^-^") -}; - -take_a_nap();` - -const yarn = `pawckage "nya:catculator"; -pawckage "nya:clawtility"; - -scratch cat = { - "name": "Whiskers", - "age": 3, - "breed": "Siamese", - "color": "seal point", -}; - -meow(""); -scratch age = cat's age * 12; - -meow(cat's name, "is a", cat's color, cat's breed, "cat!", "He is", age, "months old."); - -scratch play_with_yarn = pawction () { - scratch yarn_length = 0; - - meow("Let's play with yarn!"); - - scratch lives = 9; - furrever { - purrhaps (yarn_length == lives) { - hiss; - } - meow(cat's name, "is playing with yarn loop ", -lives + 10); - amew lives = lives - 1; - } - - meow("Finished playing with yarn!"); -}; - - -play_with_yarn();` - -const toy = `pawckage "nya:clawtility"; -pawckage "nya:catculator"; - -scratch toy_box = ["Feather Wand", "Catnip Mouse", "Yarn Ball", "Squeaky Mouse"]; - -scratch play_with_toy = pawction (toy) { - scratch play_count = round(random(3, 6)); - scratch play_session = 1; - - scratch t = toy_box[toy]; - meow("Let's play with the ", t); - - furrever { - purrhaps (play_session != play_count) { - purrhaps (toy == 1) { - meow("Chasing the feather!"); - } meowtually purrhaps (toy == 4) { - meow("Squeak! Squeak!"); - } meowtually { - meow("Having fun with the ", t); - } - amew play_session = play_session + 1; - } meowtually { - meow("I'm tired now. Time for a catnap!"); - hiss; - } - } -}; - -scratch main = pawction() { - - play_with_toy(round(random(0, 3))); - -}; - -main(); -` - -const fizzbuzz = ` -scratch fizzbuzz = pawction (x) { - purrhaps (x % 15 == 0) { - tail "FizzBuzz"; - } meowtually purrhaps (x % 3 == 0) { - tail "Fizz"; - } meowtually purrhaps (x % 5 == 0) { - tail "Buzz"; - } meowtually { - tail x; - } -}; - - - -scratch i = 0; - -furrever { - purrhaps (i == 100) { - hiss; - } - meow(fizzbuzz(i)); - amew i = i + 1; -}` - - -export const examples: Record = { - naptime, - yarn, - toy, - fizzbuzz -} diff --git a/site/lib/syntax.ts b/site/lib/syntax.ts deleted file mode 100644 index 558cc8a..0000000 --- a/site/lib/syntax.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Prism, { languages } from 'prismjs' - -export const meowScriptSyntax = languages.extend('clike', { - comment: [ - { - pattern: /\/\// - }, - { - pattern: /(^|[^\\:])\/\/.*/, - lookbehind: false, - greedy: true - } - ], - string: { - pattern: /(["`])(?:\\[\s\S]|(?!\1)[^\\])*\1/, - greedy: true - }, - keyword: /\b(?:scratch|amew|pawction|purrhaps|meowtually|tail|pawckage|purrfect|clawful|furreal|furrever|hiss|continue)\b/, - boolean: /\b(?:BUGGER ALL|NAH|YEAH)\b/, - number: /(?:(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[-+]?\d+)?)i?/i, - operator: - /[*/%^!=]=?|~|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./ -}) - -Prism.languages.meowScript = meowScriptSyntax diff --git a/site/next.config.js b/site/next.config.js deleted file mode 100644 index ae88795..0000000 --- a/site/next.config.js +++ /dev/null @@ -1,7 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { - reactStrictMode: true, - swcMinify: true, -} - -module.exports = nextConfig diff --git a/site/next.config.ts b/site/next.config.ts new file mode 100644 index 0000000..1210056 --- /dev/null +++ b/site/next.config.ts @@ -0,0 +1,15 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + reactStrictMode: true, + turbopack: { + rules: { + "*.css": { + loaders: ["@tailwindcss/turbopack"], + as: "*.css", + }, + }, + }, +}; + +export default nextConfig; diff --git a/site/package-lock.json b/site/package-lock.json deleted file mode 100644 index 029de72..0000000 --- a/site/package-lock.json +++ /dev/null @@ -1,2506 +0,0 @@ -{ - "name": "site", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "site", - "version": "0.1.0", - "dependencies": { - "@headlessui/react": "^1.7.15", - "@heroicons/react": "^1.0.6", - "@tailwindcss/aspect-ratio": "^0.4.2", - "@types/node": "20.4.2", - "@types/react": "18.2.15", - "@types/react-dom": "18.2.7", - "comlink": "^4.4.1", - "next": "13.4.10", - "prismjs": "^1.29.0", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-markdown": "^8.0.7", - "react-simple-code-editor": "^0.13.1", - "typescript": "5.1.6", - "use-breakpoint": "^3.1.1" - }, - "devDependencies": { - "@types/classnames": "^2.3.1", - "@types/prismjs": "^1.26.0", - "autoprefixer": "^10.4.14", - "postcss": "^8.4.26", - "tailwindcss": "^3.3.3" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@headlessui/react": { - "version": "1.7.15", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.15.tgz", - "integrity": "sha512-OTO0XtoRQ6JPB1cKNFYBZv2Q0JMqMGNhYP1CjPvcJvjz8YGokz8oAj89HIYZGN0gZzn/4kk9iUpmMF4Q21Gsqw==", - "dependencies": { - "client-only": "^0.0.1" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": "^16 || ^17 || ^18", - "react-dom": "^16 || ^17 || ^18" - } - }, - "node_modules/@heroicons/react": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.6.tgz", - "integrity": "sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==", - "peerDependencies": { - "react": ">= 16" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@next/env": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.10.tgz", - "integrity": "sha512-3G1yD/XKTSLdihyDSa8JEsaWOELY+OWe08o0LUYzfuHp1zHDA8SObQlzKt+v+wrkkPcnPweoLH1ImZeUa0A1NQ==" - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.10.tgz", - "integrity": "sha512-4bsdfKmmg7mgFGph0UorD1xWfZ5jZEw4kKRHYEeTK9bT1QnMbPVPlVXQRIiFPrhoDQnZUoa6duuPUJIEGLV1Jg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.10.tgz", - "integrity": "sha512-ngXhUBbcZIWZWqNbQSNxQrB9T1V+wgfCzAor2olYuo/YpaL6mUYNUEgeBMhr8qwV0ARSgKaOp35lRvB7EmCRBg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.10.tgz", - "integrity": "sha512-SjCZZCOmHD4uyM75MVArSAmF5Y+IJSGroPRj2v9/jnBT36SYFTORN8Ag/lhw81W9EeexKY/CUg2e9mdebZOwsg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.10.tgz", - "integrity": "sha512-F+VlcWijX5qteoYIOxNiBbNE8ruaWuRlcYyIRK10CugqI/BIeCDzEDyrHIHY8AWwbkTwe6GRHabMdE688Rqq4Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.10.tgz", - "integrity": "sha512-WDv1YtAV07nhfy3i1visr5p/tjiH6CeXp4wX78lzP1jI07t4PnHHG1WEDFOduXh3WT4hG6yN82EQBQHDi7hBrQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.10.tgz", - "integrity": "sha512-zFkzqc737xr6qoBgDa3AwC7jPQzGLjDlkNmt/ljvQJ/Veri5ECdHjZCUuiTUfVjshNIIpki6FuP0RaQYK9iCRg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.10.tgz", - "integrity": "sha512-IboRS8IWz5mWfnjAdCekkl8s0B7ijpWeDwK2O8CdgZkoCDY0ZQHBSGiJ2KViAG6+BJVfLvcP+a2fh6cdyBr9QQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.10.tgz", - "integrity": "sha512-bSA+4j8jY4EEiwD/M2bol4uVEu1lBlgsGdvM+mmBm/BbqofNBfaZ2qwSbwE2OwbAmzNdVJRFRXQZ0dkjopTRaQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.10.tgz", - "integrity": "sha512-g2+tU63yTWmcVQKDGY0MV1PjjqgZtwM4rB1oVVi/v0brdZAcrcTV+04agKzWtvWroyFz6IqtT0MoZJA7PNyLVw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/aspect-ratio": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz", - "integrity": "sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==", - "peerDependencies": { - "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" - } - }, - "node_modules/@types/classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A==", - "deprecated": "This is a stub types definition. classnames provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "classnames": "*" - } - }, - "node_modules/@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/hast": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.5.tgz", - "integrity": "sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg==", - "dependencies": { - "@types/unist": "^2" - } - }, - "node_modules/@types/mdast": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.12.tgz", - "integrity": "sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==", - "dependencies": { - "@types/unist": "^2" - } - }, - "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" - }, - "node_modules/@types/node": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", - "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==" - }, - "node_modules/@types/prismjs": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz", - "integrity": "sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "node_modules/@types/react": { - "version": "18.2.15", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.15.tgz", - "integrity": "sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, - "node_modules/@types/unist": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz", - "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==" - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001517", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz", - "integrity": "sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==", - "dev": true - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "node_modules/comlink": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.1.tgz", - "integrity": "sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q==" - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" - }, - "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.466", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.466.tgz", - "integrity": "sha512-TSkRvbXRXD8BwhcGlZXDsbI2lRoP8dvqR7LQnqQNk9KxXBc4tG8O+rTuXgTyIpEdiqSGKEBSqrxdqEntnjNncA==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/fast-glob": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", - "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/hast-util-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", - "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jiti": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", - "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/mdast-util-definitions": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", - "integrity": "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", - "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", - "integrity": "sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-definitions": "^5.0.0", - "micromark-util-sanitize-uri": "^1.1.0", - "trim-lines": "^3.0.0", - "unist-util-generated": "^2.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", - "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", - "dependencies": { - "@types/mdast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromark": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", - "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", - "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-factory-destination": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", - "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", - "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", - "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", - "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", - "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", - "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", - "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", - "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", - "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", - "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", - "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", - "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-html-tag-name": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", - "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", - "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", - "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", - "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", - "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", - "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", - "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "13.4.10", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.10.tgz", - "integrity": "sha512-4ep6aKxVTQ7rkUW2fBLhpBr/5oceCuf4KmlUpvG/aXuDTIf9mexNSpabUD6RWPspu6wiJJvozZREhXhueYO36A==", - "dependencies": { - "@next/env": "13.4.10", - "@swc/helpers": "0.5.1", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0", - "zod": "3.21.4" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=16.8.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.10", - "@next/swc-darwin-x64": "13.4.10", - "@next/swc-linux-arm64-gnu": "13.4.10", - "@next/swc-linux-arm64-musl": "13.4.10", - "@next/swc-linux-x64-gnu": "13.4.10", - "@next/swc-linux-x64-musl": "13.4.10", - "@next/swc-win32-arm64-msvc": "13.4.10", - "@next/swc-win32-ia32-msvc": "13.4.10", - "@next/swc-win32-x64-msvc": "13.4.10" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "fibers": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss": { - "version": "8.4.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz", - "integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, - "engines": { - "node": ">= 14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dependencies": { - "postcss-selector-parser": "^6.0.11" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/property-information": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.2.0.tgz", - "integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/react-markdown": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", - "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/prop-types": "^15.0.0", - "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "prop-types": "^15.0.0", - "property-information": "^6.0.0", - "react-is": "^18.0.0", - "remark-parse": "^10.0.0", - "remark-rehype": "^10.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.4.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=16", - "react": ">=16" - } - }, - "node_modules/react-simple-code-editor": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.13.1.tgz", - "integrity": "sha512-XYeVwRZwgyKtjNIYcAEgg2FaQcCZwhbarnkJIV20U2wkCU9q/CPFBo8nRXrK4GXUz3AvbqZFsZRrpUTkqqEYyQ==", - "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/remark-parse": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", - "integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==", - "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", - "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-to-hast": "^12.1.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dependencies": { - "mri": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/style-to-object": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.1.tgz", - "integrity": "sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==", - "dependencies": { - "inline-style-parser": "0.1.1" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/sucrase": { - "version": "3.34.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", - "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", - "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" - }, - "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-generated": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", - "integrity": "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", - "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", - "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", - "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/use-breakpoint": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use-breakpoint/-/use-breakpoint-3.1.1.tgz", - "integrity": "sha512-zJ2a9sqdiOnsYwjZryOuq+SIDRP2vWsl7iWDUJ7Xid9t29zF1oLZjkEE+uRooPB/98YT+784rCFIvmKhV6VqLg==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uvu": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", - "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", - "dependencies": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - }, - "bin": { - "uvu": "bin.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/site/package.json b/site/package.json index efee42c..6854539 100644 --- a/site/package.json +++ b/site/package.json @@ -1,35 +1,40 @@ { - "name": "site", - "version": "0.1.0", + "name": "meowscript-site", + "version": "1.0.0", "private": true, + "description": "Playground and docs for MeowScript, the purrfect programming language", "scripts": { "dev": "next dev", + "prebuild": "pnpm sync", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "eslint", + "typecheck": "tsc --noEmit", + "sync": "node scripts/sync-examples.mjs && node scripts/sync-stdlib.mjs", + "build:wasm": "node scripts/build-wasm.mjs" }, "dependencies": { - "@headlessui/react": "^1.7.15", - "@heroicons/react": "^1.0.6", - "@tailwindcss/aspect-ratio": "^0.4.2", - "@types/node": "20.4.2", - "@types/react": "18.2.15", - "@types/react-dom": "18.2.7", - "comlink": "^4.4.1", - "next": "13.4.10", - "prismjs": "^1.29.0", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-markdown": "^8.0.7", - "react-simple-code-editor": "^0.13.1", - "typescript": "5.1.6", - "use-breakpoint": "^3.1.1" + "@codemirror/autocomplete": "^6.18.0", + "@codemirror/commands": "^6.8.0", + "@codemirror/language": "^6.11.0", + "@codemirror/state": "^6.5.0", + "@codemirror/view": "^6.36.0", + "@lezer/highlight": "^1.2.0", + "next": "16.4.0", + "react": "19.3.0", + "react-dom": "19.3.0", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1" }, "devDependencies": { - "@types/classnames": "^2.3.1", - "@types/prismjs": "^1.26.0", - "autoprefixer": "^10.4.14", - "postcss": "^8.4.26", - "tailwindcss": "^3.3.3" - } + "@tailwindcss/turbopack": "^4.3.3", + "@types/node": "^22", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.4.0", + "tailwindcss": "^4.3.3", + "typescript": "^5.9.3" + }, + "packageManager": "pnpm@11.5.1" } diff --git a/site/pages/_app.tsx b/site/pages/_app.tsx deleted file mode 100644 index 18b3e74..0000000 --- a/site/pages/_app.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import '../styles/global.css' -import type { AppProps } from 'next/app' - -export default function App({ Component, pageProps }: AppProps) { - - return ( - <> - - - ) -} diff --git a/site/pages/api/hello.ts b/site/pages/api/hello.ts deleted file mode 100644 index f8bcc7e..0000000 --- a/site/pages/api/hello.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from 'next' - -type Data = { - name: string -} - -export default function handler( - req: NextApiRequest, - res: NextApiResponse -) { - res.status(200).json({ name: 'John Doe' }) -} diff --git a/site/pages/index.tsx b/site/pages/index.tsx deleted file mode 100644 index 4e851ee..0000000 --- a/site/pages/index.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import Code from '../components/Code' -import Features from '../components/Features' -import Head from '../components/Head' -import { GetStaticProps } from 'next' -import React from 'react' -import ReactMarkdown from 'react-markdown' - -import { readDocsFile } from '../lib/docs' - -type Props = { - docs: string -} - -const Landing = ({ docs }: Props) => { - return ( - <> - -
-
-
-
-

- MeowScript🐾 -

-

- The Purrfect Programming Language -

- -
-

- Made by{' '} - - @Alen - - , inspired by{' '} - - 🐱 - -

-
-
-
-
- - -
-
- {docs} -
-
-
- - ) -} - -export default Landing - -export const getStaticProps: GetStaticProps = async () => { - const docs = await readDocsFile() - return { - props: { - docs - } - } -} diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml new file mode 100644 index 0000000..30ae9a5 --- /dev/null +++ b/site/pnpm-lock.yaml @@ -0,0 +1,5163 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@codemirror/autocomplete': + specifier: ^6.18.0 + version: 6.20.3 + '@codemirror/commands': + specifier: ^6.8.0 + version: 6.11.1 + '@codemirror/language': + specifier: ^6.11.0 + version: 6.12.4 + '@codemirror/state': + specifier: ^6.5.0 + version: 6.7.6 + '@codemirror/view': + specifier: ^6.36.0 + version: 6.43.13 + '@lezer/highlight': + specifier: ^1.2.0 + version: 1.2.5 + next: + specifier: 16.4.0 + version: 16.4.0(@babel/core@7.29.7)(@types/node@22.20.5)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: + specifier: 19.3.0 + version: 19.3.0 + react-dom: + specifier: 19.3.0 + version: 19.3.0(react@19.3.0) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.3.0)(react@19.3.0) + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + devDependencies: + '@tailwindcss/turbopack': + specifier: ^4.3.3 + version: 4.3.3 + '@types/node': + specifier: ^22 + version: 22.20.5 + '@types/react': + specifier: ^19 + version: 19.3.0 + '@types/react-dom': + specifier: ^19 + version: 19.3.0(@types/react@19.3.0) + eslint: + specifier: ^9 + version: 9.39.5(jiti@2.7.0) + eslint-config-next: + specifier: 16.4.0 + version: 16.4.0(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + tailwindcss: + specifier: ^4.3.3 + version: 4.3.3 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@alloc/quick-lru@5.3.0': + resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} + engines: {node: '>=10'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.9': + resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@codemirror/autocomplete@6.20.3': + resolution: {integrity: sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==} + + '@codemirror/commands@6.11.1': + resolution: {integrity: sha512-O/4hG3SC1YwcmQ0d2UVNDs+AsaNWd1iHVxbTeEBuqH+6bExAiPK3iS/BvpY6rZGURALv4ZD3sIgcCmRvw3ehBg==} + + '@codemirror/language@6.12.4': + resolution: {integrity: sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==} + + '@codemirror/state@6.7.6': + resolution: {integrity: sha512-kAz+AncRtKuIknedxT1bq4XwXv4UowhbkHU1myPrtVb/jZtImWuV5BXzv5vK6i3kYACsdiZiQKFQQ5Mq7elW8w==} + + '@codemirror/view@6.43.13': + resolution: {integrity: sha512-sihaFrUzAsYBQsL9J2t69y8nfMQGwcYmggAZsk+kjPbjYZMyuf2hU8tUNTZ+P+isb6XRr8JE22TZlJxBoVdH1A==} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.7': + resolution: {integrity: sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.5': + resolution: {integrity: sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.5': + resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.5': + resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.5': + resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.4': + resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.4': + resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.4': + resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.3.4': + resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.3.4': + resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.3.4': + resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.3.4': + resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.3.4': + resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.35.5': + resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.35.5': + resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.35.5': + resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.35.5': + resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.35.5': + resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.35.5': + resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.35.5': + resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.35.5': + resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.35.5': + resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.5': + resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.5': + resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.5': + resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.5': + resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@lezer/common@1.5.3': + resolution: {integrity: sha512-H0iErY4e43LpXbYDyBci5W4v/RwTgGV3YzYOlJPiGZ8RY8w51kVE+xLn1tg3Z6UmSfyETvtsUK3r7YsgDQEI7Q==} + + '@lezer/highlight@1.2.5': + resolution: {integrity: sha512-O1GMVKgtf5YspFaRzpmqkVgMtIk2HG9uMAbH6wdAIdNh3TVzCsch/+cRi+6l2//UGDKe6NB9BW3cvuR5ezMQ0w==} + + '@lezer/lr@1.4.10': + resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} + + '@marijn/find-cluster-break@1.0.4': + resolution: {integrity: sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==} + + '@napi-rs/wasm-runtime@1.2.5': + resolution: {integrity: sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + + '@next/env@16.4.0': + resolution: {integrity: sha512-pyLlT5oafGlX8X7xjgGNXz5dNIDSxREm+qD6i9VLSZiZFopA/XWl8NM/KPmLx/8EG/++c49iid3gNWSQW1+2dQ==} + + '@next/eslint-plugin-next@16.4.0': + resolution: {integrity: sha512-ffeflB/dL8RrvWejQximw01pOpKHN692Y3FjDB82DCd0YVvXvBD6vY7mcZp27yvSVFVM6wA73xVodEKF4spizA==} + + '@next/swc-darwin-arm64@16.4.0': + resolution: {integrity: sha512-yyZ+9MgViAKLLb5l1gPBGjRwnq3teNLb5Zx6JEw8LzNSTjlsnp+baUHFxTgl7PpjCmKf48VQfyipG1eBflb48Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.4.0': + resolution: {integrity: sha512-RePEEejEj1Auf5s9qEcG0JbcDP3ceNUS/ofNX8AhxzgIjTVlZIHMatlp16YplcSMpsVo/ZMQHJTjbMYJznjGUg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.4.0': + resolution: {integrity: sha512-HhsyCqd+NpmvDDVY/LqkAN24f+QVvXh3ie+PfcwKinWL2Mu826JymQxJXGjAIfmJ4VlHjp4Pe/nZtXtUoEMAqw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.4.0': + resolution: {integrity: sha512-sN9Pf+Zh+RpZAOmbR7d8KAA8T61CVhawtbEJ2Bk6QrRzx6Z/6haaF4UiwBzytM96GRRRWZh9/WALIEO3npMamA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.4.0': + resolution: {integrity: sha512-D5M5xLWQVd1CvR+L7BickM1weRfmM41x3L1NWcnKY/oyJJqr1qwaCgmu3dMAhLBOMdZwSuDCRV6DJRRpiUkbDQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.4.0': + resolution: {integrity: sha512-8d5WLS6a9YalqpOgXdlbvonFu+sIgjA+CO6tGzetrpPVcUL56foa7B7664h41rAlbLi5fJwK4vWji3zf4QDy+w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.4.0': + resolution: {integrity: sha512-sQuOIiW3snb48UwrBcDMvFA/u03qtw2LeuSIxFIQ9AJuW9UG/4Ddsfo+eV73PnZwBhyncMtsKVh7PrzMol2/fA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.4.0': + resolution: {integrity: sha512-6/33lCuxpdHUy27RegyGM/5uTpF7YZd3UR4D0gpkOA/tWY5YR7msbQjqPgCZmSmxrrTLGCXYA4A8vT2H5DPGTQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@swc/helpers@0.5.23': + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} + + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} + + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} + engines: {node: '>= 20'} + + '@tailwindcss/turbopack@4.3.3': + resolution: {integrity: sha512-FgL4wRgItNdXcDjcgYUSd59gNsWqNVK4GotjZimZMmt7OOIkRNqH2QEUcRXLdBDXvwTsi5rkYxDxzfrFUkmObQ==} + + '@tybys/wasm-util@0.10.4': + resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@22.20.5': + resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==} + + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} + peerDependencies: + '@types/react': ^19.3.0 + + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@typescript-eslint/eslint-plugin@8.71.1': + resolution: {integrity: sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.71.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.71.1': + resolution: {integrity: sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.71.1': + resolution: {integrity: sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.71.1': + resolution: {integrity: sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.71.1': + resolution: {integrity: sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.71.1': + resolution: {integrity: sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.71.1': + resolution: {integrity: sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.71.1': + resolution: {integrity: sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.71.1': + resolution: {integrity: sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.71.1': + resolution: {integrity: sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.4.0': + resolution: {integrity: sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + cpu: [x64] + os: [win32] + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.2.0: + resolution: {integrity: sha512-VXY5eFRarnXcYxwBjJzPmEhH55+rmP79/+ueDhi0F+TuqfHCItagIHqxeUZrmgrOPa31QTh9H85DjX3FfJ0FTg==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.14.0: + resolution: {integrity: sha512-9WTZxEjsZ7b13TH8JPmbV2z8CHbl80/2hm3XPEG4JgNdQLK81IBRXmSxHfMAOkSqQeRxT/0dwNDz2GOm3zzpcQ==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.11.27: + resolution: {integrity: sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + brace-expansion@1.1.21: + resolution: {integrity: sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==} + + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.29.3: + resolution: {integrity: sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001814: + resolution: {integrity: sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.446: + resolution: {integrity: sha512-kWlGMPHzuitCKx0O+MbY1ZGvQmP14JtckrnGjD4JsusTxh2cX9wu4bb4rOYZqLSvENjFFrHzlqY8kXhseucR/w==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.26.0: + resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==} + engines: {node: '>=10.13.0'} + + es-abstract-get@1.0.0: + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} + engines: {node: '>= 0.4'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.4.0: + resolution: {integrity: sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + eslint-config-next@16.4.0: + resolution: {integrity: sha512-2RHLYswzc+hNRktWAjIL6XAvwb1cKcjLawJ5KWywAxn/JivNHtG42ZigL1yobVXDqsimuuL2F9jcEcnHFzbppQ==} + peerDependencies: + eslint: '>=9.0.0' + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.10: + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.14.0: + resolution: {integrity: sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.5: + resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.20.3: + resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.14.3: + resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.12: + resolution: {integrity: sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.17.0: + resolution: {integrity: sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-find-and-replace@3.0.3: + resolution: {integrity: sha512-xPgpDNl0/OXHsI7TlaIs22lWnH3KlpvZdXG1ET/m/YT2Hhdkx8lJV4kLphE6l9simyM4KPDFBwas08BgEob6Jw==} + + mdast-util-from-markdown@2.1.0: + resolution: {integrity: sha512-KRLgmPaP2H1ul2bpoJkOS+9pAcDAAj9Nu1mqLnh8NLeJG5tlvj42TH80PIGBpROWlRXLk0lDrWNuZCFy/tsB4A==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.1: + resolution: {integrity: sha512-OuJHqvr455pwu2OaOrir7dbzqs4jlWKOtlu9L6GjcIjjQwNyw02VntQsr/Ek6/A13vgnXfUhBekWRUP1OkNivw==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.2.0: + resolution: {integrity: sha512-2Jn/ADrHFFyyniBMi0bncTbJqU78K3/TEYvzvwrWWzD9MYPUa/Gm4r3nOeKFQg/PDM5BsbDYdc8ackW4NTY6NA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.4: + resolution: {integrity: sha512-wxEeE8v8XVvOrxn1TZj74qYhAtTQsSqufHVS3uNVyT1MupXxhyaHk8/9xDNPh9BmL77QNDgWTkZ3RsYHB2ry7w==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.2: + resolution: {integrity: sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.1.0: + resolution: {integrity: sha512-fS8hnLIjnjvdQIj39Geug8wWsR0HrYZ43KShKxNfwT7t2LOHo/LbWZEzEaSOjwtjdCsjoE6syHhonEzW0zv0+Q==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-edit-map@1.0.0: + resolution: {integrity: sha512-Pa2ljlsEL6sVwFaYeyrOLSYbQt73JvGbPOYFq+9AElXiSnfI5Q4465RRZ1sHv7lDjDOnGRDDaqPXqClqWK/q1Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.3: + resolution: {integrity: sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==} + + micromark@4.0.3: + resolution: {integrity: sha512-oGYfQzHSG5dOMovQcJ3fyTmZlWAWpi0XA0sJwJs+i6OT88o1+Jtw/8z0CmdowSLxGhhFK89rQ/oXph/wN02PNw==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next@16.4.0: + resolution: {integrity: sha512-N2C+9q89Z/oLrsepSRS4jRMtwmUZAoZuAHU0e9T6+sAB5DdhADmrnOW+zjYijlrYFmVfmQhGVGy9eMFoB7UgKg==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-exports-info@1.6.2: + resolution: {integrity: sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==} + engines: {node: '>= 0.4'} + + node-releases@2.0.57: + resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.2: + resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.3.0: + resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==} + peerDependencies: + react: ^19.3.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + + react@19.3.0: + resolution: {integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==} + engines: {node: '>=0.10.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + scheduler@0.28.0: + resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.35.5: + resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.1.0: + resolution: {integrity: sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + style-mod@4.1.4: + resolution: {integrity: sha512-XXWIQt633/EpAFx8aZDOTjBzrCaGmhvEQlQo6MVPfa2OzO2cWo+4hV9h+6UkHYlXGfy+ODXKUdP7Pthmcu5ATw==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.5: + resolution: {integrity: sha512-0FHJvLPqZ7KJzp17O13jfsAjsqazgrxBu2zEK95PmUz8lv2+GjRuxUInCr2Rk9Dms3ihN21zJ929ZO43yJ95QQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.71.1: + resolution: {integrity: sha512-oiNVPC3/NbV1FpaHU07l8O6ynqG9v4PAiW2WvTrAmZdR0f2HI/gE668ElMLCK7Xbsu5k2fK5C4fXNiq05j7/nQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + + update-browserslist-db@1.3.3: + resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.24: + resolution: {integrity: sha512-wk4Mf4pR5mRP7eYuuTBCIQ9d0ud2Fv2jRLQpfgnRjbOxAFHmjKFValgTpitVKzJJS8ajnYQV2Du1SZ8j6b/EUQ==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.6.5: + resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.3.0': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.29.3 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.29.9': + dependencies: + '@babel/types': 7.29.8 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.8': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@codemirror/autocomplete@6.20.3': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.13 + '@lezer/common': 1.5.3 + + '@codemirror/commands@6.11.1': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.13 + '@lezer/common': 1.5.3 + + '@codemirror/language@6.12.4': + dependencies: + '@codemirror/state': 6.7.6 + '@codemirror/view': 6.43.13 + '@lezer/common': 1.5.3 + '@lezer/highlight': 1.2.5 + '@lezer/lr': 1.4.10 + style-mod: 4.1.4 + + '@codemirror/state@6.7.6': + dependencies: + '@marijn/find-cluster-break': 1.0.4 + + '@codemirror/view@6.43.13': + dependencies: + '@codemirror/state': 6.7.6 + crelt: 1.0.7 + style-mod: 4.1.4 + w3c-keyname: 2.2.8 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(jiti@2.7.0))': + dependencies: + eslint: 9.39.5(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.5(jiti@2.7.0))': + dependencies: + eslint: 9.39.5(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.7': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.3.2 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.5': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.4 + optional: true + + '@img/sharp-darwin-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.4 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + optional: true + + '@img/sharp-linux-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.4 + optional: true + + '@img/sharp-linux-arm@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.4 + optional: true + + '@img/sharp-linux-ppc64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.4 + optional: true + + '@img/sharp-linux-riscv64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.4 + optional: true + + '@img/sharp-linux-s390x@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.4 + optional: true + + '@img/sharp-linux-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + optional: true + + '@img/sharp-wasm32@0.35.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 + optional: true + + '@img/sharp-win32-arm64@0.35.5': + optional: true + + '@img/sharp-win32-ia32@0.35.5': + optional: true + + '@img/sharp-win32-x64@0.35.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@lezer/common@1.5.3': {} + + '@lezer/highlight@1.2.5': + dependencies: + '@lezer/common': 1.5.3 + + '@lezer/lr@1.4.10': + dependencies: + '@lezer/common': 1.5.3 + + '@marijn/find-cluster-break@1.0.4': {} + + '@napi-rs/wasm-runtime@1.2.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.4 + optional: true + + '@next/env@16.4.0': {} + + '@next/eslint-plugin-next@16.4.0(eslint@9.39.5(jiti@2.7.0))': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5(jiti@2.7.0)) + fast-glob: 3.3.1 + transitivePeerDependencies: + - eslint + + '@next/swc-darwin-arm64@16.4.0': + optional: true + + '@next/swc-darwin-x64@16.4.0': + optional: true + + '@next/swc-linux-arm64-gnu@16.4.0': + optional: true + + '@next/swc-linux-arm64-musl@16.4.0': + optional: true + + '@next/swc-linux-x64-gnu@16.4.0': + optional: true + + '@next/swc-linux-x64-musl@16.4.0': + optional: true + + '@next/swc-win32-arm64-msvc@16.4.0': + optional: true + + '@next/swc-win32-x64-msvc@16.4.0': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.3 + + '@nolyfill/is-core-module@1.0.39': {} + + '@rtsao/scc@1.1.0': {} + + '@swc/helpers@0.5.23': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.3.3': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.26.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.2 + tailwindcss: 4.3.3 + + '@tailwindcss/oxide-android-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide@4.3.3': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + + '@tailwindcss/turbopack@4.3.3': + dependencies: + '@alloc/quick-lru': 5.3.0 + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + tailwindcss: 4.3.3 + + '@tybys/wasm-util@0.10.4': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@22.20.5': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.3.0(@types/react@19.3.0)': + dependencies: + '@types/react': 19.3.0 + + '@types/react@19.3.0': + dependencies: + csstype: 3.2.3 + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@typescript-eslint/eslint-plugin@8.71.1(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.71.1 + '@typescript-eslint/type-utils': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.71.1 + eslint: 9.39.5(jiti@2.7.0) + ignore: 7.0.12 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.71.1 + '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/typescript-estree': 8.71.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.71.1 + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.71.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.71.1(typescript@5.9.3) + '@typescript-eslint/types': 8.71.1 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.71.1': + dependencies: + '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/visitor-keys': 8.71.1 + + '@typescript-eslint/tsconfig-utils@8.71.1(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/typescript-estree': 8.71.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.71.1': {} + + '@typescript-eslint/typescript-estree@8.71.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.71.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.71.1(typescript@5.9.3) + '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/visitor-keys': 8.71.1 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.71.1 + '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/typescript-estree': 8.71.1(typescript@5.9.3) + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.71.1': + dependencies: + '@typescript-eslint/types': 8.71.1 + eslint-visitor-keys: 5.0.1 + + '@ungap/structured-clone@1.4.0': {} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.2.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true + + acorn-jsx@5.3.2(acorn@8.19.0): + dependencies: + acorn: 8.19.0 + + acorn@8.19.0: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.2.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.14.0: {} + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.11.27: {} + + brace-expansion@1.1.21: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.29.3: + dependencies: + baseline-browser-mapping: 2.11.27 + caniuse-lite: 1.0.30001814 + electron-to-chromium: 1.5.446 + node-releases: 2.0.57 + update-browserslist-db: 1.3.3(browserslist@4.29.3) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001814: {} + + ccount@2.0.1: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + client-only@0.0.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + comma-separated-tokens@2.0.3: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + crelt@1.0.7: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.446: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.26.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + es-abstract-get@1.0.0: + dependencies: + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + is-callable: 1.2.7 + object-inspect: 1.13.4 + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.4 + function.prototype.name: 1.2.0 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.2 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.4 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.5 + typed-array-length: 1.0.8 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.24 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.4.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.4 + + es-to-primitive@1.3.4: + dependencies: + es-abstract-get: 1.0.0 + es-define-property: 1.0.1 + es-errors: 1.3.0 + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-config-next@16.4.0(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 16.4.0(eslint@9.39.5(jiti@2.7.0)) + eslint: 9.39.5(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.5(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.5(jiti@2.7.0)) + globals: 16.4.0 + typescript-eslint: 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.10: + dependencies: + debug: 3.2.7 + is-core-module: 2.17.0 + resolve: 2.0.0-next.7 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + get-tsconfig: 4.14.3 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.17 + unrs-resolver: 1.12.2 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.5(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.2.0 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.5(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) + hasown: 2.0.4 + is-core-module: 2.17.0 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.10 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.5(jiti@2.7.0)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.2.0 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.14.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.5(jiti@2.7.0) + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.5(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.9 + eslint: 9.39.5(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.6.5 + zod-validation-error: 4.0.2(zod@4.6.5) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react@7.37.5(eslint@9.39.5(jiti@2.7.0)): + dependencies: + array-includes: 3.2.0 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.4.0 + eslint: 9.39.5(jiti@2.7.0) + estraverse: 5.3.0 + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.7 + semver: 6.3.1 + string.prototype.matchall: 4.1.0 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.5(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.7 + '@eslint/js': 9.39.5 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + esutils@2.0.3: {} + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.3: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.4 + keyv: 4.5.4 + + flatted@3.4.4: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + function-bind@1.1.2: {} + + function.prototype.name@1.2.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + es-define-property: 1.0.1 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 + is-callable: 1.2.7 + is-document.all: 1.0.0 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.14.3: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.4.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + html-url-attributes@3.0.1: {} + + ignore@5.3.2: {} + + ignore@7.0.12: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inline-style-parser@0.2.7: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.4 + side-channel: 1.1.1 + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.8.5 + + is-callable@1.2.7: {} + + is-core-module@2.17.0: + dependencies: + hasown: 2.0.4 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-decimal@2.0.1: {} + + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-plain-obj@4.1.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.24 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.2.0 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + markdown-table@3.0.4: {} + + math-intrinsics@1.1.0: {} + + mdast-util-find-and-replace@3.0.3: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.3 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.3 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0 + mdast-util-to-markdown: 2.2.0 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.1.0 + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.1.0 + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0 + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.1.0 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.1 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0 + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0 + mdast-util-to-markdown: 2.2.0 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.1.0 + mdast-util-to-markdown: 2.2.0 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.4.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.2.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-character: 2.1.1 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.4: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.1.0 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-edit-map: 1.0.0 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.4 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-table@2.1.2: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.3 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.2 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-factory-space@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.3 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-edit-map@1.0.0: + dependencies: + micromark-util-types: 2.0.3 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.3 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.3: {} + + micromark@4.0.3: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.4 + micromark-factory-space: 2.1.0 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-edit-map: 1.0.0 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.3 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.21 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + nanoid@3.3.20: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next@16.4.0(@babel/core@7.29.7)(@types/node@22.20.5)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + dependencies: + '@next/env': 16.4.0 + '@swc/helpers': 0.5.23 + baseline-browser-mapping: 2.11.27 + caniuse-lite: 1.0.30001814 + postcss: 8.5.23 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.3.0) + optionalDependencies: + '@next/swc-darwin-arm64': 16.4.0 + '@next/swc-darwin-x64': 16.4.0 + '@next/swc-linux-arm64-gnu': 16.4.0 + '@next/swc-linux-arm64-musl': 16.4.0 + '@next/swc-linux-x64-gnu': 16.4.0 + '@next/swc-linux-x64-musl': 16.4.0 + '@next/swc-win32-arm64-msvc': 16.4.0 + '@next/swc-win32-x64-msvc': 16.4.0 + sharp: 0.35.5(@types/node@22.20.5) + transitivePeerDependencies: + - '@babel/core' + - '@types/node' + - babel-plugin-macros + + node-exports-info@1.6.2: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-releases@2.0.57: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.7: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.5.23: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + prelude-ls@1.2.1: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + property-information@7.2.0: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-dom@19.3.0(react@19.3.0): + dependencies: + react: 19.3.0 + scheduler: 0.28.0 + + react-is@16.13.1: {} + + react-markdown@10.1.0(@types/react@19.3.0)(react@19.3.0): + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/react': 19.3.0 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.3.0 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + react@19.3.0: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.1.0 + micromark-util-types: 2.0.3 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.2.0 + unified: 11.0.5 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@2.0.0-next.7: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.17.0 + node-exports-info: 1.6.2 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + scheduler@0.28.0: {} + + semver@6.3.1: {} + + semver@7.8.5: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + + sharp@0.35.5(@types/node@22.20.5): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + '@types/node': 22.20.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + source-map-js@1.2.2: {} + + space-separated-tokens@2.0.2: {} + + stable-hash@0.0.5: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.matchall@4.1.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.1 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.trim@1.2.11: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 + + string.prototype.trimend@1.0.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + style-mod@4.1.4: {} + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.3.0): + dependencies: + client-only: 0.0.1 + react: 19.3.0 + optionalDependencies: + '@babel/core': 7.29.7 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwindcss@4.3.3: {} + + tapable@2.3.3: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.5: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.8: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.71.1(@typescript-eslint/parser@8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.71.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.1(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + + update-browserslist-db@1.3.3(browserslist@4.29.3): + dependencies: + browserslist: 4.29.3 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + w3c-keyname@2.2.8: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.2.0 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.24 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.24: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.6.5): + dependencies: + zod: 4.6.5 + + zod@4.6.5: {} + + zwitch@2.0.4: {} diff --git a/site/pnpm-workspace.yaml b/site/pnpm-workspace.yaml new file mode 100644 index 0000000..c2da90e --- /dev/null +++ b/site/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +allowBuilds: + sharp: false + unrs-resolver: false diff --git a/site/postcss.config.js b/site/postcss.config.js deleted file mode 100644 index 85f717c..0000000 --- a/site/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {} - } -} diff --git a/site/public/FiraCode-Light.woff b/site/public/FiraCode-Light.woff deleted file mode 100644 index 9e99c41..0000000 Binary files a/site/public/FiraCode-Light.woff and /dev/null differ diff --git a/site/public/FiraCode-Light.woff2 b/site/public/FiraCode-Light.woff2 deleted file mode 100644 index 5084487..0000000 Binary files a/site/public/FiraCode-Light.woff2 and /dev/null differ diff --git a/site/public/FiraCode-Regular.woff b/site/public/FiraCode-Regular.woff deleted file mode 100644 index 01a6bfc..0000000 Binary files a/site/public/FiraCode-Regular.woff and /dev/null differ diff --git a/site/public/meowscript.js b/site/public/meowscript.js deleted file mode 100644 index 00f5b98..0000000 --- a/site/public/meowscript.js +++ /dev/null @@ -1,19 +0,0 @@ - -var MeowScript = (() => { - var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; - if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; - return ( -function(moduleArg = {}) { - -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject}));var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",((err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)}))};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow};Module["inspect"]=()=>"[Emscripten Module object]"}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="meowscript.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then((response=>{if(!response["ok"]){throw"failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()})).catch((()=>getBinarySync(binaryFile)))}else if(readAsync){return new Promise(((resolve,reject)=>{readAsync(binaryFile,(response=>resolve(new Uint8Array(response))),reject)}))}}return Promise.resolve().then((()=>getBinarySync(binaryFile)))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then((binary=>WebAssembly.instantiate(binary,imports))).then((instance=>instance)).then(receiver,(reason=>{err("failed to asynchronously prepare wasm: "+reason);abort(reason)}))}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then((response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,(function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)}))}))}return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["M"];updateMemoryViews();wasmTable=Module["asm"]["S"];addOnInit(Module["asm"]["N"]);removeRunDependency("wasm-instantiate");return exports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var exceptionCaught=[];var uncaughtExceptionCount=0;function ___cxa_begin_catch(ptr){var info=new ExceptionInfo(ptr);if(!info.get_caught()){info.set_caught(true);uncaughtExceptionCount--}info.set_rethrown(false);exceptionCaught.push(info);___cxa_increment_exception_refcount(info.excPtr);return info.get_exception_ptr()}var exceptionLast=0;function ___cxa_end_catch(){_setThrew(0);var info=exceptionCaught.pop();___cxa_decrement_exception_refcount(info.excPtr);exceptionLast=0}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){HEAPU32[this.ptr+4>>2]=type};this.get_type=function(){return HEAPU32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAPU32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAPU32[this.ptr+8>>2]};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)};this.set_adjusted_ptr=function(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return HEAPU32[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}function ___resumeException(ptr){if(!exceptionLast){exceptionLast=ptr}throw exceptionLast}function ___cxa_find_matching_catch(){var thrown=exceptionLast;if(!thrown){setTempRet0(0);return 0}var info=new ExceptionInfo(thrown);info.set_adjusted_ptr(thrown);var thrownType=info.get_type();if(!thrownType){setTempRet0(0);return thrown}for(var i=0;ipath.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter((p=>!!p)),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter((p=>!!p)),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf,0,BUFSIZE,-1)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init:function(){},shutdown:function(){},register:function(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open:function(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.fsync(stream.tty)},fsync:function(stream){stream.tty.ops.fsync(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets:function(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets:function(tty,optional_actions,data){return 0},ioctl_tiocgwinsz:function(tty){return[24,80]}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var mmapAlloc=size=>{abort()};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,(arrayBuffer=>{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)}),(event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}}));if(dep)addRunDependency(dep)};var preloadPlugins=Module["preloadPlugins"]||[];function FS_handledByPreloadPlugin(byteArray,fullname,finish,onerror){if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach((function(plugin){if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}}));return handled}function FS_createPreloadedFile(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish){var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,(()=>{if(onerror)onerror();removeRunDependency(dep)}))){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,(byteArray=>processData(byteArray)),onerror)}else{processData(url)}}function FS_modeStringToFlags(str){var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags}function FS_getMode(canRead,canWrite){var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode}var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter((p=>!!p));var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:node=>{var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName:(parentid,name)=>{var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:node=>{var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>node===node.parent,isMountpoint:node=>!!node.mounted,isFile:mode=>(mode&61440)===32768,isDir:mode=>(mode&61440)===16384,isLink:mode=>(mode&61440)===40960,isChrdev:mode=>(mode&61440)===8192,isBlkdev:mode=>(mode&61440)===24576,isFIFO:mode=>(mode&61440)===4096,isSocket:mode=>(mode&49152)===49152,flagsToPermissionString:flag=>{var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:()=>{for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked:fd=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream:(stream,fd=-1)=>{if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get(){return this.node},set(val){this.node=val}},isRead:{get(){return(this.flags&2097155)!==1}},isWrite:{get(){return(this.flags&2097155)!==0}},isAppend:{get(){return this.flags&1024}},flags:{get(){return this.shared.flags},set(val){this.shared.flags=val}},position:{get(){return this.shared.position},set(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts:mount=>{var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:(populate,callback)=>{if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach((mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)}))},mount:(type,opts,mountpoint)=>{var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach((hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}}));node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>parent.node_ops.lookup(parent,name),mknod:(path,mode,dev)=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(path,mode)=>{var dirs=path.split("/");var d="";for(var i=0;i{if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(old_path,new_path)=>{var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>FS.stat(path,true),chmod:(path,mode,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStreamChecked(fd);FS.chmod(stream.node,mode)},chown:(path,uid,gid,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStreamChecked(fd);FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStreamChecked(fd);if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(path,atime,mtime)=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;node.node_ops.setattr(node,{timestamp:Math.max(atime,mtime)})},open:(path,flags,mode)=>{if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS_modeStringToFlags(flags):flags;mode=typeof mode=="undefined"?438:mode;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;if(typeof path=="object"){node=path}else{path=PATH.normalize(path);try{var lookup=FS.lookupPath(path,{follow:!(flags&131072)});node=lookup.node}catch(e){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(Module["logReadFiles"]&&!(flags&1)){if(!FS.readFiles)FS.readFiles={};if(!(path in FS.readFiles)){FS.readFiles[path]=1}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>stream.fd===null,llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile:(path,data,opts={})=>{opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices:()=>{FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories:()=>{FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount:()=>{var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams:()=>{if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach((code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""}))},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;for(var i=0;i{var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath:(path,dontResolveLastLink)=>{try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath:(parent,path,canRead,canWrite)=>{parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){}parent=current}return current},createFile:(parent,name,properties,canRead,canWrite)=>{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS_getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;i{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(!!input,!!output);if(!FS.createDevice.major)FS.createDevice.major=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i{for(var i=0;i{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return true;if(typeof XMLHttpRequest!="undefined"){throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.")}else if(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error("Cannot load without read() or XMLHttpRequest.")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}LazyUint8Array.prototype.get=function LazyUint8Array_get(idx){if(idx>this.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter((chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]}));if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach((key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}}));function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat:function(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStreamChecked(fd);return stream}};function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function ___syscall_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size{abort("")};var _emscripten_get_now;_emscripten_get_now=()=>performance.now();var _emscripten_memcpy_big=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>0]=str.charCodeAt(i)}HEAP8[buffer>>0]=0};var _environ_get=(__environ,environ_buf)=>{var bufSize=0;getEnvStrings().forEach((function(string,i){var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1}));return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach((function(string){bufSize+=string.length+1}));HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function convertI32PairToI53Checked(lo,hi){return hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret};function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var _getentropy=(buffer,size)=>{randomFill(HEAPU8.subarray(buffer,buffer+size));return 0};function _llvm_eh_typeid_for(type){return type}var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var wasmTableMirror=[];var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();var wasmImports={s:___cxa_begin_catch,K:___cxa_end_catch,b:___cxa_find_matching_catch_2,m:___cxa_find_matching_catch_3,n:___cxa_find_matching_catch_4,J:___cxa_throw,d:___resumeException,E:___syscall_fstat64,A:___syscall_getcwd,B:___syscall_lstat64,C:___syscall_newfstatat,z:___syscall_openat,D:___syscall_stat64,o:_abort,r:_emscripten_get_now,F:_emscripten_memcpy_big,x:_emscripten_resize_heap,H:_environ_get,I:_environ_sizes_get,G:_fd_close,y:_fd_read,u:_fd_seek,q:_fd_write,t:_getentropy,l:invoke_i,i:invoke_ii,h:invoke_iii,k:invoke_iiii,L:invoke_iiiiii,w:invoke_jii,j:invoke_v,a:invoke_vi,c:invoke_vii,e:invoke_viii,f:invoke_viiii,g:invoke_viiiii,v:invoke_vji,p:_llvm_eh_typeid_for};var asm=createWasm();var ___wasm_call_ctors=function(){return(___wasm_call_ctors=Module["asm"]["N"]).apply(null,arguments)};var _interpret=Module["_interpret"]=function(){return(_interpret=Module["_interpret"]=Module["asm"]["O"]).apply(null,arguments)};var _alloc=Module["_alloc"]=function(){return(_alloc=Module["_alloc"]=Module["asm"]["P"]).apply(null,arguments)};var _dealloc=Module["_dealloc"]=function(){return(_dealloc=Module["_dealloc"]=Module["asm"]["Q"]).apply(null,arguments)};var _main=Module["_main"]=function(){return(_main=Module["_main"]=Module["asm"]["R"]).apply(null,arguments)};var ___errno_location=function(){return(___errno_location=Module["asm"]["__errno_location"]).apply(null,arguments)};var _malloc=function(){return(_malloc=Module["asm"]["malloc"]).apply(null,arguments)};var _htonl=function(){return(_htonl=Module["asm"]["htonl"]).apply(null,arguments)};var _htons=function(){return(_htons=Module["asm"]["htons"]).apply(null,arguments)};var _ntohs=function(){return(_ntohs=Module["asm"]["ntohs"]).apply(null,arguments)};var _setThrew=function(){return(_setThrew=Module["asm"]["T"]).apply(null,arguments)};var setTempRet0=function(){return(setTempRet0=Module["asm"]["U"]).apply(null,arguments)};var stackSave=function(){return(stackSave=Module["asm"]["V"]).apply(null,arguments)};var stackRestore=function(){return(stackRestore=Module["asm"]["W"]).apply(null,arguments)};var stackAlloc=function(){return(stackAlloc=Module["asm"]["X"]).apply(null,arguments)};var ___cxa_free_exception=function(){return(___cxa_free_exception=Module["asm"]["__cxa_free_exception"]).apply(null,arguments)};var ___cxa_increment_exception_refcount=function(){return(___cxa_increment_exception_refcount=Module["asm"]["Y"]).apply(null,arguments)};var ___cxa_decrement_exception_refcount=function(){return(___cxa_decrement_exception_refcount=Module["asm"]["Z"]).apply(null,arguments)};var ___cxa_can_catch=function(){return(___cxa_can_catch=Module["asm"]["_"]).apply(null,arguments)};var ___cxa_is_pointer_type=function(){return(___cxa_is_pointer_type=Module["asm"]["$"]).apply(null,arguments)};var dynCall_vji=Module["dynCall_vji"]=function(){return(dynCall_vji=Module["dynCall_vji"]=Module["asm"]["aa"]).apply(null,arguments)};var dynCall_jii=Module["dynCall_jii"]=function(){return(dynCall_jii=Module["dynCall_jii"]=Module["asm"]["ba"]).apply(null,arguments)};function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jii(index,a1,a2){var sp=stackSave();try{return dynCall_jii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vji(index,a1,a2,a3){var sp=stackSave();try{dynCall_vji(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}Module["UTF8ToString"]=UTF8ToString;Module["intArrayFromString"]=intArrayFromString;Module["writeArrayToMemory"]=writeArrayToMemory;Module["FS"]=FS;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=_main;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv>>2;args.forEach((arg=>{HEAP32[argv_ptr++]=stringToUTF8OnStack(arg)}));HEAP32[argv_ptr]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run(); - - - return moduleArg.ready -} - -); -})(); -if (typeof exports === 'object' && typeof module === 'object') - module.exports = MeowScript; -else if (typeof define === 'function' && define['amd']) - define([], () => MeowScript); diff --git a/site/public/meowscript.wasm b/site/public/meowscript.wasm deleted file mode 100644 index 385f8f0..0000000 Binary files a/site/public/meowscript.wasm and /dev/null differ diff --git a/site/public/image.png b/site/public/og.png similarity index 100% rename from site/public/image.png rename to site/public/og.png diff --git a/site/public/wasm/meowscript.js b/site/public/wasm/meowscript.js new file mode 100644 index 0000000..9bdcacc --- /dev/null +++ b/site/public/wasm/meowscript.js @@ -0,0 +1,331 @@ +/** + * @returns {string[]} + */ +export function keywords() { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.keywords(retptr); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var v1 = getArrayJsValueFromWasm0(r0, r1); + wasm.__wbindgen_export2(r0, r1 * 4, 4); + return v1; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * Calls `on_output` once per printed line. Rejects with the rendered error text on failure. + * @param {string} source + * @param {Function} on_output + */ +export function run(source, on_output) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0(source, wasm.__wbindgen_export3, wasm.__wbindgen_export4); + const len0 = WASM_VECTOR_LEN; + wasm.run(retptr, ptr0, len0, addBorrowedObject(on_output)); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + if (r1) { + throw takeObject(r0); + } + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + heap[stack_pointer++] = undefined; + } +} + +/** + * @returns {string} + */ +export function version() { + let deferred1_0; + let deferred1_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.version(retptr); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + deferred1_0 = r0; + deferred1_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_export2(deferred1_0, deferred1_1, 1); + } +} +function __wbg_get_imports() { + const import0 = { + __proto__: null, + __wbg___wbindgen_throw_41e9ee4f547fc59a: function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }, + __wbg_call_187d372bd5fdd4aa: function() { return handleError(function (arg0, arg1, arg2) { + const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }, arguments); }, + __wbg_now_aa4ccb83129e9e55: function() { + const ret = Date.now(); + return ret; + }, + __wbg_random_5a4cafd2f02395ff: function() { + const ret = Math.random(); + return ret; + }, + __wbindgen_generic_0000000000000001: function(arg0, arg1) { + // Cast intrinsic for `Ref(String) -> Externref`. + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); + }, + __wbindgen_object_clone_ref: function(arg0) { + const ret = getObject(arg0); + return addHeapObject(ret); + }, + __wbindgen_object_drop_ref: function(arg0) { + takeObject(arg0); + }, + }; + return { + __proto__: null, + "./meowscript_bg.js": import0, + }; +} + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +function addBorrowedObject(obj) { + if (stack_pointer == 1) throw new Error('out of js stack'); + heap[--stack_pointer] = obj; + return stack_pointer; +} + +function dropObject(idx) { + if (idx < 1028) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function getArrayJsValueFromWasm0(ptr, len) { + ptr = ptr >>> 0; + const mem = getDataViewMemory0(); + const result = []; + for (let i = ptr; i < ptr + 4 * len; i += 4) { + result.push(takeObject(mem.getUint32(i, true))); + } + return result; +} + +let cachedDataViewMemory0 = null; +function getDataViewMemory0() { + if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); + } + return cachedDataViewMemory0; +} + +function getStringFromWasm0(ptr, len) { + return decodeText(ptr >>> 0, len); +} + +let cachedUint8ArrayMemory0 = null; +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +function getObject(idx) { return heap[idx]; } + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_export(addHeapObject(e)); + } +} + +let heap = new Array(1024).fill(undefined); +heap.push(undefined, null, true, false); + +let heap_next = heap.length; + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = cachedTextEncoder.encodeInto(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +let stack_pointer = 1024; + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); +cachedTextDecoder.decode(); +const MAX_SAFARI_DECODE_BYTES = 2146435072; +let numBytesDecoded = 0; +function decodeText(ptr, len) { + numBytesDecoded += len; + if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) { + cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + cachedTextDecoder.decode(); + numBytesDecoded = len; + } + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} + +const cachedTextEncoder = new TextEncoder(); + +if (!('encodeInto' in cachedTextEncoder)) { + cachedTextEncoder.encodeInto = function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; + }; +} + +let WASM_VECTOR_LEN = 0; + +let wasmModule, wasmInstance, wasm; +function __wbg_finalize_init(instance, module) { + wasmInstance = instance; + wasm = instance.exports; + wasmModule = module; + cachedDataViewMemory0 = null; + cachedUint8ArrayMemory0 = null; + return wasm; +} + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (!module.ok) { + throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`); + } + + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + } catch (e) { + const validResponse = expectedResponseType(module.type); + + if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') { + console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); + + } else { throw e; } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + } else { + return instance; + } + } + + function expectedResponseType(type) { + switch (type) { + case 'basic': case 'cors': case 'default': return true; + } + return false; + } +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + + if (module !== undefined) { + if (Object.getPrototypeOf(module) === Object.prototype) { + ({module} = module) + } else { + console.warn('using deprecated parameters for `initSync()`; pass a single object instead') + } + } + + const imports = __wbg_get_imports(); + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + const instance = new WebAssembly.Instance(module, imports); + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(module_or_path) { + if (wasm !== undefined) return wasm; + + + if (module_or_path !== undefined) { + if (Object.getPrototypeOf(module_or_path) === Object.prototype) { + ({module_or_path} = module_or_path) + } else { + console.warn('using deprecated parameters for the initialization function; pass a single object instead') + } + } + + if (module_or_path === undefined) { + module_or_path = new URL('meowscript_bg.wasm', import.meta.url); + } + const imports = __wbg_get_imports(); + + if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) { + module_or_path = fetch(module_or_path); + } + + const { instance, module } = await __wbg_load(await module_or_path, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync, __wbg_init as default }; diff --git a/site/public/wasm/meowscript_bg.wasm b/site/public/wasm/meowscript_bg.wasm new file mode 100644 index 0000000..0195145 Binary files /dev/null and b/site/public/wasm/meowscript_bg.wasm differ diff --git a/site/scripts/build-wasm.mjs b/site/scripts/build-wasm.mjs new file mode 100644 index 0000000..f27cb71 --- /dev/null +++ b/site/scripts/build-wasm.mjs @@ -0,0 +1,35 @@ +// wasm-pack -> public/wasm. Removes the .gitignore wasm-pack drops there, since the output is +// committed. + +import { spawnSync } from "node:child_process"; +import { rmSync } from "node:fs"; +import { fileURLToPath } from "node:url"; + +const repoRoot = fileURLToPath(new URL("../../", import.meta.url)); +const outDir = fileURLToPath(new URL("../public/wasm/", import.meta.url)); + +const result = spawnSync( + "wasm-pack", + [ + "build", + "crates/meowscript-wasm", + "--release", + "--target", + "web", + "--out-dir", + outDir, + "--out-name", + "meowscript", + "--no-pack", + "--no-typescript", + ], + { cwd: repoRoot, stdio: "inherit" }, +); + +if (result.status !== 0) { + console.error("build-wasm: wasm-pack failed. Is it installed? https://github.com/wasm-bindgen/wasm-pack"); + process.exit(result.status ?? 1); +} + +rmSync(new URL(".gitignore", `file://${outDir}`), { force: true }); +console.log("build-wasm: wrote public/wasm/meowscript.js and meowscript_bg.wasm"); diff --git a/site/scripts/sync-examples.mjs b/site/scripts/sync-examples.mjs new file mode 100644 index 0000000..f500c6c --- /dev/null +++ b/site/scripts/sync-examples.mjs @@ -0,0 +1,38 @@ +// examples/*.meow -> src/generated/examples.ts. Keeps the committed file when examples/ is +// not around (on Vercel, say). + +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; + +const ORDER = ["hello", "yarn", "fizzbuzz", "closures", "recursion", "furrball", "whiskers", "toy", "naptime"]; + +const examplesDir = new URL("../../examples/", import.meta.url); +const outFile = fileURLToPath(new URL("../src/generated/examples.ts", import.meta.url)); + +if (!existsSync(examplesDir)) { + console.log("sync-examples: examples/ not found, keeping the committed src/generated/examples.ts"); + process.exit(0); +} + +const examples = ORDER.map((id) => { + const raw = readFileSync(new URL(`${id}.meow`, examplesDir), "utf8").replace(/\r\n/g, "\n"); + const lines = raw.split("\n").filter((line) => !line.includes("// test: skip")); + const descriptionLine = lines.find((line) => line.startsWith("//")); + const description = descriptionLine ? descriptionLine.replace(/^\/\/\s*/, "") : ""; + const source = lines.join("\n").replace(/^\n+/, "").replace(/\n+$/, "\n"); + return { id, file: `${id}.meow`, description, source }; +}); + +const header = `// Generated by scripts/sync-examples.mjs from examples/*.meow. Do not edit by hand. + +export interface Example { + id: string; + file: string; + description: string; + source: string; +} + +export const examples: Example[] = `; + +writeFileSync(outFile, `${header}${JSON.stringify(examples, null, 2)};\n`); +console.log(`sync-examples: wrote ${examples.length} examples`); diff --git a/site/scripts/sync-stdlib.mjs b/site/scripts/sync-stdlib.mjs new file mode 100644 index 0000000..b117be0 --- /dev/null +++ b/site/scripts/sync-stdlib.mjs @@ -0,0 +1,54 @@ +// `meowscript packages --json` -> src/generated/stdlib.ts. Keeps the committed file when cargo +// is not available. + +import { spawnSync } from "node:child_process"; +import { writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; + +const repoRoot = fileURLToPath(new URL("../../", import.meta.url)); +const outFile = fileURLToPath(new URL("../src/generated/stdlib.ts", import.meta.url)); + +const result = spawnSync("cargo", ["run", "--quiet", "-p", "meowscript-cli", "--", "packages", "--json"], { + cwd: repoRoot, + encoding: "utf8", +}); + +if (result.error || result.status !== 0) { + const reason = result.error ? result.error.message : (result.stderr || "").trim().split("\n").pop(); + console.log(`sync-stdlib: cargo not usable (${reason}), keeping the committed src/generated/stdlib.ts`); + process.exit(0); +} + +const listing = JSON.parse(result.stdout); + +const header = `// Generated by scripts/sync-stdlib.mjs from \`meowscript packages --json\`. Do not edit by hand. + +export interface BuiltinDoc { + name: string; + arity: string; + doc: string; +} + +export interface ConstantDoc { + name: string; + /** A number, or "Infinity" for values JSON can't carry. */ + value: number | string; +} + +export interface PackageDoc { + name: string; + doc: string; + functions: BuiltinDoc[]; + constants: ConstantDoc[]; +} + +export interface StdlibDoc { + version: string; + prelude: BuiltinDoc[]; + packages: PackageDoc[]; +} + +export const stdlib: StdlibDoc = `; + +writeFileSync(outFile, `${header}${JSON.stringify(listing, null, 2)};\n`); +console.log(`sync-stdlib: wrote ${listing.packages.length} packages for MeowScript ${listing.version}`); diff --git a/site/src/app/docs/page.tsx b/site/src/app/docs/page.tsx new file mode 100644 index 0000000..d804893 --- /dev/null +++ b/site/src/app/docs/page.tsx @@ -0,0 +1,64 @@ +import type { Metadata } from "next"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import Markdown from "react-markdown"; +import remarkGfm from "remark-gfm"; +import { CodeBlock } from "@/components/CodeBlock"; +import { SiteFooter } from "@/components/SiteFooter"; +import { SiteHeader } from "@/components/SiteHeader"; +import { StdlibReference } from "@/components/StdlibReference"; + +export const metadata: Metadata = { + title: "Docs", + description: "The MeowScript language reference: every keyword, operator, and nya: pawckage.", +}; + +function slug(text: string): string { + return text + .toLowerCase() + .replace(/[^a-z0-9\s-]/g, "") + .trim() + .replace(/\s+/g, "-"); +} + +function textOf(node: React.ReactNode): string { + if (typeof node === "string") return node; + if (Array.isArray(node)) return node.map(textOf).join(""); + if (node && typeof node === "object" && "props" in node) { + return textOf((node as { props: { children?: React.ReactNode } }).props.children); + } + return ""; +} + +export default function DocsPage() { + const source = readFileSync(join(process.cwd(), "content", "docs.md"), "utf8"); + + return ( + <> + +
+
+

{children}

, + h3: ({ children }) =>

{children}

, + pre: ({ children }) => <>{children}, + code: ({ className, children }) => { + const text = textOf(children); + const isBlock = text.includes("\n") || (className ?? "").startsWith("language-"); + if (!isBlock) return {children}; + const lang = (className ?? "").replace("language-", ""); + return ; + }, + }} + > + {source} +
+ +
+
+ + + ); +} diff --git a/site/src/app/globals.css b/site/src/app/globals.css new file mode 100644 index 0000000..313bc38 --- /dev/null +++ b/site/src/app/globals.css @@ -0,0 +1,225 @@ +@import "tailwindcss"; + +/* Tokens. See DESIGN.md at the repository root for the reasoning. */ +@theme { + --color-*: initial; + --color-bg: #171310; + --color-surface: #201a15; + --color-surface-2: #2a231c; + --color-line: #3b3128; + --color-text: #f1e8d8; + --color-text-soft: #cdbfab; + --color-muted: #a09078; + --color-accent: #f0a048; + --color-accent-strong: #ffb860; + --color-paw: #e9a9bd; + --color-catnip: #a7d79c; + --color-danger: #f0846f; + --color-transparent: transparent; + --color-current: currentColor; +} + +@theme inline { + --font-display: var(--font-baloo), ui-rounded, "Segoe UI", system-ui, sans-serif; + --font-mono: var(--font-fira), ui-monospace, "Cascadia Code", Menlo, Consolas, monospace; + --font-sans: var(--font-mono); +} + +@layer base { + html { + color-scheme: dark; + scroll-behavior: smooth; + } + + @media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + } + + body { + background-color: var(--color-bg); + color: var(--color-text); + font-family: var(--font-mono); + font-size: 15px; + line-height: 1.6; + /* Prose is set in the code font, but ligatures only belong in code. */ + font-variant-ligatures: none; + text-rendering: optimizeLegibility; + } + + code, + pre, + .cm-editor { + font-variant-ligatures: normal; + font-feature-settings: "calt" 1; + } + + h1, + h2, + h3 { + font-family: var(--font-display); + line-height: 1.15; + letter-spacing: -0.01em; + text-wrap: balance; + } + + :focus-visible { + outline: 2px solid var(--color-accent); + outline-offset: 2px; + border-radius: 2px; + } + + ::selection { + background: color-mix(in oklab, var(--color-accent) 35%, transparent); + } + + button:not(:disabled) { + cursor: pointer; + } + + select { + appearance: none; + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: right 10px center; + padding-right: 30px; + } +} + +/* The pun is spelled wrong on purpose, so it gets the spellchecker's squiggle. */ +.squiggle { + text-decoration: underline wavy var(--color-danger); + text-decoration-thickness: 2px; + text-underline-offset: 6px; +} + +.paw-step { + animation: paw-step 240ms ease-out both; +} +@keyframes paw-step { + from { + opacity: 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .paw-step { + animation: none; + } +} + +/* Static listings. The editor uses the same colours in src/lib/meowscript-language.ts. */ +.tok-keyword { + color: var(--color-accent); +} +.tok-atom, +.tok-number { + color: var(--color-catnip); +} +.tok-string { + color: var(--color-paw); +} +.tok-comment { + color: var(--color-muted); + font-style: italic; +} +.tok-operator, +.tok-punctuation { + color: var(--color-text-soft); +} +.tok-invalid { + color: var(--color-danger); + text-decoration: underline wavy; +} + +.docs { + max-width: 72ch; +} +.docs h1 { + font-size: 36px; + font-weight: 800; + margin-bottom: 8px; +} +.docs h2 { + font-size: 24px; + font-weight: 700; + margin-top: 56px; + padding-top: 24px; + border-top: 1px solid var(--color-line); + scroll-margin-top: 80px; +} +.docs h3 { + font-size: 18px; + font-weight: 700; + margin-top: 32px; + scroll-margin-top: 80px; +} +.docs p, +.docs ul, +.docs ol { + margin-top: 12px; + color: var(--color-text-soft); +} +.docs li { + margin-top: 6px; + padding-left: 4px; +} +.docs ul { + list-style: disc; + padding-left: 22px; +} +.docs ol { + list-style: decimal; + padding-left: 22px; +} +.docs strong { + color: var(--color-text); + font-weight: 400; +} +.docs a { + color: var(--color-text); + text-decoration: underline; + text-decoration-color: var(--color-line); + text-underline-offset: 4px; +} +.docs a:hover { + color: var(--color-accent); + text-decoration-color: currentColor; +} +.docs :not(pre) > code { + color: var(--color-text); + background: var(--color-surface-2); + padding: 1px 5px; + border-radius: 4px; + font-size: 0.93em; +} +.docs table { + width: 100%; + margin-top: 16px; + border-collapse: collapse; + font-size: 14px; +} +.docs th { + text-align: left; + font-weight: 400; + color: var(--color-muted); + font-size: 13px; + padding: 0 12px 8px 0; + border-bottom: 1px solid var(--color-line); +} +.docs td { + padding: 8px 12px 8px 0; + border-bottom: 1px solid var(--color-line); + vertical-align: top; + color: var(--color-text-soft); +} +.docs td:first-child { + white-space: nowrap; +} +.docs blockquote { + margin-top: 12px; + padding-left: 14px; + border-left: 2px solid var(--color-accent); + color: var(--color-text-soft); +} diff --git a/site/src/app/icon.svg b/site/src/app/icon.svg new file mode 100644 index 0000000..f4936e2 --- /dev/null +++ b/site/src/app/icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/site/src/app/layout.tsx b/site/src/app/layout.tsx new file mode 100644 index 0000000..61409ca --- /dev/null +++ b/site/src/app/layout.tsx @@ -0,0 +1,63 @@ +import type { Metadata, Viewport } from "next"; +import { Baloo_2 } from "next/font/google"; +import localFont from "next/font/local"; +import "./globals.css"; + +const baloo = Baloo_2({ + subsets: ["latin"], + weight: ["700", "800"], + variable: "--font-baloo", + display: "swap", +}); + +const fira = localFont({ + src: "../fonts/FiraCode-Regular.woff2", + weight: "400", + style: "normal", + variable: "--font-fira", + display: "swap", +}); + +const title = "MeowScript"; +const description = + "The purrfect programming language. A small scripting language with cat-pun keywords, interpreted in Rust and running in your browser."; + +export const metadata: Metadata = { + metadataBase: new URL("https://meowscript.vercel.app"), + title: { + default: title, + template: `%s · ${title}`, + }, + description, + openGraph: { + title, + description, + siteName: title, + type: "website", + images: ["/og.png"], + }, + twitter: { + card: "summary", + title, + description, + creator: "@alenvelocity", + images: ["/og.png"], + }, +}; + +export const viewport: Viewport = { + themeColor: "#171310", + colorScheme: "dark", +}; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/site/src/app/not-found.tsx b/site/src/app/not-found.tsx new file mode 100644 index 0000000..5887416 --- /dev/null +++ b/site/src/app/not-found.tsx @@ -0,0 +1,24 @@ +import Link from "next/link"; +import { Paw } from "@/components/Paw"; +import { SiteFooter } from "@/components/SiteFooter"; +import { SiteHeader } from "@/components/SiteHeader"; + +export default function NotFound() { + return ( + <> + +
+ +

Meow-sterious.

+

There is no page at this address.

+ + Back to the playground + +
+ + + ); +} diff --git a/site/src/app/page.tsx b/site/src/app/page.tsx new file mode 100644 index 0000000..b673320 --- /dev/null +++ b/site/src/app/page.tsx @@ -0,0 +1,120 @@ +import Link from "next/link"; +import { CheatSheet } from "@/components/CheatSheet"; +import { CodeBlock } from "@/components/CodeBlock"; +import { Paw } from "@/components/Paw"; +import { PlaygroundLoader } from "@/components/PlaygroundLoader"; +import { SiteFooter } from "@/components/SiteFooter"; +import { SiteHeader } from "@/components/SiteHeader"; +import { examples } from "@/generated/examples"; +import { stdlib } from "@/generated/stdlib"; + +const trail = [ + { left: "58%", top: "6%", rotate: -32 }, + { left: "64%", top: "22%", rotate: -18 }, + { left: "71%", top: "36%", rotate: -32 }, + { left: "77%", top: "52%", rotate: -18 }, + { left: "84%", top: "66%", rotate: -32 }, + { left: "90%", top: "82%", rotate: -18 }, +]; + +function PawTrail() { + return ( + + ); +} + +export default function Home() { + return ( + <> + +
+
+ +

+ The purrfect programming language. +

+

+ MeowScript is a small scripting language where purrhaps means if,{" "} + pawction means function, and every program announces itself with a{" "} + meow. The interpreter is written in Rust and runs right here, in your + browser. +

+
+ + + +
+ +
+ +
+

+ Batteries, in a bag of nya +

+

+ meow, purr, and length are always there. Everything else is a{" "} + pawckage away. +

+
    + {stdlib.packages.map((pkg) => ( +
  • + + {pkg.name} + +

    {pkg.doc}

    +

    + {pkg.functions.map((f) => f.name).join(", ")} + {pkg.constants.length > 0 && `, ${pkg.constants.map((c) => c.name).join(", ")}`} +

    +
  • + ))} +
+
+ +
+

+ Run it on your own machine +

+

+ The command line build adds a REPL and file access. It needs a Rust toolchain. +

+
+ +
+

+ The full language reference is in the{" "} + + docs + + . +

+
+
+ + + ); +} diff --git a/site/src/components/CheatSheet.tsx b/site/src/components/CheatSheet.tsx new file mode 100644 index 0000000..db1df3d --- /dev/null +++ b/site/src/components/CheatSheet.tsx @@ -0,0 +1,85 @@ +import { CodeBlock } from "./CodeBlock"; + +const rows: { cat: string; human: string; example: string }[] = [ + { cat: "scratch", human: "declare a variable", example: "scratch lives = 9;" }, + { cat: "amew", human: "change it", example: "amew lives = lives - 1;" }, + { cat: "pawction", human: "function", example: 'pawction greet(name) { meow("Hi", name); }' }, + { cat: "tail", human: "return", example: "tail lives * 2;" }, + { cat: "purrhaps / meowtually", human: "if / else", example: 'purrhaps hungry { meow("feed me") } meowtually { nap(10) }' }, + { cat: "furrever", human: "loop, with an optional condition", example: "furrever lives > 0 { amew lives = lives - 1; }" }, + { cat: "fur ~", human: "for each", example: "fur toy ~ toys { meow(toy); }" }, + { cat: "hiss / continue", human: "break / continue", example: "purrhaps tired { hiss; }" }, + { cat: "purrfect / clawful", human: "true / false", example: "scratch asleep = purrfect;" }, + { cat: "mew", human: "null", example: "scratch owner = mew;" }, + { cat: "furreal", human: "typeof", example: 'furreal "whiskers" // "whiskers"' }, + { cat: "pawckage", human: "import", example: 'pawckage "nya:furrball";' }, + { cat: "'s", human: "property access", example: "cat's name" }, + { cat: "~", human: "is in", example: '"Tom" ~ cats' }, + { cat: "whiskers", human: "a string", example: '"meow"' }, + { cat: "furrball", human: "an array", example: '["yarn", "box", "sunbeam"]' }, +]; + +export function CheatSheet() { + return ( +
+

+ Cat to human +

+

+ Every keyword is a pun, and every pun means exactly one ordinary thing. This is the whole vocabulary. +

+
+ + + + + + + + + + {rows.map((row) => ( + + + + + + ))} + +
+ Cat + + Human + + Looks like +
+ {row.cat} + {row.human} + {row.example} +
+
+
+

Put together, it reads like this:

+ +
+
+ ); +} diff --git a/site/src/components/CodeBlock.tsx b/site/src/components/CodeBlock.tsx new file mode 100644 index 0000000..ff2bfd0 --- /dev/null +++ b/site/src/components/CodeBlock.tsx @@ -0,0 +1,38 @@ +import { initialState, tokenizeLine } from "@/lib/meowscript-language"; +import { TryItButton } from "./TryItButton"; + +interface Props { + code: string; + tryIt?: boolean; + plain?: boolean; +} + +export function CodeBlock({ code, tryIt = false, plain = false }: Props) { + const text = code.replace(/\n$/, ""); + const lines = text.split("\n"); + const state = initialState(); + + return ( +
+
+        
+          {plain
+            ? text
+            : lines.map((line, i) => (
+                
+                  {tokenizeLine(line, state).map((tok, j) => (
+                    
+                      {tok.text}
+                    
+                  ))}
+                  {line === "" ? " " : null}
+                
+              ))}
+        
+      
+ {tryIt && } +
+ ); +} diff --git a/site/src/components/Editor.tsx b/site/src/components/Editor.tsx new file mode 100644 index 0000000..0091f71 --- /dev/null +++ b/site/src/components/Editor.tsx @@ -0,0 +1,97 @@ +"use client"; + +import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete"; +import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands"; +import { bracketMatching, indentOnInput, indentUnit } from "@codemirror/language"; +import { EditorState } from "@codemirror/state"; +import { + drawSelection, + dropCursor, + EditorView, + highlightActiveLine, + highlightActiveLineGutter, + highlightSpecialChars, + keymap, + lineNumbers, +} from "@codemirror/view"; +import { useEffect, useRef } from "react"; +import { meowscript, meowTheme } from "@/lib/meowscript-language"; + +interface Props { + value: string; + onChange: (value: string) => void; + onRun: () => void; + ariaLabel?: string; +} + +export function Editor({ value, onChange, onRun, ariaLabel = "MeowScript source" }: Props) { + const hostRef = useRef(null); + const viewRef = useRef(null); + // The editor is built once; these refs let its callbacks see the latest props. + const onChangeRef = useRef(onChange); + const onRunRef = useRef(onRun); + useEffect(() => { + onChangeRef.current = onChange; + onRunRef.current = onRun; + }); + + useEffect(() => { + const host = hostRef.current; + if (!host) return; + const view = new EditorView({ + parent: host, + state: EditorState.create({ + doc: value, + extensions: [ + lineNumbers(), + highlightActiveLineGutter(), + highlightSpecialChars(), + history(), + drawSelection(), + dropCursor(), + indentOnInput(), + bracketMatching(), + closeBrackets(), + highlightActiveLine(), + indentUnit.of(" "), + keymap.of([ + { + key: "Mod-Enter", + run: () => { + onRunRef.current(); + return true; + }, + }, + ...closeBracketsKeymap, + ...defaultKeymap, + ...historyKeymap, + indentWithTab, + ]), + meowscript(), + meowTheme, + EditorView.contentAttributes.of({ "aria-label": ariaLabel }), + EditorView.updateListener.of((update) => { + if (update.docChanged) onChangeRef.current(update.state.doc.toString()); + }), + ], + }), + }); + viewRef.current = view; + return () => { + view.destroy(); + viewRef.current = null; + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + const view = viewRef.current; + if (!view) return; + const current = view.state.doc.toString(); + if (current !== value) { + view.dispatch({ changes: { from: 0, to: current.length, insert: value } }); + } + }, [value]); + + return
; +} diff --git a/site/src/components/Output.tsx b/site/src/components/Output.tsx new file mode 100644 index 0000000..11805c6 --- /dev/null +++ b/site/src/components/Output.tsx @@ -0,0 +1,130 @@ +"use client"; + +import { useEffect, useRef } from "react"; +import type { OutputLine, Status } from "@/lib/use-meowscript"; + +interface Props { + lines: OutputLine[]; + status: Status; + version: string | null; + lastRunMillis: number | null; + fatal: string | null; +} + +const MEOW = "Meow!"; +const PAW_ID = "output-paw"; + +// Defined once; every meowed line references it, so thousands of lines stay cheap. +function PawSymbol() { + return ( + + ); +} + +function PawMark({ className }: { className: string }) { + return ( + + ); +} + +function ErrorLine({ text }: { text: string }) { + const newline = text.indexOf("\n"); + const first = newline === -1 ? text : text.slice(0, newline); + const rest = newline === -1 ? "" : text.slice(newline); + const space = first.indexOf(" "); + const exclamation = space === -1 ? first : first.slice(0, space); + const message = space === -1 ? "" : first.slice(space); + return ( +
+      {exclamation}
+      {message}
+      {rest}
+    
+ ); +} + +function Line({ line }: { line: OutputLine }) { + if (line.kind === "error") return ; + if (line.kind === "note") return
{line.text}
; + if (line.text === MEOW || line.text.startsWith(`${MEOW} `)) { + return ( +
+ + + {MEOW} + + {line.text.slice(MEOW.length)} +
+ ); + } + return
{line.text || " "}
; +} + +function statusText({ status, lines, lastRunMillis, fatal }: Props): string { + if (fatal) return "The interpreter could not start"; + if (status === "loading") return "Waking up the interpreter…"; + if (status === "running") return "Playing…"; + if (lines.at(-1)?.kind === "error") return "Hissed"; + if (lastRunMillis !== null) return `Purring · finished in ${lastRunMillis} ms`; + return "Ready"; +} + +export function Output(props: Props) { + const { lines, status, version, fatal } = props; + const scrollRef = useRef(null); + + useEffect(() => { + const el = scrollRef.current; + if (el) el.scrollTop = el.scrollHeight; + }, [lines]); + + return ( +
+ +
+ {fatal ? ( +
+ +

The playground could not load the interpreter.

+

{fatal}

+

+ Try a hard refresh. If it keeps happening,{" "} + + open an issue + + . +

+
+ ) : lines.length === 0 ? ( +
+ +

+ {status === "loading" ? "Waking up…" : "Press Run, or Ctrl+Enter in the editor, to hear from the cat."} +

+
+ ) : ( + lines.map((line, i) => ) + )} +
+
+ {statusText(props)} + {version ? `MeowScript ${version} · WebAssembly` : ""} +
+
+ ); +} diff --git a/site/src/components/Paw.tsx b/site/src/components/Paw.tsx new file mode 100644 index 0000000..1fdfa22 --- /dev/null +++ b/site/src/components/Paw.tsx @@ -0,0 +1,13 @@ +import type { CSSProperties } from "react"; + +export function Paw({ className = "", style }: { className?: string; style?: CSSProperties }) { + return ( + + ); +} diff --git a/site/src/components/Playground.tsx b/site/src/components/Playground.tsx new file mode 100644 index 0000000..5b52f1b --- /dev/null +++ b/site/src/components/Playground.tsx @@ -0,0 +1,111 @@ +"use client"; + +import { useCallback, useId, useState } from "react"; +import type { Example } from "@/generated/examples"; +import { takeHandedCode } from "@/lib/try-it"; +import { useMeowScript } from "@/lib/use-meowscript"; +import { Editor } from "./Editor"; +import { Output } from "./Output"; +import { Paw } from "./Paw"; + +interface Props { + examples: Example[]; + initialExampleId?: string; +} + +// Client-only (see PlaygroundLoader), so sessionStorage can be read while picking the first program. +export function Playground({ examples, initialExampleId = "yarn" }: Props) { + const fallback = examples.find((e) => e.id === initialExampleId) ?? examples[0]; + const [state, setState] = useState(() => { + const handed = takeHandedCode(); + return handed !== null ? { code: handed, selected: "" } : { code: fallback.source, selected: fallback.id }; + }); + const meow = useMeowScript(); + const selectId = useId(); + + const { code, selected } = state; + const setCode = useCallback((code: string) => setState((s) => ({ ...s, code })), []); + const run = useCallback(() => meow.run(code), [meow, code]); + + const pickExample = (id: string) => { + const example = examples.find((e) => e.id === id); + if (!example) return; + setState({ code: example.source, selected: id }); + meow.clear(); + }; + + const busy = meow.status === "running"; + const canRun = meow.status === "ready"; + const current = examples.find((e) => e.id === selected); + + return ( +
+
+
+ + +
+
+ + {busy ? ( + + ) : ( + + )} +
+
+ +
+
+ +
+
+ +
+
+ {current?.description &&

{current.description}

} +
+ ); +} diff --git a/site/src/components/PlaygroundLoader.tsx b/site/src/components/PlaygroundLoader.tsx new file mode 100644 index 0000000..c3e0393 --- /dev/null +++ b/site/src/components/PlaygroundLoader.tsx @@ -0,0 +1,30 @@ +"use client"; + +import dynamic from "next/dynamic"; +import type { Example } from "@/generated/examples"; + +function PlaygroundSkeleton() { + return ( +
+
+
+
+
+
+
+
+ Loading the playground… +
+
+
+ ); +} + +const Playground = dynamic(() => import("./Playground").then((m) => m.Playground), { + ssr: false, + loading: PlaygroundSkeleton, +}); + +export function PlaygroundLoader({ examples }: { examples: Example[] }) { + return ; +} diff --git a/site/src/components/SiteFooter.tsx b/site/src/components/SiteFooter.tsx new file mode 100644 index 0000000..52102d9 --- /dev/null +++ b/site/src/components/SiteFooter.tsx @@ -0,0 +1,13 @@ +export function SiteFooter() { + return ( +
+

+ Made by{" "} + + Alen + + , with help from a cat. Interpreter in Rust, running in your browser as WebAssembly. +

+
+ ); +} diff --git a/site/src/components/SiteHeader.tsx b/site/src/components/SiteHeader.tsx new file mode 100644 index 0000000..c54582a --- /dev/null +++ b/site/src/components/SiteHeader.tsx @@ -0,0 +1,24 @@ +import Link from "next/link"; +import { Paw } from "./Paw"; + +export function SiteHeader() { + return ( +
+ + + meowscript + + +
+ ); +} diff --git a/site/src/components/StdlibReference.tsx b/site/src/components/StdlibReference.tsx new file mode 100644 index 0000000..06ff09e --- /dev/null +++ b/site/src/components/StdlibReference.tsx @@ -0,0 +1,72 @@ +import { stdlib } from "@/generated/stdlib"; + +export function StdlibReference() { + return ( + <> +

Standard library

+

+ These tables come from the interpreter itself (meowscript packages --json), so they can't + drift from the code. Arities are checked before a function runs: the wrong number of arguments is a{" "} + Paws off! error, not a silent mew. +

+ +

Always available

+ + + {stdlib.packages.map((pkg) => ( +
+

+ pawckage "{pkg.name}"; +

+

{pkg.doc}

+ + {pkg.constants.length > 0 && ( + + + + + + + + + {pkg.constants.map((c) => ( + + + + + ))} + +
ConstantValue
+ {c.name} + {String(c.value)}
+ )} +
+ ))} + + ); +} + +function FunctionTable({ functions }: { functions: { name: string; arity: string; doc: string }[] }) { + return ( + + + + + + + + + + {functions.map((f) => ( + + + + + + ))} + +
PawctionTakesDoes
+ {f.name} + {f.arity}{f.doc}
+ ); +} diff --git a/site/src/components/TryItButton.tsx b/site/src/components/TryItButton.tsx new file mode 100644 index 0000000..2d61b00 --- /dev/null +++ b/site/src/components/TryItButton.tsx @@ -0,0 +1,21 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { handOverCode } from "@/lib/try-it"; + +export function TryItButton({ code }: { code: string }) { + const router = useRouter(); + const tryIt = () => { + handOverCode(`${code}\n`); + router.push("/#playground"); + }; + return ( + + ); +} diff --git a/site/public/FiraCode-Regular.woff2 b/site/src/fonts/FiraCode-Regular.woff2 similarity index 100% rename from site/public/FiraCode-Regular.woff2 rename to site/src/fonts/FiraCode-Regular.woff2 diff --git a/site/src/generated/examples.ts b/site/src/generated/examples.ts new file mode 100644 index 0000000..8794eed --- /dev/null +++ b/site/src/generated/examples.ts @@ -0,0 +1,65 @@ +// Generated by scripts/sync-examples.mjs from examples/*.meow. Do not edit by hand. + +export interface Example { + id: string; + file: string; + description: string; + source: string; +} + +export const examples: Example[] = [ + { + "id": "hello", + "file": "hello.meow", + "description": "Every program starts with a meow.", + "source": "// Every program starts with a meow.\nmeow(\"Hello, world!\");\n\n// purr prints without the announcement.\npurr(\"The cat says:\", \"meow\", 3, \"times\");\n" + }, + { + "id": "yarn", + "file": "yarn.meow", + "description": "Objects, the possessive 's, and a loop with a condition.", + "source": "// Objects, the possessive 's, and a loop with a condition.\nscratch cat = {\n name: \"Whiskers\",\n age: 3,\n breed: \"Siamese\",\n color: \"seal point\",\n};\n\nscratch months = cat's age * 12;\nmeow(cat's name, \"is a\", cat's color, cat's breed, \"cat. He is\", months, \"months old.\");\n\npawction play_with_yarn(lives) {\n meow(\"Let's play with yarn!\");\n furrever lives > 0 {\n meow(cat's name, \"is playing with yarn, round\", 10 - lives);\n amew lives = lives - 1;\n }\n meow(\"Finished playing with yarn!\");\n}\n\nplay_with_yarn(9);\n\namew cat's age = cat's age + 1;\nmeow(\"Happy birthday!\", cat's name, \"is now\", cat's age);\n" + }, + { + "id": "fizzbuzz", + "file": "fizzbuzz.meow", + "description": "The classic, with a cat's vocabulary.", + "source": "// The classic, with a cat's vocabulary.\npawction fizzbuzz(n) {\n purrhaps n % 15 == 0 {\n tail \"FizzBuzz\";\n } meowtually purrhaps n % 3 == 0 {\n tail \"Fizz\";\n } meowtually purrhaps n % 5 == 0 {\n tail \"Buzz\";\n }\n tail n;\n}\n\nfur i ~ 15 {\n purr(fizzbuzz(i + 1));\n}\n" + }, + { + "id": "closures", + "file": "closures.meow", + "description": "Pawctions remember the scope they were born in.", + "source": "// Pawctions remember the scope they were born in.\npawction make_counter(name) {\n scratch count = 0;\n tail pawction() {\n amew count = count + 1;\n meow(name, \"has been petted\", count, \"times\");\n tail count;\n };\n}\n\nscratch pet_tom = make_counter(\"Tom\");\nscratch pet_luna = make_counter(\"Luna\");\n\npet_tom();\npet_tom();\npet_luna();\npet_tom();\n" + }, + { + "id": "recursion", + "file": "recursion.meow", + "description": "Recursion, and purrhaps as an expression.", + "source": "// Recursion, and purrhaps as an expression.\npawction fib(n) {\n purrhaps n < 2 { tail n; }\n tail fib(n - 1) + fib(n - 2);\n}\n\npawction factorial(n) {\n purrhaps n <= 1 { 1 } meowtually { n * factorial(n - 1) }\n}\n\nfur i ~ 10 {\n purr(\"fib(\" + i + \") =\", fib(i));\n}\npurr(\"10! =\", factorial(10));\n" + }, + { + "id": "furrball", + "file": "furrball.meow", + "description": "A tour of the nya:furrball pawckage.", + "source": "// A tour of the nya:furrball pawckage.\npawckage \"nya:furrball\";\n\nscratch cats = [\"Tom\", \"Garfield\", \"Felix\", \"Salem\"];\npush(cats, \"Luna\");\npurr(\"We have\", length(cats), \"cats:\", join(cats, \", \"));\n\nscratch shouty = map(cats, pawction(name) { name + \"!\" });\npurr(shouty);\n\nscratch short_names = filter(cats, pawction(name) { length(name) <= 4 });\npurr(\"Short names:\", short_names);\n\nscratch letters = reduce(cats, pawction(total, name) { total + length(name) }, 0);\npurr(\"Letters in all the names:\", letters);\n\npurr(\"Sorted:\", sort(cats));\npurr(\"Backwards:\", reverse(cats));\npurr(\"The middle two:\", slice(cats, 1, 3));\npurr(\"Is Salem here?\", \"Salem\" ~ cats);\npurr(\"Squares:\", map(range(1, 6), pawction(n) { n * n }));\n\nscratch last_cat = pounce(cats);\npurr(last_cat, \"left, so now there are\", length(cats));\n" + }, + { + "id": "whiskers", + "file": "whiskers.meow", + "description": "A tour of the nya:whiskers pawckage.", + "source": "// A tour of the nya:whiskers pawckage.\npawckage \"nya:whiskers\";\n\nscratch greeting = \" meow meow, purr \";\npurr(\"[\" + trim(greeting) + \"]\");\npurr(upper(trim(greeting)));\npurr(split(trim(greeting), \" \"));\npurr(replace(trim(greeting), \"meow\", \"nya\"));\npurr(starts_with(trim(greeting), \"meow\"), ends_with(trim(greeting), \"purr\"));\npurr(pawrse(\"42\") + 1, pawrse(\"nine\"));\npurr(pad_start(\"7\", 3, \"0\"), \"|\" + pad_end(\"cat\", 6, \".\") + \"|\");\npurr(reverse(\"stressed\"));\npurr(length(\"🐱 cat\"), \"characters\");\n\nfur letter ~ \"cat\" {\n purr(letter, \"-\", letter * 3);\n}\n" + }, + { + "id": "toy", + "file": "toy.meow", + "description": "Random choices from the nya:rundamn pawckage.", + "source": "// Random choices from the nya:rundamn pawckage.\npawckage \"nya:rundamn\";\n\nscratch toy_box = [\"Feather Wand\", \"Catnip Mouse\", \"Yarn Ball\", \"Squeaky Mouse\"];\n\npawction play_with(toy) {\n scratch sessions = randint(3, 6);\n meow(\"Let's play with the\", toy + \"!\");\n\n fur session ~ sessions {\n purrhaps toy == \"Feather Wand\" {\n meow(\"Chasing the feather!\");\n } meowtually purrhaps toy == \"Squeaky Mouse\" {\n meow(\"Squeak! Squeak!\");\n } meowtually {\n meow(\"Having fun with the\", toy);\n }\n }\n\n meow(\"I'm tired now. Time for a catnap!\");\n}\n\nplay_with(choice(toy_box));\n" + }, + { + "id": "naptime", + "file": "naptime.meow", + "description": "nap() pauses the program. In the playground, watch the output arrive live.", + "source": "// nap() pauses the program. In the playground, watch the output arrive live.\npawckage \"nya:clawtility\";\npawckage \"nya:rundamn\";\n\npawction take_a_nap() {\n furrever {\n meow(\"...zZz...\");\n nap(600);\n purrhaps randint(1, 3) == 3 {\n hiss;\n }\n }\n meow(\"I woke up! ^-^\");\n}\n\ntake_a_nap();\n" + } +]; diff --git a/site/src/generated/stdlib.ts b/site/src/generated/stdlib.ts new file mode 100644 index 0000000..2389b45 --- /dev/null +++ b/site/src/generated/stdlib.ts @@ -0,0 +1,478 @@ +// Generated by scripts/sync-stdlib.mjs from `meowscript packages --json`. Do not edit by hand. + +export interface BuiltinDoc { + name: string; + arity: string; + doc: string; +} + +export interface ConstantDoc { + name: string; + /** A number, or "Infinity" for values JSON can't carry. */ + value: number | string; +} + +export interface PackageDoc { + name: string; + doc: string; + functions: BuiltinDoc[]; + constants: ConstantDoc[]; +} + +export interface StdlibDoc { + version: string; + prelude: BuiltinDoc[]; + packages: PackageDoc[]; +} + +export const stdlib: StdlibDoc = { + "version": "1.0.0", + "prelude": [ + { + "name": "meow", + "arity": "at least 0 arguments", + "doc": "Print the arguments on one line, announced with \"Meow!\"." + }, + { + "name": "purr", + "arity": "at least 0 arguments", + "doc": "Print the arguments on one line, separated by spaces." + }, + { + "name": "log", + "arity": "at least 0 arguments", + "doc": "The same as `purr`, for people who miss JavaScript." + }, + { + "name": "length", + "arity": "exactly 1 argument", + "doc": "How many characters, items, or keys something has." + } + ], + "packages": [ + { + "name": "nya:clawtility", + "doc": "Input, timing, objects, and other everyday tools.", + "functions": [ + { + "name": "length", + "arity": "exactly 1 argument", + "doc": "How many characters, items, or keys something has." + }, + { + "name": "kibble", + "arity": "between 0 and 1 arguments", + "doc": "Read a line of input. Shows the prompt first if you give one." + }, + { + "name": "nap", + "arity": "exactly 1 argument", + "doc": "Pause for that many milliseconds." + }, + { + "name": "now", + "arity": "exactly 0 arguments", + "doc": "Milliseconds since the Unix epoch." + }, + { + "name": "keys", + "arity": "exactly 1 argument", + "doc": "A furrball of an object's keys, in insertion order." + }, + { + "name": "values", + "arity": "exactly 1 argument", + "doc": "A furrball of an object's values, in insertion order." + }, + { + "name": "remove", + "arity": "exactly 2 arguments", + "doc": "Remove a key from an object. Returns the removed value, or mew." + }, + { + "name": "assert", + "arity": "between 1 and 2 arguments", + "doc": "Stop with an error unless the first argument is truthy." + }, + { + "name": "apply", + "arity": "exactly 2 arguments", + "doc": "Call a pawction with a furrball of arguments." + } + ], + "constants": [] + }, + { + "name": "nya:furrball", + "doc": "Everything for furrballs (arrays).", + "functions": [ + { + "name": "push", + "arity": "at least 2 arguments", + "doc": "Add items to the end of a furrball. Changes it in place and returns it." + }, + { + "name": "pounce", + "arity": "exactly 1 argument", + "doc": "Remove and return the last item, or mew if the furrball is empty." + }, + { + "name": "top", + "arity": "exactly 1 argument", + "doc": "The first item, or mew." + }, + { + "name": "last", + "arity": "exactly 1 argument", + "doc": "The last item, or mew." + }, + { + "name": "bottom", + "arity": "exactly 1 argument", + "doc": "A new furrball with everything but the first item." + }, + { + "name": "includes", + "arity": "exactly 2 arguments", + "doc": "Whether a furrball has an item, or whiskers contain a substring. Same as `~`." + }, + { + "name": "index_of", + "arity": "exactly 2 arguments", + "doc": "Where an item (or substring) first appears, or -1." + }, + { + "name": "map", + "arity": "exactly 2 arguments", + "doc": "A new furrball made by calling the pawction on each item." + }, + { + "name": "filter", + "arity": "exactly 2 arguments", + "doc": "A new furrball of the items the pawction says purrfect to." + }, + { + "name": "reduce", + "arity": "between 2 and 3 arguments", + "doc": "Fold a furrball into one value with `pawction(total, item)`, starting from the optional initial value." + }, + { + "name": "each", + "arity": "exactly 2 arguments", + "doc": "Call the pawction on every item. Returns mew." + }, + { + "name": "find", + "arity": "exactly 2 arguments", + "doc": "The first item the pawction says purrfect to, or mew." + }, + { + "name": "range", + "arity": "between 1 and 3 arguments", + "doc": "Numbers from `start` (default 0) up to but not including `end`, in `step`s (default 1)." + }, + { + "name": "reverse", + "arity": "exactly 1 argument", + "doc": "A reversed copy of a furrball or whiskers." + }, + { + "name": "sort", + "arity": "between 1 and 2 arguments", + "doc": "A sorted copy. Give a `pawction(a, b)` returning a number to decide the order." + }, + { + "name": "join", + "arity": "between 1 and 2 arguments", + "doc": "Glue the items into whiskers with a separator (default none)." + }, + { + "name": "slice", + "arity": "between 2 and 3 arguments", + "doc": "A copy of part of a furrball or whiskers, from `start` up to (not including) `end`. Negative counts from the end." + }, + { + "name": "concat", + "arity": "at least 1 argument", + "doc": "A new furrball with the items of all the given furrballs." + } + ], + "constants": [] + }, + { + "name": "nya:whiskers", + "doc": "Everything for whiskers (strings).", + "functions": [ + { + "name": "in_whiskers", + "arity": "exactly 1 argument", + "doc": "Turn anything into whiskers, the way `meow` would print it." + }, + { + "name": "pawrse", + "arity": "exactly 1 argument", + "doc": "Read a number out of whiskers, or mew if there isn't one." + }, + { + "name": "replace", + "arity": "exactly 3 arguments", + "doc": "Replace every occurrence of `from` with `to`." + }, + { + "name": "split", + "arity": "between 1 and 2 arguments", + "doc": "Split into a furrball on a separator. With no separator, splits on whitespace." + }, + { + "name": "upper", + "arity": "exactly 1 argument", + "doc": "SHOUTING." + }, + { + "name": "lower", + "arity": "exactly 1 argument", + "doc": "whispering." + }, + { + "name": "trim", + "arity": "exactly 1 argument", + "doc": "Strip whitespace from both ends." + }, + { + "name": "starts_with", + "arity": "exactly 2 arguments", + "doc": "Whether the whiskers begin with the given prefix." + }, + { + "name": "ends_with", + "arity": "exactly 2 arguments", + "doc": "Whether the whiskers end with the given suffix." + }, + { + "name": "includes", + "arity": "exactly 2 arguments", + "doc": "Whether a furrball has an item, or whiskers contain a substring. Same as `~`." + }, + { + "name": "index_of", + "arity": "exactly 2 arguments", + "doc": "Where an item (or substring) first appears, or -1." + }, + { + "name": "chars", + "arity": "exactly 1 argument", + "doc": "A furrball of the individual characters." + }, + { + "name": "repeat", + "arity": "exactly 2 arguments", + "doc": "The whiskers repeated that many times. Same as `*`." + }, + { + "name": "pad_start", + "arity": "between 2 and 3 arguments", + "doc": "Pad on the left to a width, with spaces or the given filler." + }, + { + "name": "pad_end", + "arity": "between 2 and 3 arguments", + "doc": "Pad on the right to a width, with spaces or the given filler." + }, + { + "name": "reverse", + "arity": "exactly 1 argument", + "doc": "A reversed copy of a furrball or whiskers." + }, + { + "name": "slice", + "arity": "between 2 and 3 arguments", + "doc": "A copy of part of a furrball or whiskers, from `start` up to (not including) `end`. Negative counts from the end." + } + ], + "constants": [] + }, + { + "name": "nya:catculator", + "doc": "Maths. Angles are in radians.", + "functions": [ + { + "name": "random", + "arity": "between 0 and 2 arguments", + "doc": "A random number: in [0, 1) with no arguments, [0, n) with one, or [min, max) with two." + }, + { + "name": "round", + "arity": "exactly 1 argument", + "doc": "Round to the nearest whole number." + }, + { + "name": "ceil", + "arity": "exactly 1 argument", + "doc": "Round up." + }, + { + "name": "floor", + "arity": "exactly 1 argument", + "doc": "Round down." + }, + { + "name": "trunc", + "arity": "exactly 1 argument", + "doc": "Drop the fractional part." + }, + { + "name": "abs", + "arity": "exactly 1 argument", + "doc": "Distance from zero." + }, + { + "name": "sqrt", + "arity": "exactly 1 argument", + "doc": "Square root." + }, + { + "name": "sin", + "arity": "exactly 1 argument", + "doc": "Sine (radians)." + }, + { + "name": "cos", + "arity": "exactly 1 argument", + "doc": "Cosine (radians)." + }, + { + "name": "tan", + "arity": "exactly 1 argument", + "doc": "Tangent (radians)." + }, + { + "name": "log2", + "arity": "exactly 1 argument", + "doc": "Logarithm base 2." + }, + { + "name": "log10", + "arity": "exactly 1 argument", + "doc": "Logarithm base 10." + }, + { + "name": "ln", + "arity": "exactly 1 argument", + "doc": "Natural logarithm." + }, + { + "name": "exp", + "arity": "exactly 1 argument", + "doc": "e raised to the power." + }, + { + "name": "pow", + "arity": "exactly 2 arguments", + "doc": "`base` raised to `exponent`." + }, + { + "name": "modulo", + "arity": "exactly 2 arguments", + "doc": "Remainder that is never negative for a positive divisor, unlike `%`." + }, + { + "name": "min", + "arity": "at least 1 argument", + "doc": "The smallest of the numbers, or of one furrball of numbers." + }, + { + "name": "max", + "arity": "at least 1 argument", + "doc": "The largest of the numbers, or of one furrball of numbers." + }, + { + "name": "clamp", + "arity": "exactly 3 arguments", + "doc": "Keep a number between `low` and `high`." + } + ], + "constants": [ + { + "name": "PI", + "value": 3.141592653589793 + }, + { + "name": "TAU", + "value": 6.283185307179586 + }, + { + "name": "E", + "value": 2.718281828459045 + }, + { + "name": "INFINITY", + "value": "Infinity" + } + ] + }, + { + "name": "nya:rundamn", + "doc": "Random numbers, choices, and shuffles.", + "functions": [ + { + "name": "seed", + "arity": "exactly 1 argument", + "doc": "Restart the random sequence from a number, so runs repeat exactly." + }, + { + "name": "random", + "arity": "between 0 and 2 arguments", + "doc": "A random number: in [0, 1) with no arguments, [0, n) with one, or [min, max) with two." + }, + { + "name": "uniform", + "arity": "exactly 2 arguments", + "doc": "A random float in [a, b)." + }, + { + "name": "randint", + "arity": "exactly 2 arguments", + "doc": "A random whole number from a to b, including both ends." + }, + { + "name": "choice", + "arity": "exactly 1 argument", + "doc": "A random item from a furrball." + }, + { + "name": "shuffle", + "arity": "exactly 1 argument", + "doc": "Shuffle a furrball in place and return it." + } + ], + "constants": [] + }, + { + "name": "nya:scratchpad", + "doc": "Reading and writing files. Not available in the browser.", + "functions": [ + { + "name": "read_file", + "arity": "exactly 1 argument", + "doc": "The whole contents of a file as whiskers." + }, + { + "name": "write_file", + "arity": "exactly 2 arguments", + "doc": "Write whiskers to a file, replacing what was there." + }, + { + "name": "append_file", + "arity": "exactly 2 arguments", + "doc": "Add whiskers to the end of a file." + }, + { + "name": "exists", + "arity": "exactly 1 argument", + "doc": "Whether a file or directory is there." + } + ], + "constants": [] + } + ] +}; diff --git a/site/src/lib/meow.worker.ts b/site/src/lib/meow.worker.ts new file mode 100644 index 0000000..dca05d5 --- /dev/null +++ b/site/src/lib/meow.worker.ts @@ -0,0 +1,63 @@ +// Runs the interpreter off the main thread, so an endless loop never freezes the page and Stop +// can simply terminate the worker. Output is flushed on a time budget: a tight loop sends about +// 30 messages a second however fast it prints, while nap()-paced output still shows up as it +// happens. + +import type { WorkerRequest, WorkerResponse } from "./protocol"; +import { WASM_BINARY_URL, WASM_GLUE_URL, type WasmModule } from "./wasm-types"; + +const ctx = self as unknown as { + postMessage(message: WorkerResponse): void; + onmessage: ((event: MessageEvent) => void) | null; +}; + +const FLUSH_EVERY_MS = 30; +const FLUSH_EVERY_LINES = 20_000; + +let wasm: WasmModule | null = null; + +async function load(): Promise { + // The glue is served from /public, not bundled; a variable keeps the bundler from resolving it. + const glueUrl = WASM_GLUE_URL; + const mod = (await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ glueUrl)) as WasmModule; + await mod.default({ module_or_path: WASM_BINARY_URL }); + wasm = mod; + ctx.postMessage({ type: "ready", version: mod.version() }); +} + +load().catch((error: unknown) => { + ctx.postMessage({ type: "fatal", message: error instanceof Error ? error.message : String(error) }); +}); + +ctx.onmessage = (event) => { + const request = event.data; + if (request.type !== "run") return; + if (!wasm) { + ctx.postMessage({ type: "error", id: request.id, message: "The interpreter is still loading." }); + return; + } + + let batch: string[] = []; + let lastFlush = Date.now(); + const flush = () => { + if (batch.length === 0) return; + ctx.postMessage({ type: "lines", id: request.id, lines: batch }); + batch = []; + lastFlush = Date.now(); + }; + const onOutput = (line: string) => { + batch.push(line); + if (batch.length >= FLUSH_EVERY_LINES || Date.now() - lastFlush >= FLUSH_EVERY_MS) flush(); + }; + + const started = Date.now(); + try { + wasm.run(request.source, onOutput); + flush(); + ctx.postMessage({ type: "done", id: request.id, millis: Date.now() - started }); + } catch (error: unknown) { + flush(); + const message = typeof error === "string" ? error : error instanceof Error ? error.message : String(error); + ctx.postMessage({ type: "error", id: request.id, message }); + } +}; diff --git a/site/src/lib/meowscript-language.ts b/site/src/lib/meowscript-language.ts new file mode 100644 index 0000000..1755dcb --- /dev/null +++ b/site/src/lib/meowscript-language.ts @@ -0,0 +1,262 @@ +// One tokenizer feeds both the CodeMirror editor and the static code blocks in the docs, so +// they always highlight the same way. + +import { HighlightStyle, LanguageSupport, StreamLanguage, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const KEYWORDS = [ + "scratch", + "amew", + "pawction", + "purrhaps", + "meowtually", + "tail", + "pawckage", + "purrfect", + "clawful", + "mew", + "furreal", + "furrever", + "fur", + "hiss", + "continue", +] as const; + +const KEYWORD_SET = new Set(KEYWORDS); +const ATOMS = new Set(["purrfect", "clawful", "mew"]); + +const OPERATORS = ["<<", ">>", "<=", ">=", "==", "!=", "&&", "||", "=", "<", ">", "+", "-", "*", "/", "%", "!", "&", "|", "^", "~"]; + +export type TokenKind = + | "keyword" + | "atom" + | "string" + | "number" + | "comment" + | "operator" + | "punctuation" + | "function" + | "property" + | "variable" + | "invalid" + | "text"; + +export interface Token { + kind: TokenKind; + text: string; +} + +export interface TokenizerState { + inBlockComment: boolean; + inString: boolean; + afterPossessive: boolean; +} + +export function initialState(): TokenizerState { + return { inBlockComment: false, inString: false, afterPossessive: false }; +} + +const IDENT_START = /[\p{L}_]/u; +const IDENT = /[\p{L}\p{N}_]/u; +const NUMBER = /^\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][+-]?\d+)?/; + +function scanString(line: string, pos: number): [number, boolean] { + let i = pos; + while (i < line.length) { + const c = line[i]; + if (c === "\\") { + i += 2; + continue; + } + if (c === '"') return [i + 1, true]; + i++; + } + return [line.length, false]; +} + +export function nextToken(line: string, pos: number, state: TokenizerState): [TokenKind, number] { + if (state.inBlockComment) { + const close = line.indexOf("*/", pos); + if (close === -1) return ["comment", line.length]; + state.inBlockComment = false; + return ["comment", close + 2]; + } + if (state.inString) { + const [end, closed] = scanString(line, pos); + state.inString = !closed; + return ["string", end]; + } + + const c = line[pos]; + + if (/\s/.test(c)) { + let i = pos + 1; + while (i < line.length && /\s/.test(line[i])) i++; + return ["text", i]; + } + + if (c === "/" && line[pos + 1] === "/") return ["comment", line.length]; + if (c === "/" && line[pos + 1] === "*") { + const close = line.indexOf("*/", pos + 2); + if (close === -1) { + state.inBlockComment = true; + return ["comment", line.length]; + } + return ["comment", close + 2]; + } + + state.afterPossessive = false; + + if (c === '"') { + const [end, closed] = scanString(line, pos + 1); + state.inString = !closed; + return ["string", end]; + } + + if (/\d/.test(c)) { + const m = NUMBER.exec(line.slice(pos)); + return ["number", pos + (m ? m[0].length : 1)]; + } + + if (c === "'") { + const next = line[pos + 2]; + if (line[pos + 1] === "s" && (next === undefined || !IDENT.test(next))) { + state.afterPossessive = true; + return ["punctuation", pos + 2]; + } + return ["invalid", pos + 1]; + } + + if (IDENT_START.test(c)) { + let i = pos + 1; + while (i < line.length && IDENT.test(line[i])) i++; + const word = line.slice(pos, i); + // The name after `'s` is a property, never a keyword. + const wasProperty = line.slice(Math.max(0, pos - 2), pos) === "'s"; + if (wasProperty) return ["property", i]; + if (ATOMS.has(word)) return ["atom", i]; + if (KEYWORD_SET.has(word)) return ["keyword", i]; + let j = i; + while (j < line.length && line[j] === " ") j++; + return [line[j] === "(" ? "function" : "variable", i]; + } + + for (const op of OPERATORS) { + if (line.startsWith(op, pos)) return ["operator", pos + op.length]; + } + + if ("()[]{},:;".includes(c)) return ["punctuation", pos + 1]; + + return ["invalid", pos + 1]; +} + +export function tokenizeLine(line: string, state: TokenizerState): Token[] { + const tokens: Token[] = []; + let pos = 0; + while (pos < line.length) { + const [kind, end] = nextToken(line, pos, state); + const safeEnd = end > pos ? end : pos + 1; + tokens.push({ kind, text: line.slice(pos, safeEnd) }); + pos = safeEnd; + } + return tokens; +} + +const STYLE_FOR_KIND: Record = { + keyword: "keyword", + atom: "atom", + string: "string", + number: "number", + comment: "comment", + operator: "operator", + punctuation: "punctuation", + function: "variableName.function", + property: "propertyName", + variable: "variableName", + invalid: "invalid", + text: null, +}; + +const meowStream = StreamLanguage.define({ + name: "meowscript", + startState: initialState, + copyState: (s) => ({ ...s }), + token(stream, state) { + const [kind, end] = nextToken(stream.string, stream.pos, state); + stream.pos = end > stream.pos ? end : stream.pos + 1; + return STYLE_FOR_KIND[kind]; + }, + languageData: { + commentTokens: { line: "//", block: { open: "/*", close: "*/" } }, + closeBrackets: { brackets: ["(", "[", "{", '"'] }, + }, +}); + +export const meowHighlight = HighlightStyle.define([ + { tag: t.keyword, color: "var(--color-accent)" }, + { tag: t.atom, color: "var(--color-catnip)" }, + { tag: t.number, color: "var(--color-catnip)" }, + { tag: t.string, color: "var(--color-paw)" }, + { tag: t.comment, color: "var(--color-muted)", fontStyle: "italic" }, + { tag: t.operator, color: "var(--color-text-soft)" }, + { tag: t.punctuation, color: "var(--color-text-soft)" }, + { tag: t.function(t.variableName), color: "var(--color-text)" }, + { tag: t.propertyName, color: "var(--color-text)" }, + { tag: t.variableName, color: "var(--color-text)" }, + { tag: t.invalid, color: "var(--color-danger)", textDecoration: "underline wavy" }, +]); + +export const meowTheme = EditorView.theme( + { + "&": { + backgroundColor: "var(--color-surface)", + color: "var(--color-text)", + fontSize: "14px", + height: "100%", + }, + ".cm-scroller": { + fontFamily: "var(--font-mono)", + lineHeight: "1.6", + }, + ".cm-content": { + padding: "12px 0", + caretColor: "var(--color-accent)", + }, + ".cm-line": { + padding: "0 16px 0 8px", + }, + ".cm-cursor, .cm-dropCursor": { + borderLeftColor: "var(--color-accent)", + borderLeftWidth: "2px", + }, + "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { + backgroundColor: "color-mix(in oklab, var(--color-accent) 28%, transparent)", + }, + ".cm-activeLine": { + backgroundColor: "color-mix(in oklab, var(--color-text) 4%, transparent)", + }, + ".cm-gutters": { + backgroundColor: "var(--color-surface)", + color: "var(--color-muted)", + border: "none", + paddingLeft: "8px", + }, + ".cm-activeLineGutter": { + backgroundColor: "transparent", + color: "var(--color-text-soft)", + }, + ".cm-matchingBracket": { + backgroundColor: "color-mix(in oklab, var(--color-accent) 22%, transparent)", + outline: "none", + }, + "&.cm-focused": { + outline: "none", + }, + }, + { dark: true }, +); + +export function meowscript(): LanguageSupport { + return new LanguageSupport(meowStream, [syntaxHighlighting(meowHighlight)]); +} diff --git a/site/src/lib/protocol.ts b/site/src/lib/protocol.ts new file mode 100644 index 0000000..453c744 --- /dev/null +++ b/site/src/lib/protocol.ts @@ -0,0 +1,8 @@ +export type WorkerRequest = { type: "run"; id: number; source: string }; + +export type WorkerResponse = + | { type: "ready"; version: string } + | { type: "fatal"; message: string } + | { type: "lines"; id: number; lines: string[] } + | { type: "done"; id: number; millis: number } + | { type: "error"; id: number; message: string }; diff --git a/site/src/lib/try-it.ts b/site/src/lib/try-it.ts new file mode 100644 index 0000000..abe3456 --- /dev/null +++ b/site/src/lib/try-it.ts @@ -0,0 +1,21 @@ +// sessionStorage rather than a URL parameter, so a refresh doesn't resurrect the snippet. + +const KEY = "meowscript.try-it"; + +export function handOverCode(code: string): void { + try { + window.sessionStorage.setItem(KEY, code); + } catch { + // Storage unavailable (private mode, say). The playground shows its default. + } +} + +export function takeHandedCode(): string | null { + try { + const code = window.sessionStorage.getItem(KEY); + if (code !== null) window.sessionStorage.removeItem(KEY); + return code; + } catch { + return null; + } +} diff --git a/site/src/lib/use-meowscript.ts b/site/src/lib/use-meowscript.ts new file mode 100644 index 0000000..0025fe8 --- /dev/null +++ b/site/src/lib/use-meowscript.ts @@ -0,0 +1,155 @@ +"use client"; + +import { useCallback, useEffect, useReducer, useRef } from "react"; +import type { WorkerRequest, WorkerResponse } from "./protocol"; + +export type OutputLine = { kind: "out" | "error" | "note"; text: string }; + +export type Status = "loading" | "ready" | "running" | "failed"; + +export interface MeowState { + status: Status; + version: string | null; + lines: OutputLine[]; + lastRunMillis: number | null; + fatal: string | null; +} + +const MAX_LINES = 3000; + +type Action = + | { type: "ready"; version: string } + | { type: "fatal"; message: string } + | { type: "start" } + | { type: "lines"; lines: string[] } + | { type: "done"; millis: number } + | { type: "error"; message: string } + | { type: "stopped" } + | { type: "clear" }; + +const initial: MeowState = { status: "loading", version: null, lines: [], lastRunMillis: null, fatal: null }; + +function append(lines: OutputLine[], extra: OutputLine[]): OutputLine[] { + const next = lines.concat(extra); + if (next.length <= MAX_LINES) return next; + const kept = next.slice(next.length - MAX_LINES); + return [{ kind: "note", text: `… earlier lines trimmed; only the last ${MAX_LINES} are kept` }, ...kept]; +} + +function reducer(state: MeowState, action: Action): MeowState { + switch (action.type) { + case "ready": + return { ...state, status: "ready", version: action.version, fatal: null }; + case "fatal": + return { ...state, status: "failed", fatal: action.message }; + case "start": + return { ...state, status: "running", lines: [], lastRunMillis: null }; + case "lines": + return { ...state, lines: append(state.lines, action.lines.map((text) => ({ kind: "out", text }))) }; + case "done": + return { ...state, status: "ready", lastRunMillis: action.millis }; + case "error": + return { ...state, status: "ready", lines: append(state.lines, [{ kind: "error", text: action.message }]) }; + case "stopped": + return { ...state, status: "loading", lines: append(state.lines, [{ kind: "note", text: "Stopped." }]) }; + case "clear": + return { ...state, lines: [], lastRunMillis: null }; + } +} + +export function useMeowScript() { + const [state, dispatch] = useReducer(reducer, initial); + const workerRef = useRef(null); + const runIdRef = useRef(0); + // Incoming lines are gathered here and handed to React once per frame, so a fast program + // can't starve the page. + const pendingRef = useRef([]); + const frameRef = useRef(null); + + const flushPending = useCallback(() => { + frameRef.current = null; + if (pendingRef.current.length === 0) return; + const lines = pendingRef.current; + pendingRef.current = []; + dispatch({ type: "lines", lines: lines.length > MAX_LINES ? lines.slice(-MAX_LINES) : lines }); + }, []); + + const discardPending = useCallback(() => { + pendingRef.current = []; + if (frameRef.current !== null) { + cancelAnimationFrame(frameRef.current); + frameRef.current = null; + } + }, []); + + const spawn = useCallback(() => { + workerRef.current?.terminate(); + const worker = new Worker(new URL("./meow.worker.ts", import.meta.url), { type: "module" }); + worker.onmessage = (event: MessageEvent) => { + const msg = event.data; + switch (msg.type) { + case "ready": + dispatch({ type: "ready", version: msg.version }); + break; + case "fatal": + dispatch({ type: "fatal", message: msg.message }); + break; + case "lines": + if (msg.id !== runIdRef.current) break; + pendingRef.current = pendingRef.current.concat(msg.lines); + if (pendingRef.current.length > MAX_LINES) pendingRef.current = pendingRef.current.slice(-MAX_LINES); + if (frameRef.current === null) frameRef.current = requestAnimationFrame(flushPending); + break; + case "done": + if (msg.id !== runIdRef.current) break; + flushPending(); + dispatch({ type: "done", millis: msg.millis }); + break; + case "error": + if (msg.id !== runIdRef.current) break; + flushPending(); + dispatch({ type: "error", message: msg.message }); + break; + } + }; + worker.onerror = (event) => { + dispatch({ type: "fatal", message: event.message || "The interpreter worker crashed." }); + }; + workerRef.current = worker; + }, [flushPending]); + + useEffect(() => { + spawn(); + return () => { + discardPending(); + workerRef.current?.terminate(); + }; + }, [spawn, discardPending]); + + const run = useCallback( + (source: string) => { + const worker = workerRef.current; + if (!worker || state.status !== "ready") return; + runIdRef.current += 1; + discardPending(); + dispatch({ type: "start" }); + const request: WorkerRequest = { type: "run", id: runIdRef.current, source }; + worker.postMessage(request); + }, + [state.status, discardPending], + ); + + const stop = useCallback(() => { + runIdRef.current += 1; + flushPending(); + dispatch({ type: "stopped" }); + spawn(); + }, [spawn, flushPending]); + + const clear = useCallback(() => { + discardPending(); + dispatch({ type: "clear" }); + }, [discardPending]); + + return { ...state, run, stop, clear }; +} diff --git a/site/src/lib/wasm-types.ts b/site/src/lib/wasm-types.ts new file mode 100644 index 0000000..a184e50 --- /dev/null +++ b/site/src/lib/wasm-types.ts @@ -0,0 +1,18 @@ +// Shape of the wasm-pack output in public/wasm, which the worker loads by URL at runtime. + +export interface WasmInitOutput { + memory: WebAssembly.Memory; +} + +export interface WasmModule { + /** Throws the rendered error text if the program fails. */ + run(source: string, onOutput: (line: string) => void): void; + version(): string; + keywords(): string[]; + default(input?: { + module_or_path?: string | URL | Request | Response | BufferSource | WebAssembly.Module; + }): Promise; +} + +export const WASM_GLUE_URL = "/wasm/meowscript.js"; +export const WASM_BINARY_URL = "/wasm/meowscript_bg.wasm"; diff --git a/site/styles/global.css b/site/styles/global.css deleted file mode 100644 index d8cb4ef..0000000 --- a/site/styles/global.css +++ /dev/null @@ -1,96 +0,0 @@ -/* ./styles/globals.css */ -@tailwind base; -@tailwind components; -@tailwind utilities; -html, -body, -body > div:first-child, -div#__next, -div#__next > div { - height: 100%; - background-color: #1E2130; - scroll-behavior: smooth; -} - -@font-face { - font-family: 'Fira Code'; - src: url('/FiraCode-Light.woff2') format('woff2'), - url("/FiraCode-Light.woff") format("woff"); - font-weight: 300; - font-style: normal; -} - -@font-face { - font-family: 'Fira Code'; - src: url('/FiraCode-Regular.woff2') format('woff2'), - url("/FiraCode-Regular.woff") format("woff"); - font-weight: 400; - font-style: normal; -} - -.docs { - @apply text-gray-50; -} - -.docs h1 { - @apply text-2xl pt-8 font-bold underline; -} - -.docs h2 { - @apply text-lg pt-16 font-bold underline; -} - -.docs p { - @apply pt-8 text-gray-300; -} - -.docs pre { - @apply mt-8 bg-[#282C42] p-4 rounded-md overflow-auto; -} - -.docs p code { - @apply text-gray-50 bg-[#1A1C26]; -} - -.docs a { - @apply text-blue-400 underline font-bold; -} - -.editor { - counter-reset: line; - overflow-x: scroll !important; - overflow-y: scroll !important; -} - -#codeArea { - overflow-wrap: normal !important; - word-break: keep-all !important; - outline: none; - padding-top: 1rem; - padding-left: 60px !important; - z-index: 999999999; - white-space: nowrap; - overflow-x: hidden !important; - overflow-y: scroll !important; -} - -.editor pre { - padding-left: 60px !important; -} - -.editor .editorLineNumber { - position: absolute; - left: 0px; - color: #8a8a8a; - text-align: right; - width: 40px; -} - -.tooltip { - @apply invisible absolute; - transform: translateY(-100%); -} - -.has-tooltip:hover .tooltip { - @apply visible z-50; -} diff --git a/site/tailwind.config.js b/site/tailwind.config.js deleted file mode 100644 index c603b22..0000000 --- a/site/tailwind.config.js +++ /dev/null @@ -1,25 +0,0 @@ -const colors = require('tailwindcss/colors') - -module.exports = { - purge: ['**/*.tsx'], - mode: 'jit', - darkMode: false, // or 'media' or 'class' - theme: { - extend: { - colors: { - orange: colors.orange, - coolGray: colors.coolGray, - blueGray: colors.blueGray, - red: colors.red, - bg: '#1E2130' - } - }, - fontFamily: { - sans: ['Fira code', 'Fira Mono', 'monospace'] - } - }, - variants: { - extend: {} - }, - plugins: [require('@tailwindcss/aspect-ratio')] -} diff --git a/site/tsconfig.json b/site/tsconfig.json index 99710e8..7d553a8 100644 --- a/site/tsconfig.json +++ b/site/tsconfig.json @@ -1,20 +1,34 @@ { "compilerOptions": { - "target": "es5", + "target": "ES2022", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, - "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", - "incremental": true + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], "exclude": ["node_modules"] } diff --git a/site/type/types.ts b/site/type/types.ts deleted file mode 100644 index 8a5bfc0..0000000 --- a/site/type/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type WasmRunFn = (strPtr: number) => number -export type WasmAlloc = (size: number) => number -export type WasmDealloc = (ptr: number, len: number) => number diff --git a/src/ast/mod.rs b/src/ast/mod.rs deleted file mode 100644 index 0df786e..0000000 --- a/src/ast/mod.rs +++ /dev/null @@ -1,157 +0,0 @@ -pub mod token; -use std::fmt::{self, Display, Formatter}; - -#[derive(PartialEq, Clone, Debug)] -pub struct Ident(pub String); - -#[derive(PartialEq, Clone, Debug)] -pub enum Prefix { - Plus, - Minus, - Exclamation -} - -#[derive(PartialEq, Clone, Debug)] -pub enum Infix { - In, - Plus, - Minus, - Times, - Divide, - Modulo, - Equals, - NotEquals, - LessThan, - GreaterThan, - LessThanEqual, - GreaterThanEqual, - LeftShift, - RightShift, - AND, - OR, - XOR, -} - -#[derive(PartialEq, Clone, Debug)] -pub enum Literal { - Number(f64), - String(String), - Boolean(bool), - Array(Vec), - Object(Vec<(Expr, Expr)>) -} - -#[derive(PartialEq, Clone, Debug)] -pub enum Statement { - Set(Ident, Expr), - Return(Expr), - Expression(Expr), - Include(String), - Anew(Ident, Expr), - Break, - Continue -} - -#[derive(PartialEq, PartialOrd, Debug, Clone)] -pub enum Precedence { - Lowest, - Equals, - LessGreater, - Sum, - Product, - Prefix, - Call, - Index, - In, - LeftShift, - RightShift, - AND, - OR, - XOR -} - -pub type BlockStatement = Vec; - -#[derive(PartialEq, Clone, Debug)] -pub enum Expr { - Literal(Literal), - Ident(Ident), - Prefix(Prefix, Box), - Infix(Infix, Box, Box), - If { - cond: Box, - then: Box, - else_: Option - }, - - Fun { - params: Vec, - body: BlockStatement - }, - - Call { - function: Box, - args: Vec - }, - - Index { - array: Box, - index: Box - }, - - Typeof { - expr: Box - }, - - Loop { - body: BlockStatement - } - -} - -#[derive(PartialEq, Clone, Debug)] -pub struct Program { - pub(crate) statements: Vec -} - -// Implement the Display trait for all the types we have - -impl Display for Prefix { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match *self { - Prefix::Plus => write!(f, "+"), - Prefix::Minus => write!(f, "-"), - Prefix::Exclamation => write!(f, "!"), - } - } -} - -impl Display for Infix { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match *self { - Infix::In => write!(f, "~"), - Infix::Plus => write!(f, "+"), - Infix::Minus => write!(f, "-"), - Infix::Times => write!(f, "*"), - Infix::Divide => write!(f, "/"), - Infix::Modulo => write!(f, "%"), - Infix::Equals => write!(f, "=="), - Infix::NotEquals => write!(f, "!="), - Infix::LessThan => write!(f, "<"), - Infix::GreaterThan => write!(f, ">"), - Infix::LessThanEqual => write!(f, "<="), - Infix::GreaterThanEqual => write!(f, ">="), - Infix::LeftShift => write!(f, "<<"), - Infix::RightShift => write!(f, ">>"), - Infix::AND => write!(f, "&"), - Infix::OR => write!(f, "|"), - Infix::XOR => write!(f, "^") - } - } -} - -impl Display for Expr { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} \ No newline at end of file diff --git a/src/ast/token.rs b/src/ast/token.rs deleted file mode 100644 index 41bd627..0000000 --- a/src/ast/token.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -#[derive(Debug, Clone, PartialEq)] -pub enum Token { - Eof, - Illegal, - Comment, - - // Literals - Ident(String), - Number(f64), - String(String), - Boolean(bool), - - // Operators - Assign, - Plus, - Minus, - Bang, - Asterisk, - Slash, - Percent, - Anew, - In, - - // Bitwise operators - AND, - OR, - XOR, - LeftShift, - RightShift, - - // Comparison - Less, - Greater, - LessEqual, - GreaterEqual, - Equals, - NotEquals, - - // Delimiters - Comma, - Colon, - Semicolon, - LeftParen, - RightParen, - LeftBrace, - RightBrace, - LeftBracket, - RightBracket, - SingleQuoteS, - - // Keywords - Set, - Func, - If, - Else, - Return, - Include, - Typeof, - Loop, - Break, - Continue - -} - -impl Display for Token { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - diff --git a/src/evaluation/globals.rs b/src/evaluation/globals.rs deleted file mode 100644 index c6e1877..0000000 --- a/src/evaluation/globals.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::object::*; -use std::collections::HashMap; - -/// Adds the built-in functions to the global environment. -/// This is called once at the start of the program. -/// The global environment is a HashMap of names to objects. -pub fn new_globals() -> HashMap { - let mut globals = HashMap::new(); - globals.insert(String::from("meow"), Object::Inbuilt(meow)); - globals.insert(String::from("log"), Object::Inbuilt(log)); - globals -} - -/// The built-in function `log`. -/// It takes an unlimited number of arguments, -/// and logs them to the console. -/// It returns `null`. -fn log(args: Vec) -> Object { - if args.is_empty() { - return Object::Error(String::from("Wrong number of arguments")); - } else { - for arg in args { - print!("{} ", arg); - } - println!(); - } - Object::Null -} - -fn meow(args: Vec) -> Object { - if args.is_empty() { - return Object::Error(String::from("Wrong number of arguments")); - } else { - print!("Meow!"); - for arg in args { - print!(" {}", arg); - } - println!(); - } - Object::Null -} \ No newline at end of file diff --git a/src/evaluation/library.rs b/src/evaluation/library.rs deleted file mode 100644 index ac770cc..0000000 --- a/src/evaluation/library.rs +++ /dev/null @@ -1,63 +0,0 @@ -use super::{store::Store, object::*, Eval}; -use crate::{lexer::Lexer, parser::Parser, std_library::*}; -use std::{cell::RefCell, collections::HashMap, fs, rc::Rc}; -/// Function to load an external file or a standard library onto the environment.\ -/// The file is loaded as a string, and the string is parsed into an AST. -/// The AST is then evaluated. -/// The result is then added to the environment. -/// # Arguments -/// * `lib` - The name of the library to load. -/// # Returns -/// `HashMap` - The environment with the library loaded. -/// -pub fn load_meow(lib: String) -> Option> { - - // Checks if the library is a standard library. - if lib.starts_with("nya:") { - // Loads the standard library. - // The standard library is a HashMap of names to objects. - let libs = get_std_lib(lib).unwrap(); - let mut eval = Eval::new(Rc::new(RefCell::new( - Store::from(libs.globals.clone()) - ))); - - match &libs.raw { - Some(s) => { - let mut parser = Parser::new(Lexer::new(s.to_string())); - let program = parser.parse_program(); - eval.eval(program); - let store = (&*eval.store.borrow()).to_owned().store; - let mut final_env = HashMap::new(); - for (k, v) in libs.globals.iter() { - final_env.insert(k.to_string(), v.to_owned()); - } - for (k, v) in store.iter() { - final_env.insert(k.clone(), v.clone()); - } - return Some(final_env) - }, - None => return Some(libs.globals), - } - } - let filename =format!("./{}.meow", lib); - // File is read as a string. - let file = fs::read_to_string(filename).expect("Lib not found."); - let mut parser = Parser::new(Lexer::new(file)); - let program = parser.parse_program(); - if !parser.errors.is_empty() { - for e in parser.errors.iter() { - println!("\t{}", e); - } - return None; - }; - let mut eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - // Evaluates the program. - eval.eval(program); - let store = (&*eval.store.borrow()).to_owned().store; - let mut final_env = HashMap::new(); - // Returns the environment with the library loaded. - for (k, v) in store.iter() { - final_env.insert(k.clone(), v.clone()); - } - Some(final_env) -} \ No newline at end of file diff --git a/src/evaluation/mod.rs b/src/evaluation/mod.rs deleted file mode 100644 index ac0c454..0000000 --- a/src/evaluation/mod.rs +++ /dev/null @@ -1,657 +0,0 @@ -pub mod object; -pub mod store; -pub mod library; -pub mod globals; - -use crate::ast::*; -use globals::new_globals; -use store::Store; -use object::Object; -use std::{cell::RefCell, collections::HashMap, rc::Rc}; - -use library::load_meow; - -/// ## Eval -/// The Eval struct is used to evaluate an AST. -/// It contains a reference to a Store, which is used to store variables. -/// The Eval struct also contains a reference to the global environment. -/// The global environment is a HashMap of names to objects. -/// The Eval struct also contains a reference to the current environment. -pub struct Eval { - /// The current environment. - pub store: Rc>, -} - -impl Eval { - /// ## new - /// Creates a new Eval struct. - /// # Arguments - /// * `store` - The store to use. - /// # Returns - /// `Eval` - The new Eval struct. - pub fn new(store: Rc>) -> Self { - Eval { store } - } - - /// ## is_truthy - /// Checks if an object is truthy. - /// # Arguments - /// * `obj` - The object to check. - /// # Returns - /// `bool` - Whether the object is truthy. - /// # Examples - /// ``` - /// use crate::eval::Eval; - /// let eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let obj = Object::Boolean(true); - /// assert_eq!(true, is_truthy(obj)); - /// ``` - fn is_truthy(&mut self, object: Object) -> bool { - !matches!(object, Object::Null | Object::Bool(false)) - } - - /// ##is_error - /// Checks if an object is an error. - /// # Arguments - /// * `object` - The object to check. - /// # Returns - /// `bool` - Whether the object is an error. - /// # Examples - /// ``` - /// use crate::eval::Eval; - /// let eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let obj = Object::Error(String::from("Error")); - /// assert_eq!(true, is_error(obj)); - /// ``` - fn is_error(&mut self, object: &Object) -> bool { - matches!(object, Object::Error(_)) - } - - /// ## eval - /// Evaluates the program. - /// It loops over all the statements in the program, - /// and evaluates them. - /// If an error occurs, it is returned. - /// # Arguments - /// * `program` - The program to evaluate. - /// # Returns - /// `Object` - The result of the evaluation. - /// # Examples - /// ``` - /// use crate::eval::Eval; - /// let eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let program = Program { - /// statements: vec![ - /// Statement::Expression(Expression::Identifier(String::from("x"))), - /// Statement::Expression(Expression::Identifier(String::from("y"))), - /// Statement::Expression(Expression::Identifier(String::from("z"))), - /// ], - /// }; - /// let mut eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let result = eval.eval(program); - /// assert_eq!(Object::Null, result); - /// ``` - pub fn eval(&mut self, program: Program) -> Option { - let mut result = None; - - for statement in program.statements { - match self.eval_statement(statement) { - Some(Object::Error(val)) => return Some(Object::Error(val)), - Some(Object::Return(val)) => return Some(*val), - e => result = e, - } - } - - result - } - - /// ## eval_statement - /// Evaluates a statement. - /// It matches the statement type, - /// and calls the appropriate function to evaluate it. - /// # Arguments - /// * `statement` - The statement to evaluate. - /// # Returns - /// `Option` - The result of the evaluation. - /// # Examples - /// ``` - /// use crate::eval::Eval; - /// let eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let statement = Statement::Expression(Expression::Identifier(String::from("x"))); - /// let mut eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let result = eval.eval_statement(statement); - /// assert_eq!(Some(Object::Null), result); - /// ``` - fn eval_statement(&mut self, statement: Statement) -> Option { - match statement { - Statement::Expression(e) => self.eval_expr(e), - Statement::Return(e) => { - let val = match self.eval_expr(e) { - Some(v) => v, - None => return None, - }; - - Some(Object::Return(Box::new(val))) - } - Statement::Set(i, v) => { - let val = match self.eval_expr(v) { - Some(value) => value, - None => return None, - }; - if self.is_error(&val) { - Some(val) - } else { - let Ident(name) = i; - self.store.borrow_mut().set(name, val); - None - } - } - Statement::Anew(i, v) => { - let Ident(name) = i; - let val = match self.eval_expr(v) { - Some(value) => value, - None => return None, - }; - if self.is_error(&val) { - Some(val) - } else { - let mut store = self.store.borrow_mut(); - match store.get(&name) { - Some(_) => { - store.anew(name, val); - None - } - None => Some(Object::Error(format!("Meow-sterious! The identifier '{}' seems to be playing a game of hide-and-seek", name))), - } - } - } - Statement::Include(i) => { - let lib = i; - self.extend_global_store(lib) - }, - Statement::Break => Some(Object::Break), - Statement::Continue => Some(Object::Continue), - } - } - - /// ## eval_block_statement - /// Evaluates a block statement. - /// It loops over all the statements in the block, - /// and evaluates them. - /// If an error occurs, it is returned. - /// # Arguments - /// * `statements` - The block to evaluate. - /// # Returns - /// `Option` - The result of the evaluation. - /// # Examples - /// ``` - /// use crate::eval::Eval; - /// let eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let block = Block { - /// statements: vec![ - /// Statement::Expression(Expression::Identifier(String::from("x"))), - /// Statement::Expression(Expression::Identifier(String::from("y"))), - /// Statement::Expression(Expression::Identifier(String::from("z"))), - /// ], - /// }; - /// let mut eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let result = eval.eval_block_statement(block); - /// assert_eq!(Some(Object::Null), result); - /// ``` - fn eval_block_statement(&mut self, statements: BlockStatement) -> Option { - let mut result = None; - - for statement in statements { - match self.eval_statement(statement) { - Some(Object::Return(e)) => return Some(Object::Return(e)), - Some(Object::Error(e)) => return Some(Object::Error(e)), - Some(Object::Break) => return Some(Object::Break), - Some(Object::Continue) => return Some(Object::Continue), - e => result = e, - } - } - - result - } - - /// ## eval_expr - /// Evaluates an expression. - /// It matches the expression type, - /// and calls the appropriate function to evaluate it. - /// # Arguments - /// * `expr` - The expression to evaluate. - /// # Returns - /// `Option` - The result of the evaluation. - /// # Examples - /// ``` - /// use crate::eval::Eval; - /// let eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let expr = Expression::Identifier(String::from("x")); - /// let mut eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let result = eval.eval_expr(expr); - /// assert_eq!(Some(Object::Null), result); - /// ``` - fn eval_expr(&mut self, expr: Expr) -> Option { - match expr { - Expr::Ident(ident) => Some(self.eval_ident(ident)), - Expr::Literal(lit) => Some(self.eval_literal(lit)), - Expr::Prefix(prefix, right) => self - .eval_expr(*right) - .map(|expr| self.eval_prefix_expr(prefix, expr)), - Expr::Infix(infix, left, right) => { - let left_expr = self.eval_expr(*left); - let right_expr = self.eval_expr(*right); - match left_expr.clone() { - Some(l) => { - if self.is_error(&l) { - return left_expr; - } - if self.is_error(&right_expr.clone().unwrap()) { - return right_expr; - } - right_expr.map(|r| self.eval_infix_expr(infix, left_expr.unwrap(), r)) - } - _ => None, - } - } - Expr::If { - cond: condition, - then: consequence, - else_: alternative, - } => { - let cond_expr = match self.eval_expr(*condition) { - Some(e) => e, - None => return None, - }; - - if self.is_truthy(cond_expr) { - self.eval_block_statement(*consequence) - } else if let Some(a) = alternative { - self.eval_block_statement(a) - } else { - None - } - } - Expr::Fun { params, body } => Some(Object::Fn(params, body, self.store.clone())), - Expr::Call { function, args } => Some(self.eval_call_expr(*function, args)), - Expr::Index { array, index } => { - let obj = self.eval_expr(*array); - let i = self.eval_expr(*index); - if let Some(Object::Object(obj)) = obj { - let idx = match i { - Some(Object::Number(i)) => Object::Number(i), - Some(Object::String(i)) => Object::String(i), - Some(Object::Bool(i)) => Object::Bool(i), - _ => return None, - }; - Some(self.eval_index_expr(Object::Object(obj.clone()), idx)) - } else if let Some(Object::Array(arr)) = obj { - let idx = match i { - Some(Object::Number(i)) => Object::Number(i), - _ => return None, - }; - Some(self.eval_index_expr(Object::Array(arr.clone()), idx)) - } else { - None - } - } - Expr::Typeof { expr } => Some(self.eval_typeof_expr(*expr)), - - Expr::Loop { body } => { - let mut _result = None; - loop { - match self.eval_block_statement((*body).to_vec()) { - Some(Object::Return(e)) => return Some(Object::Return(e)), - Some(Object::Error(e)) => return Some(Object::Error(e)), - Some(Object::Break) => { - break Some(Object::Null); - }, - Some(Object::Continue) => continue, - e => _result = e, - } - } - } - } - } - - fn eval_typeof_expr(&mut self, expr: Expr) -> Object { - let obj = self.eval_expr(expr); - match &obj.unwrap() { - Object::Null => Object::String(String::from("null")), - Object::Bool(_) => Object::String(String::from("boolean")), - Object::Number(_) => Object::String(String::from("number")), - Object::String(_) => Object::String(String::from("string")), - Object::Array(_) => Object::String(String::from("array")), - Object::Object(_) => Object::String(String::from("object")), - _ => Object::String(String::from("undefined")), - } - - } - - /// ## eval_prefix_expr - /// Evaluates a prefix expression. - /// It matches the prefix operator, - /// and calls the appropriate function to evaluate it. - /// # Arguments - /// * `prefix` - The prefix operator. - /// * `expr` - The expression to evaluate.s - /// # Returns - /// `Option` - The result of the evaluation. - fn eval_prefix_expr(&mut self, prefix: Prefix, expr: Object) -> Object { - if self.is_error(&expr) { - return expr; - } - match prefix { - Prefix::Exclamation => self.eval_not_prefix_expr(expr), - Prefix::Minus => self.eval_minus_prefix_expr(expr), - Prefix::Plus => self.eval_plus_prefix_expr(expr), - } - } - - /// ## eval_not_prefix_expr - /// Evaluates a `NOT` prefix expression. - /// # Arguments - /// * `expr` - The expression to evaluate. - /// # Returns - /// `Object` - The result of the evaluation. - fn eval_not_prefix_expr(&mut self, expr: Object) -> Object { - match expr { - Object::Bool(true) => Object::Bool(false), - Object::Bool(false) => Object::Bool(true), - Object::Null => Object::Bool(true), - _ => Object::Bool(false), - } - } - - /// ## eval_minus_prefix_expr - /// Evaluates a `MINUS` prefix expression. - /// # Arguments - /// * `expr` - The expression to evaluate. - /// # Returns - /// `Object` - The result of the evaluation. - /// # Examples - /// ``` - /// use crate::eval::Eval; - /// let eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let expr = Expression::Literal(Literal::Number(1.0)); - /// let mut eval = Eval::new(Rc::new(RefCell::new(Store::new()))); - /// let result = eval.eval_minus_prefix_expr(expr); - /// assert_eq!(Some(Object::Number(-1.0)), result); - /// ``` - fn eval_minus_prefix_expr(&mut self, expr: Object) -> Object { - match expr { - Object::Number(i) => Object::Number(-i), - _ => Object::Error(format!("unknown operator: -{}", expr)), - } - } - - /// ## eval_plus_prefix_expr - /// Evaluates a `PLUS` prefix expression. - /// # Arguments - /// * `expr` - The expression to evaluate. - /// # Returns - /// `Object` - The result of the evaluation. - /// # Errors - /// `Error` - If the expression is not a number. - fn eval_plus_prefix_expr(&mut self, expr: Object) -> Object { - match expr { - Object::Number(i) => Object::Number(i), - _ => Object::Error(format!("unknown operator: {}", expr)), - } - } - - /// ## eval_infix_expr - /// Evaluates an infix expression. - /// It matches the infix operator, - /// and calls the appropriate function to evaluate it. - /// # Arguments - /// * `infix` - The infix operator. - /// * `left` - The left expression. - /// * `right` - The right expression. - /// # Returns - /// `Option` - The result of the evaluation. - /// # Errors - /// `Error` - If the expression is not a number. - fn eval_infix_expr(&mut self, infix: Infix, left: Object, right: Object) -> Object { - match left { - Object::Number(left_expr) => { - if let Object::Number(right_expr) = right { - self.eval_int_infix_expr(infix, left_expr, right_expr) - } else if let Object::Object(right_expr) = right { - self.eval_object_infix_expr(infix, Object::Number(left_expr), Object::Object(right_expr)) - } else { - Object::Error(format!("type mismatch: {} {} {}", left, infix, right)) - } - } - Object::String(left_expr) => { - if let Object::String(right_expr) = right { - self.eval_string_infix_expr(infix, left_expr, right_expr) - } else if let Object::Object(right_expr) = right { - self.eval_object_infix_expr(infix, Object::String(left_expr), Object::Object(right_expr)) - } else { - Object::Error(format!("type mismatch: {} {} {}", left_expr, infix, right)) - } - } - _ => self.eval_object_infix_expr(infix, left, right) - } - } - - fn eval_string_infix_expr(&mut self, infix: Infix, left: String, right: String) -> Object { - match infix { - Infix::Plus => Object::String(format!("{}{}", left, right)), - _ => Object::Error(format!("unknown operator: {} {} {}", left, infix, right)), - } - } - - fn eval_object_infix_expr(&mut self, infix: Infix, left: Object, right: Object) -> Object { - match infix { - Infix::In => { - if let Object::Object(right) = right { - Object::Bool(right.contains_key(&left)) - } else if let Object::Array(right) = right { - Object::Bool(right.contains(&left)) - } else { - Object::Error(format!("unknown operator: {} {} {}", left, infix, right)) - } - } - _ => Object::Error(format!("unknown operator: {} {} {}", left, infix, right)), - } - } - - fn eval_int_infix_expr(&mut self, infix: Infix, left: f64, right: f64) -> Object { - match infix { - Infix::Plus => Object::Number(left + right), - Infix::Minus => Object::Number(left - right), - Infix::Times => Object::Number(left * right), - Infix::Divide => Object::Number(left / right), - Infix::Modulo => Object::Number(left % right), - Infix::LessThan => Object::Bool(left < right), - Infix::LessThanEqual => Object::Bool(left <= right), - Infix::GreaterThan => Object::Bool(left > right), - Infix::GreaterThanEqual => Object::Bool(left >= right), - Infix::Equals => Object::Bool(left == right), - Infix::NotEquals => Object::Bool(left != right), - Infix::In => Object::Bool(left.to_string().contains(&right.to_string())), - Infix::LeftShift => Object::Number(((left as i64) << (right as i64)) as f64), - Infix::RightShift => Object::Number(((left as i64) >> (right as i64)) as f64), - Infix::AND => Object::Number((left as i64 & right as i64) as f64), - Infix::OR => Object::Number((left as i64 | right as i64) as f64), - Infix::XOR => Object::Number((left as i64 ^ right as i64) as f64) - } - } - - fn eval_call_expr(&mut self, function: Expr, args: Vec) -> Object { - let args = args - .iter() - .map(|a| self.eval_expr(a.clone()).unwrap_or(Object::Null)) - .collect::>(); - - self.apply_function(function, args) - } - - fn eval_index_expr(&mut self, left: Object, index: Object) -> Object { - match left { - Object::Array(ref arr) => { - if let Object::Number(i) = index { - self.eval_array_index_expr(arr.clone(), i) - } else { - Object::Error(format!("index operator not supported: {}", left)) - } - } - Object::Object(ref hash) => match index { - Object::Number(_) | Object::Bool(_) | Object::String(_) => match hash.get(&index) { - Some(o) => o.clone(), - None => { - Object::Null - }, - }, - Object::Error(_) => index, - _ => Object::Error(format!("unsable as hash key: {}", index)), - }, - _ => Object::Error(format!("unknown operator: {} {}", left, index)), - } - } - - fn eval_array_index_expr(&mut self, array: Vec, index: f64) -> Object { - let max = array.len() as f64; - if index > max { - return Object::Null; - } - - if index < 0.0 { - match array.get((array.len() as f64 + index) as usize) { - Some(o) => return o.clone(), - None => return Object::Null, - } - } - match array.get(index as usize) { - Some(o) => o.clone(), - None => Object::Null, - } - } - - fn apply_function(&mut self, function: Expr, args: Vec) -> Object { - let (params, body, store) = match self.eval_expr(function) { - Some(Object::Fn(params, body, store)) => (params, body, store), - Some(Object::Inbuilt(func)) => return func(args), - Some(o) => return Object::Error(format!("🙀 Cat-tastrophe alert! The function '{}' is nowhere to be found, like a clever cat hiding in plain sight", o)), - None => return Object::Null, - }; - - if params.len() != args.len() { - return Object::Error(format!( - "expected arguments: {}\ngiven arguments: {}", - params.len(), - args.len() - )); - }; - - let current_store = Rc::clone(&self.store); - let extended_store = self.extended_function_store(params, store, args); - self.store = Rc::new(RefCell::new(extended_store)); - let evaluated = self.eval_block_statement(body); - self.store = current_store; - self.unwrap_return_value(evaluated) - } - - fn extended_function_store( - &mut self, - params: Vec, - store: Rc>, - args: Vec, - ) -> Store { - let mut scope_store = Store::new_enclosed(store); - - for (ident, arg) in params.iter().zip(args.iter()) { - let Ident(name) = ident.clone(); - scope_store.set(name, arg.to_owned()); - } - - scope_store - } - - fn extend_global_store(&mut self, lib: String) -> Option { - let lib_store = match load_meow(lib.clone()) { - Some(e) => e, - None => return Some(Object::Error(format!("Could not load lib: {}", lib))), - }; - let mut new_store = Store::new_enclosed(self.store.clone()); - for (k, v) in lib_store { - new_store.set(k, v); - } - self.store = Rc::new(RefCell::new(new_store)); - None - } - - fn unwrap_return_value(&mut self, obj: Option) -> Object { - match obj { - Some(Object::Return(o)) => *o, - Some(o) => o, - None => Object::Null, - } - } - - fn eval_ident(&mut self, ident: Ident) -> Object { - let Ident(i) = ident; - let builtins = new_globals(); - if builtins.contains_key(&i) { - return builtins.get(&i).unwrap().clone(); - }; - match self.store.borrow_mut().get(&i) { - Some(i) => i, - None => Object::Error(format!("😾 Meow-sterious! The identifier '{}' seems to be playing a game of hide-and-seek", i)), - } - } - - /// Evaluate a literal expression - /// It matches the type of the literal and returns the appropriate object - /// # Arguments - /// * `lit` - The literal to be evaluated - /// # Returns - /// * `Object` - The object representing the literal - /// # Returns - /// * `Object` - If the literal is not a valid type - fn eval_literal(&mut self, lit: Literal) -> Object { - match lit { - Literal::String(s) => Object::String(s), - Literal::Number(i) => Object::Number(i), - Literal::Boolean(b) => Object::Bool(b), - Literal::Array(a) => Object::Array( - a.iter() - .map(|e| self.eval_expr(e.clone()).unwrap_or(Object::Null)) - .collect::>(), - ), - Literal::Object(h) => self.eval_object_literal(h), - } - } - - /// Evaluate an object literal - /// { "a": 1, "b": 2 } - /// => { "a": 1, "b": 2 } - /// # Examples - /// ``` - /// use etrl::{Evaluator, Literal, Ident}; - /// let mut eval = Evaluator::new(); - /// let obj = Literal::Object(vec![(Ident::new("a"), Literal::Number(1)), (Ident::new("b"), Literal::Number(2))]); - /// let result = eval.eval_object_literal(obj); - /// assert_eq!(result, Object::Object(vec![(Ident::new("a"), Object::Number(1)), (Ident::new("b"), Object::Number(2))])); - /// ``` - fn eval_object_literal(&mut self, h: Vec<(Expr, Expr)>) -> Object { - let mut hash = HashMap::new(); - - for (k, v) in h { - let key = self.eval_expr(k).unwrap_or(Object::Null); - if self.is_error(&key) { - return key; - } - - let val = self.eval_expr(v).unwrap_or(Object::Null); - if self.is_error(&val) { - return val; - } - - hash.insert(key, val); - } - Object::Object(hash) - } -} \ No newline at end of file diff --git a/src/evaluation/object.rs b/src/evaluation/object.rs deleted file mode 100644 index 90c70bc..0000000 --- a/src/evaluation/object.rs +++ /dev/null @@ -1,112 +0,0 @@ -use super::store::Store; -use crate::ast::{BlockStatement, Ident}; -use std::{ - cell::RefCell, - collections::HashMap, - fmt, - hash::{Hash, Hasher}, - rc::Rc, -}; - -pub type InbuiltFunction = fn(Vec) -> Object; - -#[derive(Clone, Debug)] -pub enum Object { - Number(f64), - String(String), - Bool(bool), - Null, - Return(Box), - Error(String), - Fn(Vec, BlockStatement, Rc>), - Inbuilt(InbuiltFunction), - Array(Vec), - Object(HashMap), - Typeof(Box), - Loop(Box), - Break, - Continue -} - -impl PartialEq for Object { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Object::Number(a), Object::Number(b)) => a == b, - (Object::String(a), Object::String(b)) => a == b, - (Object::Bool(a), Object::Bool(b)) => a == b, - (Object::Null, Object::Null) => true, - (Object::Return(a), Object::Return(b)) => a == b, - (Object::Error(a), Object::Error(b)) => a == b, - (Object::Fn(a, b, c), Object::Fn(d, e, f)) => a == d && b == e && c == f, - (Object::Inbuilt(a), Object::Inbuilt(b)) => a == b, - (Object::Array(a), Object::Array(b)) => a == b, - (Object::Object(a), Object::Object(b)) => a == b, - (Object::Typeof(a), Object::Typeof(b)) => a == b, - _ => false, - } - } -} - -impl Eq for Object {} - -impl fmt::Display for Object { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Object::Number(ref value) => write!(f, "{}", value), - Object::String(ref value) => write!(f, "{}", value), - Object::Bool(ref value) => write!(f, "{}", value), - Object::Null => write!(f, "null"), - Object::Return(ref value) => write!(f, "{}", value), - Object::Error(ref value) => write!(f, "{}", value), - Object::Fn(ref params, _, _) => { - let mut result = String::new(); - for (i, Ident(ref s)) in params.iter().enumerate() { - if i < 1 { - result.push_str(s); - } else { - result.push_str(&format!(", {}", s)); - } - } - write!(f, "fn({}) {{ ... }}", result) - } - Object::Inbuilt(_) => write!(f, "[inbuilt fn]"), - Object::Array(ref val) => { - let mut result = String::new(); - for (i, obj) in val.iter().enumerate() { - if i < 1 { - result.push_str(&format!("{}", obj)); - } else { - result.push_str(&format!(", {}", obj)); - } - } - write!(f, "[{}]", result) - } - Object::Object(ref hash) => { - let mut res = String::new(); - for (i, (k, v)) in hash.iter().enumerate() { - if i < 1 { - res.push_str(&format!("{}: {}", k, v)); - } else { - res.push_str(&format!(", {}: {}", k, v)); - } - } - - write!(f, "{{{}}}", res) - } - Object::Typeof(ref obj) => write!(f, "typeof({})", obj), - Object::Loop(ref _block) => write!(f, "loop {{ ... }}"), - Object::Break => write!(f, "break"), - Object::Continue => write!(f, "continue"), - } - } -} - -impl Hash for Object { - fn hash(&self, state: &mut H) { - match *self { - Object::Bool(ref b) => b.hash(state), - Object::String(ref s) => s.hash(state), - _ => "".hash(state), - } - } -} \ No newline at end of file diff --git a/src/evaluation/store.rs b/src/evaluation/store.rs deleted file mode 100644 index db53f9a..0000000 --- a/src/evaluation/store.rs +++ /dev/null @@ -1,72 +0,0 @@ -use super::object::Object; -use std::{cell::RefCell, collections::HashMap, rc::Rc}; - -#[derive(PartialEq, Clone, Debug)] -pub struct Store { - pub store: HashMap, - pub outer: Option>>, -} - -impl Store { - pub fn new() -> Self { - Self { - store: HashMap::new(), - outer: None, - } - } - - pub fn from(store: HashMap) -> Self { - Self { store, outer: None } - } - - pub fn new_enclosed(outer: Rc>) -> Self { - Self { - store: HashMap::new(), - outer: Some(outer), - } - } - - pub fn get(&mut self, name: &str) -> Option { - match self.store.get(name) { - Some(e) => Some(e).cloned(), - None => { - if let Some(ref o) = self.outer { - return o.borrow_mut().get(name); - } else { - None - } - } - } - } - - pub fn set(&mut self, name: String, val: Object) -> Option { - self.store.insert(name, val) - } - - pub fn anew(&mut self, name: String, val: Object) -> Option { - match self.store.get(&name) { - Some(_e) => self.store.insert(name, val), - None => { - if let Some(ref o) = self.outer { - let mut outer = o.borrow_mut(); - match outer.get(&name) { - Some(_) => outer.anew(name, val), - None => None, - } - } else { - None - } - } - } - } - - pub fn iter (&self) -> std::collections::hash_map::Iter { - self.store.iter() - } -} - -impl Default for Store { - fn default() -> Self { - Self::new() - } -} \ No newline at end of file diff --git a/src/lexer.rs b/src/lexer.rs deleted file mode 100644 index 832b527..0000000 --- a/src/lexer.rs +++ /dev/null @@ -1,208 +0,0 @@ -use crate::ast::token::Token; -use std::collections::HashMap; - -lazy_static::lazy_static! { - static ref KEYWORDS: HashMap<&'static str, Token> = { - let mut keywords = HashMap::new(); - keywords.insert("scratch", Token::Set); - keywords.insert("amew", Token::Anew); - keywords.insert("pawction", Token::Func); - keywords.insert("purrhaps", Token::If); - keywords.insert("meowtually", Token::Else); - keywords.insert("tail", Token::Return); - keywords.insert("pawckage", Token::Include); - keywords.insert("purrfect", Token::Boolean(true)); - keywords.insert("clawful", Token::Boolean(false)); - keywords.insert("furreal", Token::Typeof); - keywords.insert("furrever", Token::Loop); - keywords.insert("hiss", Token::Break); - keywords.insert("continue", Token::Continue); - - // Kaomojis - /* - keywords.insert("^◡^っ", Token::Return); - keywords.insert("╯°□°╯", Token::Break); - keywords.insert("≧^◡^≦", Token::Boolean(true)); - keywords.insert("。•́︿•̀。", Token::Boolean(false)); - keywords.insert("=^・_・^=〇", Token::Continue); - keywords.insert("◔.◔", Token::If); - keywords.insert("´υ`", Token::Else); - keywords.insert("๑╹o╹", Token::Set); - keywords.insert("o_o", Token::Func); - keywords.insert(">人<", Token::Else); - */ - keywords - }; -} - -fn is_letter(c: char) -> bool { - c.is_ascii_alphabetic() || c == '_' -} - -pub fn find_indentifier(ident: &str) -> Option<&Token> { - KEYWORDS.get(ident) -} - -pub struct Lexer { - input: String, - position: usize, - read_position: usize, - ch: char, -} - -impl Lexer { - pub fn new(input: String) -> Lexer { - Lexer { - ch: input.chars().next().unwrap(), - input, - position: 0, - read_position: 1, - } - } - - pub fn read_char(&mut self) { - self.ch = if self.read_position >= self.input.len() { - '\0' - } else { - self.input.chars().nth(self.read_position).unwrap() - }; - - self.position = self.read_position; - self.read_position += 1; - } - - fn read_identifier(&mut self) -> String { - let pos: usize = self.position; - while is_letter(self.ch) { - self.read_char() - } - self.input[pos..self.position].to_string() - } - - fn read_number(&mut self) -> f64 { - let pos: usize = self.position; - while self.ch.is_numeric() || self.ch == '.' { - self.read_char(); - } - self.input[pos..self.position].parse::().unwrap() - } - - fn read_string(&mut self) -> String { - let pos: usize = self.position + 1; - loop { - self.read_char(); - if self.ch == '"' || self.ch == (0 as char) { - break; - } - } - self.input[pos..self.position].to_string() - } - - pub fn read_comment(&mut self) -> String { - let pos: usize = self.position; - loop { - self.read_char(); - if self.ch == '\n' || self.ch == (0 as char) { - break; - } - } - self.input[pos..self.position].to_string() - } - - fn skip_whitespace(&mut self) { - while self.ch == ' ' || self.ch == '\t' || self.ch == '\n' || self.ch == '\r' { - self.read_char() - } - } - - fn peek_char(&self) -> char { - if self.read_position >= self.input.len() { - return 0 as char; - } - self.input.chars().nth(self.read_position).unwrap() - } - - pub fn next_token(&mut self) -> Token { - self.skip_whitespace(); - let tok: Token = match self.ch { - '=' => { - if self.peek_char() == '=' { - self.read_char(); - Token::Equals - } else { - Token::Assign - } - } - ';' => Token::Semicolon, - ':' => Token::Colon, - ',' => Token::Comma, - '+' => Token::Plus, - '-' => Token::Minus, - '&' => Token::AND, - '|' => Token::OR, - '^' => Token::XOR, - '%' => Token::Percent, - '!' => { - if self.peek_char() == '=' { - self.read_char(); - Token::NotEquals - } else { - Token::Bang - } - } - '~' => Token::In, - '(' => Token::LeftParen, - ')' => Token::RightParen, - '{' => Token::LeftBrace, - '}' => Token::RightBrace, - '[' => Token::LeftBracket, - ']' => Token::RightBracket, - '*' => Token::Asterisk, - '/' => { - if self.peek_char() == '/' { - self.read_comment(); - Token::Comment - } else { - Token::Slash - } - } - '<' => match self.peek_char() { - '<' => Token::LeftShift, - '=' => Token::LessEqual, - _ => Token::Less - }, - '>' => match self.peek_char() { - '>' => Token::RightShift, - '=' => Token::GreaterEqual, - _ => Token::Greater - }, - '"' => Token::String(self.read_string()), - '\'' => { - if self.peek_char() == 's' { - Token::SingleQuoteS - } else { - Token::Illegal - } - } - '\u{0}' => Token::Eof, - _ => { - if is_letter(self.ch) { - let i: String = self.read_identifier(); - return match find_indentifier(i.as_str()) { - Some(a) => a.to_owned(), - _ => Token::Ident(i), - }; - } else if self.ch.is_numeric() { - let i: f64 = self.read_number(); - return Token::Number(i); - } else { - Token::Illegal - } - } - }; - - self.read_char(); - tok - } - -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 383b7b0..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -pub mod ast; -pub mod evaluation; -pub mod lexer; -pub mod parser; -pub mod std_library; -pub mod repl; -use std::{rc::Rc, cell::RefCell}; - -use evaluation::{object::*, store::*, *}; -use lexer::Lexer; -use parser::Parser; - -pub fn interpret(content: &str) { - let store = Store::new(); - let mut evaluator = Eval { - store: Rc::new(RefCell::new(store)), - }; - let lexer = Lexer::new(content.to_string()); - let mut parser = Parser::new(lexer); - let program = parser.parse_program(); - if !parser.errors.is_empty() { - for e in parser.errors.iter() { - println!("\t{}", e); - } - return; - } - let res = evaluator.eval(program); - - if let Some(o) = res { - match o { - Object::Null => (), - _ => println!("{}", o), - } - } -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index d402d85..0000000 --- a/src/main.rs +++ /dev/null @@ -1,68 +0,0 @@ -#[cfg(target_os = "emscripten")] -extern crate meowscript; - -#[cfg(not(target_os = "emscripten"))] -use std::env; - -#[cfg(not(target_os = "emscripten"))] -use std::fs; - - -#[cfg(target_os = "emscripten")] -use std::{ffi::CString, mem, os::raw::c_char}; - -#[cfg(not(target_os = "emscripten"))] -fn main() { - let args: Vec = env::args().collect(); - if args.len() != 1 && args[1].as_str() == "run" { - let filename = &args[2].split('.').collect::>(); - if filename[filename.len() - 1] != "meow" { - println!("File must have the extention .meow"); - return; - } - let content = fs::read_to_string(&args[2]).expect("Could not read file."); - - meowscript::interpret(content.as_str()); - } else { - - println!( - "Welcome to the MeowScript REPL. Type in commands to get started.", - ); - meowscript::repl::start(); - } - -} - -#[cfg(target_os = "emscripten")] -fn main() {} - -#[cfg(target_os = "emscripten")] -/// # Safety -#[no_mangle] -pub unsafe extern "C" fn interpret(src: *mut c_char) -> usize { - let code = CString::from_raw(src).to_str().unwrap().to_string(); - let _ = meowscript::interpret(&code); - 0 -} - - -#[cfg(target_os = "emscripten")] -#[no_mangle] -pub extern "C" fn alloc(len: usize) -> *mut u8 { - let mut buf: Vec = Vec::with_capacity(len); - - let ptr = buf.as_mut_ptr(); - - mem::forget(buf); - - ptr -} - -#[cfg(target_os = "emscripten")] -/// # Safety -#[no_mangle] -pub unsafe extern "C" fn dealloc(ptr: *mut u8, len: usize) { - let data = Vec::from_raw_parts(ptr, len, len); - - mem::drop(data) -} \ No newline at end of file diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index b904010..0000000 --- a/src/parser.rs +++ /dev/null @@ -1,657 +0,0 @@ -use crate::{ast::{*, token::Token}, lexer::Lexer}; - -pub struct Parser { - lexer: Lexer, - current_token: Token, - peek_token: Token, - pub errors: Vec -} - -impl Parser { - - pub fn new(lexer: Lexer) -> Self { - let mut p: Parser = Parser { - lexer, - current_token: Token::Eof, - peek_token: Token::Eof, - errors: vec![], - }; - p.next_token(); - p.next_token(); - p - } - - pub fn next_token(&mut self) { - self.current_token = self.peek_token.clone(); - self.peek_token = self.lexer.next_token(); - } - - pub fn parse_program(&mut self) -> Program { - let mut statements: Vec = vec![]; - while self.current_token != Token::Eof { - let stmt: Option = self.parse_statement(); - if stmt != None { - statements.push(stmt.unwrap()); - }; - self.next_token(); - } - Program { statements } - } - - pub fn parse_statement(&mut self) -> Option { - match self.current_token { - Token::Set => self.parse_set_statement(), - Token::Return => self.parse_return_statement(), - Token::Include => self.parse_include_statement(), - Token::Anew => self.parse_anew_expr(), - Token::Break => self.parse_break_statement(), - Token::Continue => self.parse_continue_statement(), - _ => self.parse_expr_statement(), - } - } - - - pub fn parse_expr_statement(&mut self) -> Option { - match self.parse_expr(Precedence::Lowest) { - Some(expression) => { - if self.peek_token(&Token::Semicolon) { - self.next_token(); - } - Some(Statement::Expression(expression)) - } - None => None, - } - } - - pub fn parse_set_statement(&mut self) -> Option { - match &self.peek_token { - Token::Ident(_) => self.next_token(), - _ => { - self.peek_error(Token::Ident(String::new())); - return None; - } - } - - let name: Ident = match self.parse_ident() { - Some(Expr::Ident(ref mut s)) => s.clone(), - _ => return None, - }; - - if !self.expect_peek(Token::Assign) { - return None; - } - - self.next_token(); - - let lit: Expr = match self.parse_expr(Precedence::Lowest) { - Some(e) => e, - None => return None, - }; - - while !self.current_token(Token::Semicolon) { - self.next_token(); - } - - Some(Statement::Set(name, lit)) - } - - pub fn parse_return_statement(&mut self) -> Option { - self.next_token(); - - let exp = match self.parse_expr(Precedence::Lowest) { - Some(e) => e, - None => return None, - }; - - while !self.current_token(Token::Semicolon) { - self.next_token(); - } - - Some(Statement::Return(exp)) - } - - pub fn parse_include_statement(&mut self) -> Option { - self.next_token(); - // the string next to the include keyword is the lib - let lib = match &self.current_token { - Token::String(ref s) => s.clone(), - _ => { - self.peek_error(Token::String(String::new())); - return None; - } - }; - while !self.current_token(Token::Semicolon) { - self.next_token(); - } - Some(Statement::Include(lib)) - } - - fn parse_block_statement(&mut self) -> BlockStatement { - self.next_token(); - - let mut statements = vec![]; - while !self.current_token(Token::RightBrace) && !self.current_token(Token::Eof) { - if let Some(s) = self.parse_statement() { - statements.push(s); - } - self.next_token(); - } - - statements - } - - pub fn parse_anew_expr(&mut self) -> Option { - match &self.peek_token { - Token::Ident(_) => self.next_token(), - _ => { - self.peek_error(Token::Ident(String::new())); - return None; - } - } - - let name: Ident = match self.parse_ident() { - Some(Expr::Ident(ref mut s)) => s.clone(), - _ => return None, - }; - - if !self.expect_peek(Token::Assign) { - return None; - } - - self.next_token(); - - let lit: Expr = match self.parse_expr(Precedence::Lowest) { - Some(e) => e, - None => return None, - }; - - while !self.current_token(Token::Semicolon) { - self.next_token(); - } - - Some(Statement::Anew(name, lit)) - } - - pub fn parse_break_statement(&mut self) -> Option { - self.next_token(); - while !self.current_token(Token::Semicolon) { - self.next_token(); - } - Some(Statement::Break) - } - - pub fn parse_continue_statement(&mut self) -> Option { - self.next_token(); - while !self.current_token(Token::Semicolon) { - self.next_token(); - } - Some(Statement::Continue) - } - - fn parse_typof_expr(&mut self) -> Option { - self.next_token(); - let expr = match self.parse_expr(Precedence::Lowest) { - Some(e) => e, - None => return None, - }; - Some(Expr::Typeof { expr: Box::new(expr) }) - } - - fn parse_loop_expr(&mut self) -> Option { - self.next_token(); - let body = self.parse_block_statement(); - Some(Expr::Loop { body }) - } - - fn parse_expr(&mut self, precedence: Precedence) -> Option { - let mut left: Option = match self.current_token { - Token::Ident(_) => self.parse_ident(), - Token::Bang | Token::Minus | Token::Plus => self.parse_prefix_expr(), - Token::LeftParen => self.parse_grouped_expr(), - Token::If => self.parse_if_expr(), - Token::Func => self.parse_fn_expr(), - Token::Number(_) => self.parse_int_literal(), - Token::Boolean(_) => self.parse_boolean_literal(), - Token::String(_) => self.parse_string_literal(), - Token::LeftBracket => self.parse_array_literal(), - Token::LeftBrace => self.parse_object_literal(), - Token::Typeof => self.parse_typof_expr(), - Token::Loop => self.parse_loop_expr(), - Token::SingleQuoteS => { - self.next_token(); - match self.parse_ident() { - Some(Expr::Ident(ident)) => Some(Expr::Index { - array: Box::new(Expr::Ident(Ident("self".to_string()))), // Assuming 'self' is the dictionary object - index: Box::new(Expr::Literal(Literal::String(ident.0))), - }), - _ => None, - } - } - _ => { - None - } - }; - - while !self.peek_token(&Token::Semicolon) && precedence < self.next_token_precedence() { - match self.peek_token { - Token::Plus - | Token::Minus - | Token::Asterisk - | Token::Equals - | Token::Slash - | Token::Percent - | Token::NotEquals - | Token::Less - | Token::LessEqual - | Token::Greater - | Token::GreaterEqual - | Token::AND - | Token::OR - | Token::XOR - | Token::In => { - self.next_token(); - left = self.parse_infix_expr(left.unwrap()); - } - - Token::LeftShift => { - self.lexer.next_token(); - self.next_token(); - left = self.parse_infix_expr(left.unwrap()); - } - - Token::RightShift => { - self.lexer.next_token(); - self.next_token(); - left = self.parse_infix_expr(left.unwrap()); - } - - Token::LeftParen => { - self.next_token(); - left = self.parse_call_expr(left.unwrap()); - } - Token::LeftBracket => { - self.next_token(); - left = self.parse_index_expr(left.unwrap()); - } - _ => return left, - } - } - - left - } - - fn parse_object_literal(&mut self) -> Option { - let mut obj = vec![]; - while !self.peek_token(&Token::RightBrace) { - self.next_token(); - let key = match self.parse_expr(Precedence::Lowest) { - Some(o) => o, - None => return None, - }; - if !self.expect_peek(Token::Colon) { - return None; - } - - self.next_token(); - let val = match self.parse_expr(Precedence::Lowest) { - Some(o) => o, - None => return None, - }; - obj.push((key, val)); - if !self.peek_token(&Token::RightBrace) && !self.expect_peek(Token::Comma) { - return None; - } - } - if !self.expect_peek(Token::RightBrace) { - return None; - } - - Some(Expr::Literal(Literal::Object(obj))) - } - - fn parse_int_literal(&mut self) -> Option { - match self.current_token { - Token::Number(ref mut int) => Some(Expr::Literal(Literal::Number(*int))), - _ => None, - } - } - - fn parse_boolean_literal(&mut self) -> Option { - match self.current_token { - Token::Boolean(boolean) => Some(Expr::Literal(Literal::Boolean(boolean))), - _ => None, - } - } - - fn parse_string_literal(&mut self) -> Option { - match self.current_token { - Token::String(ref mut str) => Some(Expr::Literal(Literal::String(str.clone()))), - _ => None, - } - } - - fn parse_array_literal(&mut self) -> Option { - self.parse_expr_list(Token::RightBracket) - .map(|list| Expr::Literal(Literal::Array(list))) - } - - - - fn parse_expr_list(&mut self, end: Token) -> Option> { - let mut list = vec![]; - if self.peek_token(&end) { - self.next_token(); - return Some(list); - } - - self.next_token(); - match self.parse_expr(Precedence::Lowest) { - Some(a) => list.push(a), - None => return None, - }; - while self.peek_token(&Token::Comma) { - self.next_token(); - if self.peek_token(&Token::RightBracket) { - break; - } - self.next_token(); - - match self.parse_expr(Precedence::Lowest) { - Some(expr) => list.push(expr), - None => return None, - } - } - - if !self.expect_peek(end) { - return None; - } - - Some(list) - } - - fn parse_ident(&mut self) -> Option { - match self.current_token { - Token::Ident(_) => { - let ident = match &self.current_token { - Token::Ident(ident) => ident.clone(), - _ => return None, - }; - if self.peek_token(&Token::SingleQuoteS) { - self.next_token(); - self.next_token(); - if let Token::Ident(prop) = &self.peek_token { - let property = prop.clone(); - self.next_token(); - return Some(Expr::Index { - array: Box::new(Expr::Ident(Ident(ident))), - index: Box::new(Expr::Literal(Literal::String(property))), - }); - } else { - self.errors.push(format!("Expected an identifier after '")); - return None; - } - } else { - return Some(Expr::Ident(Ident(ident))); - } - } - _ => None, - } - } - - - fn parse_prefix_expr(&mut self) -> Option { - let prefix = match self.current_token { - Token::Bang => Prefix::Exclamation, - Token::Minus => Prefix::Minus, - Token::Plus => Prefix::Plus, - _ => return None, - }; - - self.next_token(); - - self.parse_expr(Precedence::Prefix) - .map(|expr| Expr::Prefix(prefix, Box::new(expr))) - } - - fn parse_infix_expr(&mut self, left: Expr) -> Option { - let infix = match self.current_token { - Token::Plus => Infix::Plus, - Token::Minus => Infix::Minus, - Token::Slash => Infix::Divide, - Token::Asterisk => Infix::Times, - Token::Percent => Infix::Modulo, - Token::Equals => Infix::Equals, - Token::NotEquals => Infix::NotEquals, - Token::Less => Infix::LessThan, - Token::Greater => Infix::GreaterThan, - Token::LessEqual => Infix::LessThanEqual, - Token::GreaterEqual => Infix::GreaterThanEqual, - Token::LeftShift => Infix::LeftShift, - Token::RightShift => Infix::RightShift, - Token::AND => Infix::AND, - Token::OR => Infix::OR, - Token::XOR => Infix::XOR, - Token::In => Infix::In, - _ => return None, - }; - - let precedence = self.current_token_precedence(); - self.next_token(); - - self.parse_expr(precedence) - .map(|e| Expr::Infix(infix, Box::new(left), Box::new(e))) - } - - fn parse_grouped_expr(&mut self) -> Option { - let exp = self.parse_expr(Precedence::Lowest); - if !self.expect_peek(Token::RightParen) { - return None; - } - exp - } - - fn parse_if_expr(&mut self) -> Option { - if !self.expect_peek(Token::LeftParen) { - return None; - } - - self.next_token(); - - let expr: Expr = match self.parse_expr(Precedence::Lowest) { - Some(e) => e, - None => return None, - }; - - if !self.expect_peek(Token::RightParen) || !self.expect_peek(Token::LeftBrace) { - return None; - } - - let cons: Vec = self.parse_block_statement(); - let mut alternative: Option> = None; - if self.peek_token(&Token::Else) { - self.next_token(); - - if self.peek_token(&Token::If) { - self.next_token(); - let else_if = self.parse_if_expr(); - alternative = Some(vec![Statement::Expression(else_if.unwrap())]); - } else if !self.expect_peek(Token::LeftBrace) { - return None; - } else { - alternative = Some(self.parse_block_statement()) - }; - } - - Some(Expr::If { - cond: Box::new(expr), - then: Box::new(cons), - else_: alternative, - }) - } - - fn parse_fn_expr(&mut self) -> Option { - if !self.expect_peek(Token::LeftParen) { - return None; - } - let params = match self.parse_params() { - Some(s) => s, - None => return None, - }; - self.next_token(); - let body = self.parse_block_statement(); - - Some(Expr::Fun { params, body }) - } - - fn token_to_precedence(tok: &Token) -> Precedence { - match tok { - Token::Equals | Token::NotEquals => Precedence::Equals, - Token::Less | Token::LessEqual => Precedence::LessGreater, - Token::Greater | Token::GreaterEqual => Precedence::LessGreater, - Token::Plus | Token::Minus => Precedence::Sum, - Token::Slash | Token::Asterisk | Token::Percent => Precedence::Product, - Token::LeftBracket => Precedence::Index, - Token::LeftParen => Precedence::Call, - Token::In => Precedence::In, - Token::LeftShift => Precedence::LeftShift, - Token::RightShift => Precedence::RightShift, - Token::AND => Precedence::AND, - Token::OR => Precedence::OR, - Token::XOR => Precedence::XOR, - _ => Precedence::Lowest, - } - } - - fn parse_params(&mut self) -> Option> { - let mut idents: Vec = vec![]; - if self.peek_token(&Token::RightParen) { - self.next_token(); - return Some(idents); - } - - self.next_token(); - match self.current_token { - Token::Ident(ref mut ident) => idents.push(Ident(ident.clone())), - _ => { - self.errors.push( - format!("Meow! Expected a purr-ameter identifier. Got: {} 🙀", self.current_token) - ); - return None; - } - }; - - while self.peek_token(&Token::Comma) { - self.next_token(); - self.next_token(); - match self.current_token { - Token::Ident(ref mut ident) => idents.push(Ident(ident.clone())), - _ => return None, - }; - } - - if !self.expect_peek(Token::RightParen) { - return None; - } - - Some(idents) - } - - fn parse_call_arguments(&mut self) -> Option> { - let mut args: Vec = vec![]; - - if self.peek_token(&Token::RightParen) { - self.next_token(); - return Some(args); - } - - self.next_token(); - match self.parse_expr(Precedence::Lowest) { - Some(e) => args.push(e), - None => return None, - }; - - while self.peek_token(&Token::Comma) { - self.next_token(); - self.next_token(); - - match self.parse_expr(Precedence::Lowest) { - Some(e) => args.push(e), - None => return None, - }; - } - - if !self.expect_peek(Token::RightParen) { - return None; - } - - Some(args) - } - - fn parse_index_expr(&mut self, left: Expr) -> Option { - self.next_token(); - let expr = match self.parse_expr(Precedence::Lowest) { - Some(e) => e, - None => return None, - }; - if !self.expect_peek(Token::RightBracket) { - return None; - } - - Some(Expr::Index { - array: Box::new(left), - index: Box::new(expr), - }) - } - - fn parse_call_expr(&mut self, left: Expr) -> Option { - let args = match self.parse_call_arguments() { - Some(e) => e, - None => return None, - }; - - Some(Expr::Call { - function: Box::new(left), - args, - }) - } - - fn peek_token(&self, t: &Token) -> bool { - self.peek_token == *t - } - - fn current_token(&self, t: Token) -> bool { - self.current_token == t - } - - fn expect_peek(&mut self, t: Token) -> bool { - if let Token::Ident(..) = t { - self.next_token(); - return true; - } - - if self.peek_token(&t) { - self.next_token(); - true - } else { - self.peek_error(t); - false - } - } - - fn peek_error(&mut self, t: Token) { - let msg = format!( - "Meowch! Expected {} as the next token, but got {}", - t, - self.peek_token - ); - self.errors.push(msg); - } - - fn current_token_precedence(&mut self) -> Precedence { - Self::token_to_precedence(&self.current_token) - } - - fn next_token_precedence(&mut self) -> Precedence { - Self::token_to_precedence(&self.peek_token) - } -} \ No newline at end of file diff --git a/src/repl.rs b/src/repl.rs deleted file mode 100644 index 6e4f2b8..0000000 --- a/src/repl.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::{ - evaluation::{store::Store, object::Object, Eval}, - lexer::Lexer, - parser::Parser, -}; -use std::{ - cell::RefCell, - io::{stdin, stdout, Write}, - rc::Rc, -}; - -pub fn start() { - let env = Store::new(); - let mut evaluator = Eval { - store: Rc::new(RefCell::new(env)), - }; - loop { - print!(">> "); - let _ = stdout().flush(); - let mut input_string = String::new(); - stdin().read_line(&mut input_string).ok(); - - if input_string.is_empty() { - println!("Invalid input."); - continue; - } - - let lexer = Lexer::new(input_string); - let mut parser = Parser::new(lexer); - let program = parser.parse_program(); - if !parser.errors.is_empty() { - print_parse_errors(parser.errors); - continue; - } - let res = evaluator.eval(program); - println!("{}", res.unwrap_or(Object::Null)); - } -} - -fn print_parse_errors(errors: Vec) { - for e in errors.iter() { - println!("\t{}", e); - } -} \ No newline at end of file diff --git a/src/std_library/array.rs b/src/std_library/array.rs deleted file mode 100644 index 4d9a32c..0000000 --- a/src/std_library/array.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::collections::HashMap; - -use crate::evaluation::object::Object; - -use super::Res; - -/// Adds the standard library to the global environment. -pub fn add_globals() -> Res { - let mut globals: HashMap = HashMap::new(); - globals.insert(String::from("pounce"), Object::Inbuilt(pop)); - globals.insert(String::from("top"), Object::Inbuilt(head)); - globals.insert(String::from("bottom"), Object::Inbuilt(tail)); - globals.insert(String::from("push"), Object::Inbuilt(push)); - globals.insert(String::from("includes"), Object::Inbuilt(includes)); - Res { - globals, - raw: Some(" - include \"std:util\"; - - set map = fun (arr, f) { - scratch res = []; - scratch iter = fun (array) { - purrhaps (length(array) == 0) { - tail; - } { - amew res = push(res, f(array[0])); - iter(bottom(array)); - } - }; - iter(arr) - tail res; - }; - ".to_string()) - } -} - -/// The std:array-built-in function `push`. -/// Pushes an object onto the end of an array. -/// # Arguments -/// * `args` - The array to push onto. -pub fn push(args: Vec) -> Object { - if args.len() != 2 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 2.", - args.len() - )); - } - - match &args[0] { - Object::Array(a) => { - let mut array = a.clone(); - array.push(args[1].clone()); - Object::Array(array) - } - o => Object::Error(format!("First argument must be an array. Got {}", o)), - } -} - -pub fn pop(args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - )); - } - match &args[0] { - Object::Array(a) => { - let mut array = a.clone(); - array.pop(); - Object::Array(array) - } - o => Object::Error(format!("First argument must be an array. Got {}", o)), - } -} - -pub fn head (args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - )); - } - match &args[0] { - Object::Array(a) => { - let mut array = a.clone(); - array.pop(); - Object::Array(array) - } - o => Object::Error(format!("First argument must be an array. Got {}", o)), - } -} - -pub fn tail (args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - )); - } - match &args[0] { - Object::Array(a) => Object::Array(a[1..].to_vec()), - o => Object::Error(format!("First argument must be an array. Got {}", o)), - } -} - -pub fn includes (args: Vec) -> Object { - if args.len() != 2 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 2.", - args.len() - )); - } - match &args[0] { - Object::Array(a) => { - let array = a.clone(); - Object::Bool(array.contains(&args[1])) - } - o => Object::Error(format!("First argument must be an array. Got {}", o)), - } -} \ No newline at end of file diff --git a/src/std_library/fs.rs b/src/std_library/fs.rs deleted file mode 100644 index 5578882..0000000 --- a/src/std_library/fs.rs +++ /dev/null @@ -1,103 +0,0 @@ -use std::collections::HashMap; -use std::fs::File; -use std::io::prelude::*; -use std::path::Path; - -use crate::evaluation::object::Object; - -use super::Res; - -pub fn add_globals() -> Res { - let mut globals = HashMap::new(); - globals.insert(String::from("readFile"), Object::Inbuilt(read_file)); - globals.insert(String::from("writeFile"), Object::Inbuilt(write_file)); - globals.insert(String::from("exists"), Object::Inbuilt(file_exists)); - Res { - globals, - raw: None - } - -} - -pub fn read_file(args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - )); - } - - match &args[0] { - Object::String(s) => { - let path = Path::new(s); - let display = path.display(); - let mut file = match File::open(&path) { - Err(why) => { - return Object::Error(format!("Couldn't open {}: {}", display, why)) - } - Ok(file) => file, - }; - let mut s = String::new(); - match file.read_to_string(&mut s) { - Err(why) => { - return Object::Error(format!("Couldn't read {}: {}", display, why)) - } - Ok(_) => { - Object::String(s) - } - } - } - _ => Object::Error(format!("Argument must be a string. Got {}", args[0])) - } -} - -pub fn write_file(args: Vec) -> Object { - if args.len() != 2 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 2.", - args.len() - )); - } - match &args[0] { - Object::String(s) => { - let path = Path::new(s); - let display = path.display(); - let mut file = match File::create(&path) { - Err(why) => { - return Object::Error(format!("Couldn't create {}: {}", display, why)) - } - Ok(file) => file, - }; - match file.write_all(args[1].to_string().as_bytes()) { - Err(why) => { - return Object::Error(format!("Couldn't write to {}: {}", display, why)) - } - Ok(_) => { - Object::Null - } - } - } - _ => Object::Error(format!("Argument must be a string. Got {}", args[0])) - } -} - -pub fn file_exists(args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - )); - } - match &args[0] { - Object::String(s) => { - let path = Path::new(s); - if path.exists() { - Object::Bool(true) - } else { - Object::Bool(false) - } - } - _ => Object::Error(format!("Argument must be a string. Got {}", args[0])) - } -} - diff --git a/src/std_library/math.rs b/src/std_library/math.rs deleted file mode 100644 index 95898c0..0000000 --- a/src/std_library/math.rs +++ /dev/null @@ -1,152 +0,0 @@ -use std::collections::HashMap; -use rand::Rng; - -use crate::evaluation::object::Object; - -use super::Res; - -/// Adds the standard library to the global environment. -pub fn add_globals() -> Res { - let mut globals = HashMap::new(); - globals.insert(String::from("random"), Object::Inbuilt(random)); - globals.insert(String::from("round"), Object::Inbuilt(round)); - globals.insert(String::from("ceil"), Object::Inbuilt(ceil)); - globals.insert(String::from("floor"), Object::Inbuilt(floor)); - globals.insert(String::from("abs"), Object::Inbuilt(abs)); - globals.insert(String::from("sqrt"), Object::Inbuilt(sqrt)); - globals.insert(String::from("sin"), Object::Inbuilt(sin)); - globals.insert(String::from("cos"), Object::Inbuilt(cos)); - globals.insert(String::from("tan"), Object::Inbuilt(tan)); - globals.insert(String::from("pow"), Object::Inbuilt(pow)); - globals.insert(String::from("log2"), Object::Inbuilt(log2)); - globals.insert(String::from("log10"), Object::Inbuilt(log10)); - globals.insert(String::from("modulo"), Object::Inbuilt(modulo)); - globals.insert(String::from("Math.PI"), Object::Number(std::f64::consts::PI)); - globals.insert(String::from("Math.E"), Object::Number(std::f64::consts::E)); - globals.insert(String::from("MAX_INT"), Object::Number(std::f64::MAX)); - globals.insert(String::from("MIN_INT"), Object::Number(std::f64::MIN)); - Res { - globals, - raw: None, - } -} - -pub fn random(args: Vec) -> Object { - let min = match &args[0] { - Object::Number(n) => *n, - _ => 0.0, - }; - - let max = match &args[1] { - Object::Number(n) => *n, - _ => 0.0, - }; - - let mut rng = rand::thread_rng(); - let random_number = rng.gen_range(min..max); - Object::Number(random_number) -} - -pub fn round(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.round()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn log2(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.log2()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn log10(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.log10()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn sin(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.sin()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn cos(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.cos()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn tan(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.tan()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn pow(args: Vec) -> Object { - let base = match &args[0] { - Object::Number(n) => *n, - _ => 0.0, - }; - - let to = match &args[1] { - Object::Number(n) => *n, - _ => 0.0, - }; - - let result = f64::powf(base, to); - Object::Number(result) -} - -pub fn modulo(args: Vec) -> Object { - let a = match &args[0] { - Object::Number(n) => *n, - _ => 0.0, - }; - - let b = match &args[1] { - Object::Number(n) => *n, - _ => 0.0, - }; - - let mut result = a % b; - result = result + b; - result = result % b; - - Object::Number(result) -} - - -pub fn floor(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.floor()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn ceil(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.ceil()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn abs(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.abs()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} - -pub fn sqrt(args: Vec) -> Object { - match &args[0] { - Object::Number(n) => Object::Number(n.sqrt()), - _ => Object::Error(format!("Argument must be a number. Got {}", args[0])), - } -} diff --git a/src/std_library/mod.rs b/src/std_library/mod.rs deleted file mode 100644 index c3ad41c..0000000 --- a/src/std_library/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::collections::HashMap; - -use crate::evaluation::object::Object; -pub mod util; -pub mod array; -pub mod fs; -pub mod string; -pub mod math; -pub mod random; -/// Function to load a standard library -/// # Arguments -/// * `lib` - The name of the library to load. -/// # Returns -/// `HashMap` - The environment with the library loaded. - -pub struct Res { - pub globals: HashMap, - pub raw: Option, -} -pub fn get_std_lib(lib: String) -> Option { - match lib.as_str() { - "nya:clawtility" => Some(util::add_globals()), - "nya:furrball" => Some(array::add_globals()), - "nya:whiskers" => Some(string::add_globals()), - "nya:scratchpad" => Some(fs::add_globals()), - "nya:catculator" => Some(math::add_globals()), - "nya:rundamn" => Some(random::add_globals()), - //"nya:meowternet" => Some(http::add_globals()), - _ => None, - } -} diff --git a/src/std_library/random.rs b/src/std_library/random.rs deleted file mode 100644 index 6db0e9a..0000000 --- a/src/std_library/random.rs +++ /dev/null @@ -1,51 +0,0 @@ -extern crate rand; -use rand::seq::SliceRandom; -use rand::Rng; - - -pub fn add_globals() -> Res { - let mut globals = HashMap::new(); - globals.insert(String::from("new"), Object::Inbuilt(new)); - globals.insert(String::from("random"), Object::Inbuilt(random)); - globals.insert(String::from("uniform"), Object::Inbuilt(uniform)); - globals.insert(String::from("randint"), Object::Inbuilt(randint)); - globals.insert(String::from("choice"), Object::Inbuilt(choice)); - globals.insert(String::from("shuffle"), Object::Inbuilt(shuffle)); - - - Res { - globals, - raw: None, - } -} -pub struct SimpleRandom { - rng: rand::rngs::ThreadRng, -} - -impl SimpleRandom { - pub fn new() -> Self { - SimpleRandom { rng: rand::thread_rng() } - } - - pub fn random(&mut self) -> f64 { - self.rng.gen::() - } - - pub fn uniform(&mut self, a: f64, b: f64) -> f64 { - self.rng.gen_range(a..b) - } - - pub fn randint(&mut self, a: i64, b: i64) -> i64 { - self.rng.gen_range(a..=b) - } - - pub fn choice(&mut self, seq: &[T]) -> T { - seq.choose(&mut self.rng).unwrap().clone() - } - - pub fn shuffle(&mut self, x: &mut Vec) { - x.shuffle(&mut self.rng); - } -} - - diff --git a/src/std_library/string.rs b/src/std_library/string.rs deleted file mode 100644 index 94b9fc5..0000000 --- a/src/std_library/string.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::collections::HashMap; - -use crate::evaluation::object::Object; - -use super::Res; - -/// Adds the standard library to the global environment. -pub fn add_globals() -> Res { - let mut globals = HashMap::new(); - globals.insert(String::from("replace"), Object::Inbuilt(replace)); - globals.insert(String::from("in_whiskers"), Object::Inbuilt(to_string)); - Res { - globals, - raw: None, - } -} - -pub fn replace(args: Vec) -> Object { - if args.len() != 3 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 3.", - args.len() - )); - } - - match &args[0] { - Object::String(s) => { - let mut s = s.clone(); - s = s.replace(&args[1].to_string(), &args[2].to_string()); - Object::String(s) - } - o => Object::Error(format!("First argument must be a string. Got {}", o)), - } -} - -pub fn to_string(args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - )); - } - - match &args[0] { - Object::String(s) => Object::String(s.clone()), - Object::Array(a) => { - let mut s = String::new(); - for o in a.iter() { - s.push_str(&o.to_string()); - } - Object::String(s) - }, - Object::Number(n) => Object::String(n.to_string()), - Object::Bool(b) => Object::String(b.to_string()), - Object::Null => Object::String(String::from("null")), - Object::Error(e) => Object::String(e.clone()), - Object::Fn(..) => Object::String(String::from("[Function]")), - Object::Inbuilt(..) => Object::String(String::from("[Inbuilt Function]")), - o => Object::String(format!("{}", o)) - } -} \ No newline at end of file diff --git a/src/std_library/util.rs b/src/std_library/util.rs deleted file mode 100644 index 6fd4cc1..0000000 --- a/src/std_library/util.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::{format, collections::HashMap}; -use crate::evaluation::object::Object; - -use super::Res; - -pub fn add_globals() -> Res { - let mut globals = HashMap::new(); - globals.insert(String::from("length"), Object::Inbuilt(length)); - globals.insert(String::from("kibble"), Object::Inbuilt(kibble)); - globals.insert(String::from("nap"), Object::Inbuilt(nap)); - Res { globals, raw: None } -} - -/// Function to get the length of an array or string. -/// # Arguments -/// * `args` - The array or string to get the length of. -/// # Returns -/// `Object` - The length of the array or string. -pub fn length(args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - - )); - } - match &args[0] { - Object::String(s) => Object::Number(s.len() as f64), - Object::Array(a) => Object::Number(a.len() as f64), - o => Object::Error(format!("Argument must be a string or array. Got {}", o)), - } -} - -pub fn kibble(args: Vec) -> Object { - println!("{}", &args[0]); - if let Object::String(s) = &args[0] { - print!("{}", s); - } - let mut input = String::new(); - std::io::stdin().read_line(&mut input).expect("Failed to read line"); - Object::String(input) -} - -pub fn nap(args: Vec) -> Object { - if args.len() != 1 { - return Object::Error(format!( - "Wrong number of arguments. Got {}. Expected 1.", - args.len() - )); - } - if let Object::Number(n) = &args[0] { - std::thread::sleep(std::time::Duration::from_millis(*n as u64)); - } - Object::Null -} \ No newline at end of file