diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5273ac994b..30ab001e97 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ env: RUSTUP_MAX_RETRIES: 10 jobs: - cargo_build: + cargo-build: name: "cargo build" runs-on: ubuntu-latest steps: @@ -45,8 +45,11 @@ jobs: - run: ./target/release/ruff_dev generate-json-schema - run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. You may have to rerun 'cargo dev generate-json-schema'." - run: git diff --exit-code -- ruff.schema.json + - run: ./target/release/ruff_dev generate-playground-options + - run: git diff --quiet playground/src/ruff_options.rs || echo "::error file=playground/src/ruff_options.ts::This file is outdated. You may have to rerun 'cargo dev generate-playground-options'." + - run: git diff --exit-code -- README.md src/checks_gen.rs playground/src/ruff_options.ts - cargo_fmt: + cargo-fmt: name: "cargo fmt" runs-on: ubuntu-latest steps: @@ -82,6 +85,7 @@ jobs: toolchain: nightly-2022-11-01 override: true components: clippy + target: wasm32-unknown-unknown - uses: actions/cache@v3 env: cache-name: cache-cargo @@ -95,8 +99,9 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - run: cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic + - run: cargo clippy --workspace --target wasm32-unknown-unknown --all-features -- -D warnings -W clippy::pedantic - cargo_test: + cargo-test: name: "cargo test" runs-on: ubuntu-latest steps: @@ -122,7 +127,32 @@ jobs: - run: cargo test --all - run: cargo test --package ruff --test black_compatibility_test -- --ignored - maturin_build: + wasm-pack-test: + name: "wasm-pack test" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly-2022-11-01 + override: true + - uses: actions/cache@v3 + env: + cache-name: cache-cargo + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - run: wasm-pack test --node + + maturin-build: name: "maturin build" runs-on: ubuntu-latest steps: diff --git a/.github/workflows/playground.yaml b/.github/workflows/playground.yaml new file mode 100644 index 0000000000..ac400e9514 --- /dev/null +++ b/.github/workflows/playground.yaml @@ -0,0 +1,57 @@ +name: Playground + +on: + workflow_dispatch: + push: + branches: [main] + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUSTUP_MAX_RETRIES: 10 + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly-2022-11-01 + override: true + target: wasm32-unknown-unknown + - uses: actions/setup-node@v3 + with: + node-version: 18 + cache: 'npm' + cache-dependency-path: playground/package-lock.json + - uses: actions/cache@v3 + env: + cache-name: cache-cargo + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: "Install wasm-pack" + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: "Run wasm-pack" + run: wasm-pack build --target web --out-dir playground/src/pkg + - name: "Install Node dependencies" + run: npm ci + working-directory: playground + - name: "Build JavaScript bundle" + run: npm run build + working-directory: playground + - name: "Deploy to Cloudflare Pages" + uses: cloudflare/wrangler-action@2.0.0 + with: + apiToken: ${{ secrets.CF_API_TOKEN }} + accountId: ${{ secrets.CF_ACCOUNT_ID }} + workingDirectory: playground + command: pages publish dist --project-name=ruff diff --git a/Cargo.lock b/Cargo.lock index 536b081283..058b0515c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "ascii" @@ -86,7 +86,7 @@ version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3" dependencies = [ - "bstr 1.0.1", + "bstr 1.1.0", "doc-comment", "predicates", "predicates-core", @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" dependencies = [ "memchr", "once_cell", @@ -193,9 +193,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cfg-if" @@ -280,9 +280,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.29" +version = "4.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" +checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ "bitflags", "clap_derive", @@ -295,11 +295,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.6" +version = "4.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da" +checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" dependencies = [ - "clap 4.0.29", + "clap 4.0.32", ] [[package]] @@ -308,7 +308,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4160b4a4f72ef58bd766bad27c09e6ef1cc9d82a22f6a0f55d152985a4a48e31" dependencies = [ - "clap 4.0.29", + "clap 4.0.32", "clap_complete", "clap_complete_fig", ] @@ -319,7 +319,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46b30e010e669cd021e5004f3be26cff6b7c08d2a8a0d65b48d43a8cc0efd6c3" dependencies = [ - "clap 4.0.29", + "clap 4.0.32", "clap_complete", ] @@ -422,6 +422,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -524,9 +544,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "cxx" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf" +checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" dependencies = [ "cc", "cxxbridge-flags", @@ -536,9 +556,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39" +checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" dependencies = [ "cc", "codespan-reporting", @@ -551,15 +571,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12" +checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" [[package]] name = "cxxbridge-macro" -version = "1.0.83" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" +checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" dependencies = [ "proc-macro2", "quote", @@ -712,9 +732,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ "cfg-if 1.0.0", "libc", @@ -733,7 +753,7 @@ name = "flake8-to-ruff" version = "0.0.194-dev.0" dependencies = [ "anyhow", - "clap 4.0.29", + "clap 4.0.32", "configparser", "once_cell", "regex", @@ -952,9 +972,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197f4e300af8b23664d4077bf5c40e0afa9ba66a567bb5a51d3def3c7b287d1c" +checksum = "e48b08a091dfe5b09a6a9688c468fdd5b4396e92ce09e2eb932f0884b02788a4" dependencies = [ "console", "lazy_static", @@ -985,9 +1005,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ "hermit-abi 0.2.6", "io-lifetimes", @@ -1006,9 +1026,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "joinery" @@ -1115,9 +1135,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libcst" @@ -1145,9 +1165,9 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] @@ -1160,9 +1180,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "lock_api" @@ -1340,11 +1360,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi 0.2.6", "libc", ] @@ -1391,9 +1411,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" [[package]] name = "path-absolutize" @@ -1631,9 +1651,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -1663,9 +1683,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -1759,11 +1779,10 @@ dependencies = [ [[package]] name = "rayon" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ - "crossbeam-deque", "either", "rayon-core", ] @@ -1868,12 +1887,15 @@ dependencies = [ "bincode", "bitflags", "cachedir", + "cfg-if 1.0.0", "chrono", - "clap 4.0.29", + "clap 4.0.32", "clap_complete_command", "clearscreen", "colored", "common-path", + "console_error_panic_hook", + "console_log", "criterion", "dirs 4.0.0", "fern", @@ -1884,6 +1906,7 @@ dependencies = [ "ignore", "insta", "itertools", + "js-sys", "libcst", "log", "natord", @@ -1904,6 +1927,7 @@ dependencies = [ "schemars", "semver", "serde", + "serde-wasm-bindgen", "serde_json", "shellexpand", "strum", @@ -1915,6 +1939,8 @@ dependencies = [ "update-informer", "ureq", "walkdir", + "wasm-bindgen", + "wasm-bindgen-test", ] [[package]] @@ -1922,7 +1948,7 @@ name = "ruff_dev" version = "0.0.194" dependencies = [ "anyhow", - "clap 4.0.29", + "clap 4.0.32", "codegen", "itertools", "libcst", @@ -1935,6 +1961,7 @@ dependencies = [ "serde_json", "strum", "strum_macros", + "textwrap", ] [[package]] @@ -1955,9 +1982,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" +checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" dependencies = [ "bitflags", "errno", @@ -2056,15 +2083,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "same-file" @@ -2099,6 +2126,12 @@ dependencies = [ "syn", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.1.0" @@ -2107,9 +2140,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" [[package]] name = "sct" @@ -2129,18 +2162,29 @@ checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" [[package]] name = "serde" -version = "1.0.148" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" dependencies = [ "serde_derive", ] [[package]] -name = "serde_derive" -version = "1.0.148" +name = "serde-wasm-bindgen" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", @@ -2216,9 +2260,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "str_indices" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0" +checksum = "5f026164926842ec52deb1938fae44f83dfdb82d0a5b0270c5bd5935ab74d6dd" [[package]] name = "string_cache" @@ -2263,9 +2307,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -2370,18 +2414,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -2455,9 +2499,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] @@ -2544,9 +2588,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-linebreak" @@ -2715,6 +2759,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.83" @@ -2744,6 +2800,30 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +[[package]] +name = "wasm-bindgen-test" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d2fff962180c3fadf677438054b1db62bee4aa32af26a45388af07d1287e1d" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4683da3dfc016f704c9f82cf401520c4f1cb3ee440f7f52b3d6ac29506a49ca7" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "web-sys" version = "0.3.60" @@ -2766,9 +2846,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] diff --git a/Cargo.toml b/Cargo.toml index 955a583f48..6b2965b8cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ rust-version = "1.65.0" [lib] name = "ruff" +crate-type = ["cdylib", "rlib"] [dependencies] annotate-snippets = { version = "0.9.1", features = ["color"] } @@ -20,9 +21,10 @@ atty = { version = "0.2.14" } bincode = { version = "1.3.3" } bitflags = { version = "1.3.2" } cachedir = { version = "0.3.0" } +cfg-if = { version = "1.0.0" } chrono = { version = "0.4.21", default-features = false, features = ["clock"] } clap = { version = "4.0.1", features = ["derive"] } -clap_complete_command = "0.4.0" +clap_complete_command = { version = "0.4.0" } colored = { version = "2.0.0" } common-path = { version = "1.0.0" } dirs = { version = "4.0.0" } @@ -41,7 +43,6 @@ num-bigint = { version = "0.4.3" } once_cell = { version = "1.16.0" } path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] } quick-junit = { version = "0.3.2" } -rayon = { version = "1.5.3" } regex = { version = "1.6.0" } ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false } ruff_macros = { version = "0.0.194", path = "ruff_macros" } @@ -59,23 +60,32 @@ strum_macros = { version = "0.24.3" } textwrap = { version = "0.16.0" } titlecase = { version = "2.2.1" } toml = { version = "0.5.9" } -update-informer = { version = "0.5.0", default-features = false, features = ["pypi"], optional = true } walkdir = { version = "2.3.2" } [target.'cfg(not(target_family = "wasm"))'.dependencies] -clearscreen = { version = "1.0.10" } # uses which +clearscreen = { version = "1.0.10" } +rayon = { version = "1.5.3" } +update-informer = { version = "0.5.0", default-features = false, features = ["pypi"], optional = true } # https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support # For (future) wasm-pack support [target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies] getrandom = { version = "0.2.7", features = ["js"] } +console_error_panic_hook = { version = "0.1.7" } +console_log = { version = "0.2.0" } +serde-wasm-bindgen = { version = "0.4" } +js-sys = { version = "0.3.60" } +wasm-bindgen = { version = "0.2.83" } [dev-dependencies] -assert_cmd = { version = "2.0.4" } -criterion = { version = "0.4.0" } insta = { version = "1.19.1", features = ["yaml"] } test-case = { version = "2.2.2" } ureq = { version = "2.5.0", features = [] } +wasm-bindgen-test = { version = "0.3.33" } + +[target.'cfg(not(target_family = "wasm"))'.dev-dependencies] +assert_cmd = { version = "2.0.4" } +criterion = { version = "0.4.0" } [features] default = ["update-informer"] @@ -93,6 +103,11 @@ opt-level = 3 [profile.dev.package.similar] opt-level = 3 +# Reduce complexity of a parser function that would trigger a locals limit in a wasm tool. +# https://github.com/bytecodealliance/wasm-tools/blob/b5c3d98e40590512a3b12470ef358d5c7b983b15/crates/wasmparser/src/limits.rs#L29 +[profile.dev.package.rustpython-parser] +opt-level = 1 + [[bench]] name = "source_code_locator" harness = false diff --git a/playground/.gitignore b/playground/.gitignore new file mode 100644 index 0000000000..a547bf36d8 --- /dev/null +++ b/playground/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/playground/index.html b/playground/index.html new file mode 100644 index 0000000000..64adf3868f --- /dev/null +++ b/playground/index.html @@ -0,0 +1,12 @@ + + + + + + Ruff Playground + + +
+ + + diff --git a/playground/package-lock.json b/playground/package-lock.json new file mode 100644 index 0000000000..9fb3a44df1 --- /dev/null +++ b/playground/package-lock.json @@ -0,0 +1,1517 @@ +{ + "name": "playground", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "playground", + "version": "0.0.0", + "dependencies": { + "@monaco-editor/react": "^4.4.6", + "lz-string": "^1.4.4", + "monaco-editor": "^0.34.1", + "prettier": "^2.8.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.9", + "@vitejs/plugin-react-swc": "^3.0.0", + "typescript": "^4.9.3", + "vite": "^4.0.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.9.tgz", + "integrity": "sha512-kW5ccqWHVOOTGUkkJbtfoImtqu3kA1PFkivM+9QPFSHphPfPBlBalX9eDRqPK+wHCqKhU48/78T791qPgC9e9A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.9.tgz", + "integrity": "sha512-ndIAZJUeLx4O+4AJbFQCurQW4VRUXjDsUvt1L+nP8bVELOWdmdCEOtlIweCUE6P+hU0uxYbEK2AEP0n5IVQvhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.9.tgz", + "integrity": "sha512-UbMcJB4EHrAVOnknQklREPgclNU2CPet2h+sCBCXmF2mfoYWopBn/CfTfeyOkb/JglOcdEADqAljFndMKnFtOw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.9.tgz", + "integrity": "sha512-d7D7/nrt4CxPul98lx4PXhyNZwTYtbdaHhOSdXlZuu5zZIznjqtMqLac8Bv+IuT6SVHiHUwrkL6ywD7mOgLW+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.9.tgz", + "integrity": "sha512-LZc+Wlz06AkJYtwWsBM3x2rSqTG8lntDuftsUNQ3fCx9ZttYtvlDcVtgb+NQ6t9s6K5No5zutN3pcjZEC2a4iQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.9.tgz", + "integrity": "sha512-gIj0UQZlQo93CHYouHKkpzP7AuruSaMIm1etcWIxccFEVqCN1xDr6BWlN9bM+ol/f0W9w3hx3HDuEwcJVtGneQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.9.tgz", + "integrity": "sha512-GNors4vaMJ7lzGOuhzNc7jvgsQZqErGA8rsW+nck8N1nYu86CvsJW2seigVrQQWOV4QzEP8Zf3gm+QCjA2hnBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.9.tgz", + "integrity": "sha512-cNx1EF99c2t1Ztn0lk9N+MuwBijGF8mH6nx9GFsB3e0lpUpPkCE/yt5d+7NP9EwJf5uzqdjutgVYoH1SNqzudA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.9.tgz", + "integrity": "sha512-YPxQunReYp8RQ1FvexFrOEqqf+nLbS3bKVZF5FRT2uKM7Wio7BeATqAwO02AyrdSEntt3I5fhFsujUChIa8CZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.9.tgz", + "integrity": "sha512-zb12ixDIKNwFpIqR00J88FFitVwOEwO78EiUi8wi8FXlmSc3GtUuKV/BSO+730Kglt0B47+ZrJN1BhhOxZaVrw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.9.tgz", + "integrity": "sha512-X8te4NLxtHiNT6H+4Pfm5RklzItA1Qy4nfyttihGGX+Koc53Ar20ViC+myY70QJ8PDEOehinXZj/F7QK3A+MKQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.9.tgz", + "integrity": "sha512-ZqyMDLt02c5smoS3enlF54ndK5zK4IpClLTxF0hHfzHJlfm4y8IAkIF8LUW0W7zxcKy7oAwI7BRDqeVvC120SA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.9.tgz", + "integrity": "sha512-k+ca5W5LDBEF3lfDwMV6YNXwm4wEpw9krMnNvvlNz3MrKSD2Eb2c861O0MaKrZkG/buTQAP4vkavbLwgIe6xjg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.9.tgz", + "integrity": "sha512-GuInVdogjmg9DhgkEmNipHkC+3tzkanPJzgzTC2ihsvrruLyFoR1YrTGixblNSMPudQLpiqkcwGwwe0oqfrvfA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.9.tgz", + "integrity": "sha512-49wQ0aYkvwXonGsxc7LuuLNICMX8XtO92Iqmug5Qau0kpnV6SP34jk+jIeu4suHwAbSbRhVFtDv75yRmyfQcHw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.9.tgz", + "integrity": "sha512-Nx4oKEAJ6EcQlt4dK7qJyuZUoXZG7CAeY22R7rqZijFzwFfMOD+gLP56uV7RrV86jGf8PeRY8TBsRmOcZoG42w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.9.tgz", + "integrity": "sha512-d0WnpgJ+FTiMZXEQ1NOv9+0gvEhttbgKEvVqWWAtl1u9AvlspKXbodKHzQ5MLP6YV1y52Xp+p8FMYqj8ykTahg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.9.tgz", + "integrity": "sha512-jccK11278dvEscHFfMk5EIPjF4wv1qGD0vps7mBV1a6TspdR36O28fgPem/SA/0pcsCPHjww5ouCLwP+JNAFlw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.9.tgz", + "integrity": "sha512-OetwTSsv6mIDLqN7I7I2oX9MmHGwG+AP+wKIHvq+6sIHwcPPJqRx+DJB55jy9JG13CWcdcQno/7V5MTJ5a0xfQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.9.tgz", + "integrity": "sha512-tKSSSK6unhxbGbHg+Cc+JhRzemkcsX0tPBvG0m5qsWbkShDK9c+/LSb13L18LWVdOQZwuA55Vbakxmt6OjBDOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.9.tgz", + "integrity": "sha512-ZTQ5vhNS5gli0KK8I6/s6+LwXmNEfq1ftjnSVyyNm33dBw8zDpstqhGXYUbZSWWLvkqiRRjgxgmoncmi6Yy7Ng==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.9.tgz", + "integrity": "sha512-C4ZX+YFIp6+lPrru3tpH6Gaapy8IBRHw/e7l63fzGDhn/EaiGpQgbIlT5paByyy+oMvRFQoxxyvC4LE0AjJMqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@monaco-editor/loader": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.3.2.tgz", + "integrity": "sha512-BTDbpHl3e47r3AAtpfVFTlAi7WXv4UQ/xZmz8atKl4q7epQV5e7+JbigFDViWF71VBi4IIBdcWP57Hj+OWuc9g==", + "dependencies": { + "state-local": "^1.0.6" + }, + "peerDependencies": { + "monaco-editor": ">= 0.21.0 < 1" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.4.6.tgz", + "integrity": "sha512-Gr3uz3LYf33wlFE3eRnta4RxP5FSNxiIV9ENn2D2/rN8KgGAD8ecvcITRtsbbyuOuNkwbuHYxfeaz2Vr+CtyFA==", + "dependencies": { + "@monaco-editor/loader": "^1.3.2", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@swc/core": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.23.tgz", + "integrity": "sha512-Aa7yw5+7ErOxr+G0J1eU2hkb9nEMSdt1Ye3isdAgg9mrsPuttk+cfLp6nP/Lux/VUnu5k4eOxeTy9UhjJhRAFw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "swcx": "run_swcx.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.23", + "@swc/core-darwin-x64": "1.3.23", + "@swc/core-linux-arm-gnueabihf": "1.3.23", + "@swc/core-linux-arm64-gnu": "1.3.23", + "@swc/core-linux-arm64-musl": "1.3.23", + "@swc/core-linux-x64-gnu": "1.3.23", + "@swc/core-linux-x64-musl": "1.3.23", + "@swc/core-win32-arm64-msvc": "1.3.23", + "@swc/core-win32-ia32-msvc": "1.3.23", + "@swc/core-win32-x64-msvc": "1.3.23" + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.23.tgz", + "integrity": "sha512-IGOEHmE4aBDX7gQWpanI3A0ni47UcvX7rmcy0H8kE6mm/y7mEMWskvNsYhYzJl4GVZgw38v1/lL/A7MRX6g71A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.23.tgz", + "integrity": "sha512-eQSN+JJqx/5Dk2C5uet2l7HifGsDBorQHD3PAVnge5jxl+rXU/zbzX9Un56+uuUB0QYeS4Dyr8cN7NHuIKGxBA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.23.tgz", + "integrity": "sha512-zxYvggbw6R/sTNey0qgsigFMY59DYepm1+JNojxOKjbnvxmgyeIa5sPdu/5gLj0TtJOiWvSGrpMPNUIVreUSGA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.23.tgz", + "integrity": "sha512-l8UWhcNvZ6RzNZBBToMYuKYijF0h7mbw2RuFV5rpCYF/k/Wh85PaDHPQIQ6qjMHJsIBHYXUt0HLAP+fiAfBiDw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.23.tgz", + "integrity": "sha512-TZDPp1wUE1ynVyY0vwIToyOULKEQ91H49R+p6Iu/2YY+UQQwUamhX0Gp8O85RT+j72/iHyhbQkz7yRg6v+GB5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.23.tgz", + "integrity": "sha512-rKqWnOmUyQfoKZuuXs/S0RNobN+kcUyMtwoCdRdCNqOlk1XZRCMpjGc9Aqn73K3xlZ6JXX6oLrXKn375b2dydw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.23.tgz", + "integrity": "sha512-1MK9eocIhuIr/+yUKnTNHpYovMQvfKTJQbU4UMfQLg2qyCGKAvO+jOy5JIGR9x04MWqz9U3EHHS/7Id35ekhFQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.23.tgz", + "integrity": "sha512-3nmdugj0SJIGWeCJBhvPWIfnE2Ax8H2KZsJfcaWmWg0SDh19aAt48Ncyd8WHHBandJmVm2fSjaANSjp+cS2S9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.23.tgz", + "integrity": "sha512-2AlGRhys1BsfLjXyWOd+5J/Ko2kkVQVuy3ZR8OBGy7XI54p0PpepabloYI9irr+4bi9vtyxoc5rS21PmJxB83Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.23.tgz", + "integrity": "sha512-qYKP8sIM7VVLuDb5BkRBoHy28OHZWrUhPTO7WgpErhVVM9wnzmMi/Jgg8SyfMy6oheBjO0QiwWbXONxBwByjnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.0.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", + "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.9.tgz", + "integrity": "sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.0.1.tgz", + "integrity": "sha512-3GQ2oruZO9j8dSHcI0MUeOZQBhjYyDQsF/pKY4Px+CJxn0M16OhgFeEzUjeuwci4zhhjoNIDE9aFNaV5GMQ09g==", + "dev": true, + "dependencies": { + "@swc/core": "^1.3.22" + }, + "peerDependencies": { + "vite": "^4" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.9.tgz", + "integrity": "sha512-gkH83yHyijMSZcZFs1IWew342eMdFuWXmQo3zkDPTre25LIPBJsXryg02M3u8OpTwCJdBkdaQwqKkDLnAsAeLQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.9", + "@esbuild/android-arm64": "0.16.9", + "@esbuild/android-x64": "0.16.9", + "@esbuild/darwin-arm64": "0.16.9", + "@esbuild/darwin-x64": "0.16.9", + "@esbuild/freebsd-arm64": "0.16.9", + "@esbuild/freebsd-x64": "0.16.9", + "@esbuild/linux-arm": "0.16.9", + "@esbuild/linux-arm64": "0.16.9", + "@esbuild/linux-ia32": "0.16.9", + "@esbuild/linux-loong64": "0.16.9", + "@esbuild/linux-mips64el": "0.16.9", + "@esbuild/linux-ppc64": "0.16.9", + "@esbuild/linux-riscv64": "0.16.9", + "@esbuild/linux-s390x": "0.16.9", + "@esbuild/linux-x64": "0.16.9", + "@esbuild/netbsd-x64": "0.16.9", + "@esbuild/openbsd-x64": "0.16.9", + "@esbuild/sunos-x64": "0.16.9", + "@esbuild/win32-arm64": "0.16.9", + "@esbuild/win32-ia32": "0.16.9", + "@esbuild/win32-x64": "0.16.9" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/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/lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/monaco-editor": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.34.1.tgz", + "integrity": "sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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/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==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "dev": true, + "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/prettier": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", + "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "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/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": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.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/rollup": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz", + "integrity": "sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + }, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/vite": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.1.tgz", + "integrity": "sha512-kZQPzbDau35iWOhy3CpkrRC7It+HIHtulAzBhMqzGHKRf/4+vmh8rPDDdv98SWQrFWo6//3ozwsRmwQIPZsK9g==", + "dev": true, + "dependencies": { + "esbuild": "^0.16.3", + "postcss": "^8.4.20", + "resolve": "^1.22.1", + "rollup": "^3.7.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + } + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.9.tgz", + "integrity": "sha512-kW5ccqWHVOOTGUkkJbtfoImtqu3kA1PFkivM+9QPFSHphPfPBlBalX9eDRqPK+wHCqKhU48/78T791qPgC9e9A==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.9.tgz", + "integrity": "sha512-ndIAZJUeLx4O+4AJbFQCurQW4VRUXjDsUvt1L+nP8bVELOWdmdCEOtlIweCUE6P+hU0uxYbEK2AEP0n5IVQvhg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.9.tgz", + "integrity": "sha512-UbMcJB4EHrAVOnknQklREPgclNU2CPet2h+sCBCXmF2mfoYWopBn/CfTfeyOkb/JglOcdEADqAljFndMKnFtOw==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.9.tgz", + "integrity": "sha512-d7D7/nrt4CxPul98lx4PXhyNZwTYtbdaHhOSdXlZuu5zZIznjqtMqLac8Bv+IuT6SVHiHUwrkL6ywD7mOgLW+A==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.9.tgz", + "integrity": "sha512-LZc+Wlz06AkJYtwWsBM3x2rSqTG8lntDuftsUNQ3fCx9ZttYtvlDcVtgb+NQ6t9s6K5No5zutN3pcjZEC2a4iQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.9.tgz", + "integrity": "sha512-gIj0UQZlQo93CHYouHKkpzP7AuruSaMIm1etcWIxccFEVqCN1xDr6BWlN9bM+ol/f0W9w3hx3HDuEwcJVtGneQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.9.tgz", + "integrity": "sha512-GNors4vaMJ7lzGOuhzNc7jvgsQZqErGA8rsW+nck8N1nYu86CvsJW2seigVrQQWOV4QzEP8Zf3gm+QCjA2hnBQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.9.tgz", + "integrity": "sha512-cNx1EF99c2t1Ztn0lk9N+MuwBijGF8mH6nx9GFsB3e0lpUpPkCE/yt5d+7NP9EwJf5uzqdjutgVYoH1SNqzudA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.9.tgz", + "integrity": "sha512-YPxQunReYp8RQ1FvexFrOEqqf+nLbS3bKVZF5FRT2uKM7Wio7BeATqAwO02AyrdSEntt3I5fhFsujUChIa8CZg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.9.tgz", + "integrity": "sha512-zb12ixDIKNwFpIqR00J88FFitVwOEwO78EiUi8wi8FXlmSc3GtUuKV/BSO+730Kglt0B47+ZrJN1BhhOxZaVrw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.9.tgz", + "integrity": "sha512-X8te4NLxtHiNT6H+4Pfm5RklzItA1Qy4nfyttihGGX+Koc53Ar20ViC+myY70QJ8PDEOehinXZj/F7QK3A+MKQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.9.tgz", + "integrity": "sha512-ZqyMDLt02c5smoS3enlF54ndK5zK4IpClLTxF0hHfzHJlfm4y8IAkIF8LUW0W7zxcKy7oAwI7BRDqeVvC120SA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.9.tgz", + "integrity": "sha512-k+ca5W5LDBEF3lfDwMV6YNXwm4wEpw9krMnNvvlNz3MrKSD2Eb2c861O0MaKrZkG/buTQAP4vkavbLwgIe6xjg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.9.tgz", + "integrity": "sha512-GuInVdogjmg9DhgkEmNipHkC+3tzkanPJzgzTC2ihsvrruLyFoR1YrTGixblNSMPudQLpiqkcwGwwe0oqfrvfA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.9.tgz", + "integrity": "sha512-49wQ0aYkvwXonGsxc7LuuLNICMX8XtO92Iqmug5Qau0kpnV6SP34jk+jIeu4suHwAbSbRhVFtDv75yRmyfQcHw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.9.tgz", + "integrity": "sha512-Nx4oKEAJ6EcQlt4dK7qJyuZUoXZG7CAeY22R7rqZijFzwFfMOD+gLP56uV7RrV86jGf8PeRY8TBsRmOcZoG42w==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.9.tgz", + "integrity": "sha512-d0WnpgJ+FTiMZXEQ1NOv9+0gvEhttbgKEvVqWWAtl1u9AvlspKXbodKHzQ5MLP6YV1y52Xp+p8FMYqj8ykTahg==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.9.tgz", + "integrity": "sha512-jccK11278dvEscHFfMk5EIPjF4wv1qGD0vps7mBV1a6TspdR36O28fgPem/SA/0pcsCPHjww5ouCLwP+JNAFlw==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.9.tgz", + "integrity": "sha512-OetwTSsv6mIDLqN7I7I2oX9MmHGwG+AP+wKIHvq+6sIHwcPPJqRx+DJB55jy9JG13CWcdcQno/7V5MTJ5a0xfQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.9.tgz", + "integrity": "sha512-tKSSSK6unhxbGbHg+Cc+JhRzemkcsX0tPBvG0m5qsWbkShDK9c+/LSb13L18LWVdOQZwuA55Vbakxmt6OjBDOQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.9.tgz", + "integrity": "sha512-ZTQ5vhNS5gli0KK8I6/s6+LwXmNEfq1ftjnSVyyNm33dBw8zDpstqhGXYUbZSWWLvkqiRRjgxgmoncmi6Yy7Ng==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.9.tgz", + "integrity": "sha512-C4ZX+YFIp6+lPrru3tpH6Gaapy8IBRHw/e7l63fzGDhn/EaiGpQgbIlT5paByyy+oMvRFQoxxyvC4LE0AjJMqQ==", + "dev": true, + "optional": true + }, + "@monaco-editor/loader": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.3.2.tgz", + "integrity": "sha512-BTDbpHl3e47r3AAtpfVFTlAi7WXv4UQ/xZmz8atKl4q7epQV5e7+JbigFDViWF71VBi4IIBdcWP57Hj+OWuc9g==", + "requires": { + "state-local": "^1.0.6" + } + }, + "@monaco-editor/react": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.4.6.tgz", + "integrity": "sha512-Gr3uz3LYf33wlFE3eRnta4RxP5FSNxiIV9ENn2D2/rN8KgGAD8ecvcITRtsbbyuOuNkwbuHYxfeaz2Vr+CtyFA==", + "requires": { + "@monaco-editor/loader": "^1.3.2", + "prop-types": "^15.7.2" + } + }, + "@swc/core": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.23.tgz", + "integrity": "sha512-Aa7yw5+7ErOxr+G0J1eU2hkb9nEMSdt1Ye3isdAgg9mrsPuttk+cfLp6nP/Lux/VUnu5k4eOxeTy9UhjJhRAFw==", + "dev": true, + "requires": { + "@swc/core-darwin-arm64": "1.3.23", + "@swc/core-darwin-x64": "1.3.23", + "@swc/core-linux-arm-gnueabihf": "1.3.23", + "@swc/core-linux-arm64-gnu": "1.3.23", + "@swc/core-linux-arm64-musl": "1.3.23", + "@swc/core-linux-x64-gnu": "1.3.23", + "@swc/core-linux-x64-musl": "1.3.23", + "@swc/core-win32-arm64-msvc": "1.3.23", + "@swc/core-win32-ia32-msvc": "1.3.23", + "@swc/core-win32-x64-msvc": "1.3.23" + } + }, + "@swc/core-darwin-arm64": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.23.tgz", + "integrity": "sha512-IGOEHmE4aBDX7gQWpanI3A0ni47UcvX7rmcy0H8kE6mm/y7mEMWskvNsYhYzJl4GVZgw38v1/lL/A7MRX6g71A==", + "dev": true, + "optional": true + }, + "@swc/core-darwin-x64": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.23.tgz", + "integrity": "sha512-eQSN+JJqx/5Dk2C5uet2l7HifGsDBorQHD3PAVnge5jxl+rXU/zbzX9Un56+uuUB0QYeS4Dyr8cN7NHuIKGxBA==", + "dev": true, + "optional": true + }, + "@swc/core-linux-arm-gnueabihf": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.23.tgz", + "integrity": "sha512-zxYvggbw6R/sTNey0qgsigFMY59DYepm1+JNojxOKjbnvxmgyeIa5sPdu/5gLj0TtJOiWvSGrpMPNUIVreUSGA==", + "dev": true, + "optional": true + }, + "@swc/core-linux-arm64-gnu": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.23.tgz", + "integrity": "sha512-l8UWhcNvZ6RzNZBBToMYuKYijF0h7mbw2RuFV5rpCYF/k/Wh85PaDHPQIQ6qjMHJsIBHYXUt0HLAP+fiAfBiDw==", + "dev": true, + "optional": true + }, + "@swc/core-linux-arm64-musl": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.23.tgz", + "integrity": "sha512-TZDPp1wUE1ynVyY0vwIToyOULKEQ91H49R+p6Iu/2YY+UQQwUamhX0Gp8O85RT+j72/iHyhbQkz7yRg6v+GB5A==", + "dev": true, + "optional": true + }, + "@swc/core-linux-x64-gnu": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.23.tgz", + "integrity": "sha512-rKqWnOmUyQfoKZuuXs/S0RNobN+kcUyMtwoCdRdCNqOlk1XZRCMpjGc9Aqn73K3xlZ6JXX6oLrXKn375b2dydw==", + "dev": true, + "optional": true + }, + "@swc/core-linux-x64-musl": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.23.tgz", + "integrity": "sha512-1MK9eocIhuIr/+yUKnTNHpYovMQvfKTJQbU4UMfQLg2qyCGKAvO+jOy5JIGR9x04MWqz9U3EHHS/7Id35ekhFQ==", + "dev": true, + "optional": true + }, + "@swc/core-win32-arm64-msvc": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.23.tgz", + "integrity": "sha512-3nmdugj0SJIGWeCJBhvPWIfnE2Ax8H2KZsJfcaWmWg0SDh19aAt48Ncyd8WHHBandJmVm2fSjaANSjp+cS2S9A==", + "dev": true, + "optional": true + }, + "@swc/core-win32-ia32-msvc": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.23.tgz", + "integrity": "sha512-2AlGRhys1BsfLjXyWOd+5J/Ko2kkVQVuy3ZR8OBGy7XI54p0PpepabloYI9irr+4bi9vtyxoc5rS21PmJxB83Q==", + "dev": true, + "optional": true + }, + "@swc/core-win32-x64-msvc": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.23.tgz", + "integrity": "sha512-qYKP8sIM7VVLuDb5BkRBoHy28OHZWrUhPTO7WgpErhVVM9wnzmMi/Jgg8SyfMy6oheBjO0QiwWbXONxBwByjnQ==", + "dev": true, + "optional": true + }, + "@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==", + "dev": true + }, + "@types/react": { + "version": "18.0.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", + "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.9.tgz", + "integrity": "sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, + "@vitejs/plugin-react-swc": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.0.1.tgz", + "integrity": "sha512-3GQ2oruZO9j8dSHcI0MUeOZQBhjYyDQsF/pKY4Px+CJxn0M16OhgFeEzUjeuwci4zhhjoNIDE9aFNaV5GMQ09g==", + "dev": true, + "requires": { + "@swc/core": "^1.3.22" + } + }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "esbuild": { + "version": "0.16.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.9.tgz", + "integrity": "sha512-gkH83yHyijMSZcZFs1IWew342eMdFuWXmQo3zkDPTre25LIPBJsXryg02M3u8OpTwCJdBkdaQwqKkDLnAsAeLQ==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.16.9", + "@esbuild/android-arm64": "0.16.9", + "@esbuild/android-x64": "0.16.9", + "@esbuild/darwin-arm64": "0.16.9", + "@esbuild/darwin-x64": "0.16.9", + "@esbuild/freebsd-arm64": "0.16.9", + "@esbuild/freebsd-x64": "0.16.9", + "@esbuild/linux-arm": "0.16.9", + "@esbuild/linux-arm64": "0.16.9", + "@esbuild/linux-ia32": "0.16.9", + "@esbuild/linux-loong64": "0.16.9", + "@esbuild/linux-mips64el": "0.16.9", + "@esbuild/linux-ppc64": "0.16.9", + "@esbuild/linux-riscv64": "0.16.9", + "@esbuild/linux-s390x": "0.16.9", + "@esbuild/linux-x64": "0.16.9", + "@esbuild/netbsd-x64": "0.16.9", + "@esbuild/openbsd-x64": "0.16.9", + "@esbuild/sunos-x64": "0.16.9", + "@esbuild/win32-arm64": "0.16.9", + "@esbuild/win32-ia32": "0.16.9", + "@esbuild/win32-x64": "0.16.9" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "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==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==" + }, + "monaco-editor": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.34.1.tgz", + "integrity": "sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "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==" + }, + "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==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "prettier": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", + "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==" + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "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==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "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==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "rollup": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz", + "integrity": "sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "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==", + "dev": true + }, + "state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + }, + "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==", + "dev": true + }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true + }, + "vite": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.1.tgz", + "integrity": "sha512-kZQPzbDau35iWOhy3CpkrRC7It+HIHtulAzBhMqzGHKRf/4+vmh8rPDDdv98SWQrFWo6//3ozwsRmwQIPZsK9g==", + "dev": true, + "requires": { + "esbuild": "^0.16.3", + "fsevents": "~2.3.2", + "postcss": "^8.4.20", + "resolve": "^1.22.1", + "rollup": "^3.7.0" + } + } + } +} diff --git a/playground/package.json b/playground/package.json new file mode 100644 index 0000000000..08adeaeb54 --- /dev/null +++ b/playground/package.json @@ -0,0 +1,27 @@ +{ + "name": "playground", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "push": "wrangler pages publish dist --project-name=ruff" + }, + "dependencies": { + "@monaco-editor/react": "^4.4.6", + "lz-string": "^1.4.4", + "monaco-editor": "^0.34.1", + "prettier": "^2.8.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.0.26", + "@types/react-dom": "^18.0.9", + "@vitejs/plugin-react-swc": "^3.0.0", + "typescript": "^4.9.3", + "vite": "^4.0.0" + } +} diff --git a/playground/src/App.tsx b/playground/src/App.tsx new file mode 100644 index 0000000000..8c4fc883b2 --- /dev/null +++ b/playground/src/App.tsx @@ -0,0 +1,141 @@ +import lzstring from "lz-string"; +import Editor, { useMonaco } from "@monaco-editor/react"; +import { MarkerSeverity } from "monaco-editor/esm/vs/editor/editor.api"; +import { useEffect, useState, useCallback } from "react"; + +// @ts-ignore +import init, { Check, check } from "./pkg/ruff.js"; +import { AVAILABLE_OPTIONS } from "./ruff_options"; +import { Config, getDefaultConfig, toRuffConfig } from "./config"; +import { Options } from "./Options"; + +const DEFAULT_SOURCE = "print(1 + 2)"; + +function restoreConfigAndSource(): [Config, string] { + let value = lzstring.decompressFromEncodedURIComponent( + window.location.hash.slice(1) + ); + let config = {}; + let source = DEFAULT_SOURCE; + + if (value) { + let parts = value.split("$$$"); + config = JSON.parse(parts[0]); + source = parts[1]; + } + + return [config, source]; +} + +function persistConfigAndSource(config: Config, source: string) { + window.location.hash = lzstring.compressToEncodedURIComponent( + JSON.stringify(config) + "$$$" + source + ); +} + +const defaultConfig = getDefaultConfig(AVAILABLE_OPTIONS); + +export default function App() { + const monaco = useMonaco(); + const [ruffInitialized, setRuffInitialized] = useState(false); + const [config, setConfig] = useState(null); + const [source, setSource] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + init().then(() => setRuffInitialized(true)); + }, []); + + useEffect(() => { + if (source === null && config === null && monaco) { + let [config, source] = restoreConfigAndSource(); + setConfig(config); + setSource(source); + } + }, [monaco, source, config]); + + useEffect(() => { + if (config != null && source != null) { + persistConfigAndSource(config, source); + } + }, [config, source]); + + useEffect(() => { + let editor = monaco?.editor; + let model = editor?.getModels()[0]; + if ( + !editor || + !model || + !ruffInitialized || + source === null || + config === null + ) { + return; + } + + let checks: Check[]; + try { + checks = check(source, toRuffConfig(config)); + setError(null); + } catch (e) { + setError(String(e)); + return; + } + + editor.setModelMarkers( + model, + "owner", + checks.map((check) => ({ + startLineNumber: check.location.row, + startColumn: check.location.column + 1, + endLineNumber: check.end_location.row, + endColumn: check.end_location.column + 1, + message: `${check.code}: ${check.message}`, + severity: MarkerSeverity.Error, + })) + ); + }, [config, source, monaco, ruffInitialized]); + + const handleEditorChange = useCallback( + (value: string | undefined) => { + value && setSource(value); + }, + [setSource] + ); + + const handleOptionChange = useCallback( + (groupName: string, fieldName: string, value: string) => { + let group = Object.assign({}, (config || {})[groupName]); + if (value === defaultConfig[groupName][fieldName] || value === "") { + delete group[fieldName]; + } else { + group[fieldName] = value; + } + + setConfig({ + ...config, + [groupName]: group, + }); + }, + [config] + ); + + return ( +
+ + + {error &&
{error}
} +
+ ); +} diff --git a/playground/src/Options.tsx b/playground/src/Options.tsx new file mode 100644 index 0000000000..375d04429f --- /dev/null +++ b/playground/src/Options.tsx @@ -0,0 +1,72 @@ +import { Config } from "./config"; +import { AVAILABLE_OPTIONS } from "./ruff_options"; + +function OptionEntry({ + config, + defaultConfig, + groupName, + fieldName, + onChange, +}: { + config: Config | null; + defaultConfig: Config; + groupName: string; + fieldName: string; + onChange: (groupName: string, fieldName: string, value: string) => void; +}) { + const value = + config && config[groupName] && config[groupName][fieldName] + ? config[groupName][fieldName] + : ""; + + return ( + + + + ); +} + +export function Options({ + config, + defaultConfig, + onChange, +}: { + config: Config | null; + defaultConfig: Config; + onChange: (groupName: string, fieldName: string, value: string) => void; +}) { + return ( +
+ {AVAILABLE_OPTIONS.map((group) => ( +
+ {group.name} +
+
    + {group.fields.map((field) => ( +
  • + +
  • + ))} +
+
+
+ ))} +
+ ); +} diff --git a/playground/src/config.ts b/playground/src/config.ts new file mode 100644 index 0000000000..82573bc87d --- /dev/null +++ b/playground/src/config.ts @@ -0,0 +1,52 @@ +import { OptionGroup } from "./ruff_options"; + +export type Config = { [key: string]: { [key: string]: string } }; + +export function getDefaultConfig(availableOptions: OptionGroup[]): Config { + const config: Config = {}; + availableOptions.forEach((group) => { + config[group.name] = {}; + group.fields.forEach((f) => { + config[group.name][f.name] = f.default; + }); + }); + return config; +} + +/** + * Convert the config in the application to something Ruff accepts. + * + * Application config is always nested one level. Ruff allows for some + * top-level options. + * + * Any option value is parsed as JSON to convert it to a native JS object. + * If that fails, e.g. while a user is typing, we let the application handle that + * and show an error. + */ +export function toRuffConfig(config: Config): any { + const convertValue = (value: string): any => { + return value === "None" ? null : JSON.parse(value); + }; + + let result: any = {}; + Object.keys(config).forEach((group_name) => { + let fields = config[group_name]; + if (!fields || Object.keys(fields).length === 0) { + return; + } + + if (group_name === "globals") { + Object.keys(fields).forEach((field_name) => { + result[field_name] = convertValue(fields[field_name]); + }); + } else { + result[group_name] = {}; + + Object.keys(fields).forEach((field_name) => { + result[group_name][field_name] = convertValue(fields[field_name]); + }); + } + }); + + return result; +} diff --git a/playground/src/custom.d.ts b/playground/src/custom.d.ts new file mode 100644 index 0000000000..29a97b8ece --- /dev/null +++ b/playground/src/custom.d.ts @@ -0,0 +1,6 @@ +declare module "lz-string" { + function decompressFromEncodedURIComponent( + input: string | null + ): string | null; + function compressToEncodedURIComponent(input: string | null): string; +} diff --git a/playground/src/main.tsx b/playground/src/main.tsx new file mode 100644 index 0000000000..7d6d78e120 --- /dev/null +++ b/playground/src/main.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./style.css"; + +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + +); diff --git a/playground/src/ruff_options.ts b/playground/src/ruff_options.ts new file mode 100644 index 0000000000..4f66dab44c --- /dev/null +++ b/playground/src/ruff_options.ts @@ -0,0 +1,222 @@ + +// This file is auto-generated by `cargo dev generate-playground-options`. +export interface OptionGroup { + name: string; + fields: { + name: string; + default: string; + type: string; + }[]; +}; + +export const AVAILABLE_OPTIONS: OptionGroup[] = [ + {"name": "globals", "fields": [ + { + "name": "allowed-confusables", + "default": '[]', + "type": 'Vec', + }, + { + "name": "dummy-variable-rgx", + "default": '"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"', + "type": 'Regex', + }, + { + "name": "extend-ignore", + "default": '[]', + "type": 'Vec', + }, + { + "name": "extend-select", + "default": '[]', + "type": 'Vec', + }, + { + "name": "external", + "default": '[]', + "type": 'Vec', + }, + { + "name": "fix-only", + "default": 'false', + "type": 'bool', + }, + { + "name": "ignore", + "default": '[]', + "type": 'Vec', + }, + { + "name": "line-length", + "default": '88', + "type": 'usize', + }, + { + "name": "required-version", + "default": 'None', + "type": 'String', + }, + { + "name": "select", + "default": '["E", "F"]', + "type": 'Vec', + }, + { + "name": "target-version", + "default": '"py310"', + "type": 'PythonVersion', + }, + { + "name": "unfixable", + "default": '[]', + "type": 'Vec', + }, + ]}, + {"name": "flake8-annotations", "fields": [ + { + "name": "allow-star-arg-any", + "default": 'false', + "type": 'bool', + }, + { + "name": "mypy-init-return", + "default": 'false', + "type": 'bool', + }, + { + "name": "suppress-dummy-args", + "default": 'false', + "type": 'bool', + }, + { + "name": "suppress-none-returning", + "default": 'false', + "type": 'bool', + }, + ]}, + {"name": "flake8-bugbear", "fields": [ + { + "name": "extend-immutable-calls", + "default": '[]', + "type": 'Vec', + }, + ]}, + {"name": "flake8-errmsg", "fields": [ + { + "name": "max-string-length", + "default": '0', + "type": 'usize', + }, + ]}, + {"name": "flake8-import-conventions", "fields": [ + { + "name": "aliases", + "default": '{"altair": "alt", "matplotlib.pyplot": "plt", "numpy": "np", "pandas": "pd", "seaborn": "sns"}', + "type": 'FxHashMap', + }, + { + "name": "extend-aliases", + "default": '{}', + "type": 'FxHashMap', + }, + ]}, + {"name": "flake8-quotes", "fields": [ + { + "name": "avoid-escape", + "default": 'true', + "type": 'bool', + }, + { + "name": "docstring-quotes", + "default": '"double"', + "type": 'Quote', + }, + { + "name": "inline-quotes", + "default": '"double"', + "type": 'Quote', + }, + { + "name": "multiline-quotes", + "default": '"double"', + "type": 'Quote', + }, + ]}, + {"name": "flake8-tidy-imports", "fields": [ + { + "name": "ban-relative-imports", + "default": '"parents"', + "type": 'Strictness', + }, + ]}, + {"name": "flake8-unused-arguments", "fields": [ + { + "name": "ignore-variadic-names", + "default": 'false', + "type": 'bool', + }, + ]}, + {"name": "isort", "fields": [ + { + "name": "combine-as-imports", + "default": 'false', + "type": 'bool', + }, + { + "name": "extra-standard-library", + "default": '[]', + "type": 'Vec', + }, + { + "name": "force-wrap-aliases", + "default": 'false', + "type": 'bool', + }, + { + "name": "known-first-party", + "default": '[]', + "type": 'Vec', + }, + { + "name": "known-third-party", + "default": '[]', + "type": 'Vec', + }, + { + "name": "split-on-trailing-comma", + "default": 'true', + "type": 'bool', + }, + ]}, + {"name": "mccabe", "fields": [ + { + "name": "max-complexity", + "default": '10', + "type": 'usize', + }, + ]}, + {"name": "pep8-naming", "fields": [ + { + "name": "classmethod-decorators", + "default": '["classmethod"]', + "type": 'Vec', + }, + { + "name": "ignore-names", + "default": '["setUp", "tearDown", "setUpClass", "tearDownClass", "setUpModule", "tearDownModule", "asyncSetUp", "asyncTearDown", "setUpTestData", "failureException", "longMessage", "maxDiff"]', + "type": 'Vec', + }, + { + "name": "staticmethod-decorators", + "default": '["staticmethod"]', + "type": 'Vec', + }, + ]}, + {"name": "pyupgrade", "fields": [ + { + "name": "keep-runtime-typing", + "default": 'false', + "type": 'bool', + }, + ]}, +]; \ No newline at end of file diff --git a/playground/src/style.css b/playground/src/style.css new file mode 100644 index 0000000000..da649ebfc2 --- /dev/null +++ b/playground/src/style.css @@ -0,0 +1,60 @@ +* { + box-sizing: border-box; +} + +body, +html, +#root, +#app { + margin: 0; + height: 100%; + width: 100%; +} + +#app { + display: flex; +} + +.options { + height: 100vh; + overflow-y: scroll; + padding: 1em; + min-width: 300px; + border-right: 1px solid lightgray; +} + +.options ul { + padding-left: 1em; + list-style-type: none; +} + +.options li { + margin-bottom: 0.3em; +} + +.options details { + margin-bottom: 1em; +} + +.options summary { + font-size: 1.3rem; +} + +.options input { + display: block; + width: 100%; +} + +.editor { + padding: 1em; +} + +#error { + position: fixed; + bottom: 0; + width: 100%; + min-height: 1em; + padding: 1em; + background: darkred; + color: white; +} diff --git a/playground/src/vite-env.d.ts b/playground/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/playground/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/playground/tsconfig.json b/playground/tsconfig.json new file mode 100644 index 0000000000..3d0a51a86e --- /dev/null +++ b/playground/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/playground/tsconfig.node.json b/playground/tsconfig.node.json new file mode 100644 index 0000000000..9d31e2aed9 --- /dev/null +++ b/playground/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/playground/vite.config.ts b/playground/vite.config.ts new file mode 100644 index 0000000000..d366e8c8d7 --- /dev/null +++ b/playground/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/ruff_dev/Cargo.toml b/ruff_dev/Cargo.toml index 7f413b0c5d..1b5259d93a 100644 --- a/ruff_dev/Cargo.toml +++ b/ruff_dev/Cargo.toml @@ -18,3 +18,4 @@ schemars = { version = "0.8.11" } serde_json = {version="1.0.91"} strum = { version = "0.24.1", features = ["strum_macros"] } strum_macros = { version = "0.24.3" } +textwrap = { version = "0.16.0" } diff --git a/ruff_dev/src/generate_playground_options.rs b/ruff_dev/src/generate_playground_options.rs new file mode 100644 index 0000000000..759c2fc5e6 --- /dev/null +++ b/ruff_dev/src/generate_playground_options.rs @@ -0,0 +1,142 @@ +//! Generate typescript file defining options to be used by the web playground. + +use std::fs::OpenOptions; +use std::io::Write; +use std::path::PathBuf; + +use anyhow::Result; +use clap::Args; +use itertools::Itertools; +use ruff::settings::options::Options; +use ruff::settings::options_base::{ConfigurationOptions, OptionEntry, OptionField}; + +#[derive(Args)] +pub struct Cli { + /// Write the generated table to stdout (rather than to `TODO`). + #[arg(long)] + dry_run: bool, +} + +fn emit_field(output: &mut String, field: &OptionField) { + output.push_str(&textwrap::indent( + &textwrap::dedent(&format!( + " + {{ + \"name\": \"{}\", + \"default\": '{}', + \"type\": '{}', + }},", + field.name, field.default, field.value_type + )), + " ", + )); +} + +pub fn main(cli: &Cli) -> Result<()> { + let mut output = String::new(); + + // Generate all the top-level fields. + output.push_str(&format!("{{\"name\": \"{}\", \"fields\": [", "globals")); + for field in Options::get_available_options() + .into_iter() + .filter_map(|entry| { + if let OptionEntry::Field(field) = entry { + Some(field) + } else { + None + } + }) + // Filter out options that don't make sense in the playground. + .filter(|field| { + !matches!( + field.name, + "src" + | "fix" + | "format" + | "exclude" + | "extend" + | "extend-exclude" + | "fixable" + | "force-exclude" + | "ignore-init-module-imports" + | "respect-gitignore" + | "show-source" + | "cache-dir" + | "per-file-ignores" + ) + }) + .sorted_by_key(|field| field.name) + { + emit_field(&mut output, &field); + } + output.push_str("\n]},\n"); + + // Generate all the sub-groups. + for group in Options::get_available_options() + .into_iter() + .filter_map(|entry| { + if let OptionEntry::Group(group) = entry { + Some(group) + } else { + None + } + }) + .sorted_by_key(|group| group.name) + { + output.push_str(&format!("{{\"name\": \"{}\", \"fields\": [", group.name)); + for field in group + .fields + .iter() + .filter_map(|entry| { + if let OptionEntry::Field(field) = entry { + Some(field) + } else { + None + } + }) + .sorted_by_key(|field| field.name) + { + emit_field(&mut output, field); + } + output.push_str("\n]},\n"); + } + + let prefix = textwrap::dedent( + r" + // This file is auto-generated by `cargo dev generate-playground-options`. + export interface OptionGroup { + name: string; + fields: { + name: string; + default: string; + type: string; + }[]; + }; + + export const AVAILABLE_OPTIONS: OptionGroup[] = [ + ", + ); + let postfix = "];"; + + if cli.dry_run { + print!("{output}"); + } else { + let file = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .parent() + .expect("Failed to find root directory") + .join("playground") + .join("src") + .join("ruff_options.ts"); + + let mut f = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(file)?; + write!(f, "{prefix}")?; + write!(f, "{}", textwrap::indent(&output, " "))?; + write!(f, "{postfix}")?; + } + + Ok(()) +} diff --git a/ruff_dev/src/lib.rs b/ruff_dev/src/lib.rs index 577ea5d301..8b53230bf6 100644 --- a/ruff_dev/src/lib.rs +++ b/ruff_dev/src/lib.rs @@ -14,6 +14,7 @@ pub mod generate_check_code_prefix; pub mod generate_json_schema; pub mod generate_options; +pub mod generate_playground_options; pub mod generate_rules_table; pub mod generate_source_code; pub mod print_ast; diff --git a/ruff_dev/src/main.rs b/ruff_dev/src/main.rs index fbcbda5d19..3f99f48609 100644 --- a/ruff_dev/src/main.rs +++ b/ruff_dev/src/main.rs @@ -14,8 +14,9 @@ use anyhow::Result; use clap::{Parser, Subcommand}; use ruff_dev::{ - generate_check_code_prefix, generate_json_schema, generate_options, generate_rules_table, - generate_source_code, print_ast, print_cst, print_tokens, + generate_check_code_prefix, generate_json_schema, generate_options, + generate_playground_options, generate_rules_table, generate_source_code, print_ast, print_cst, + print_tokens, }; #[derive(Parser)] @@ -36,6 +37,9 @@ enum Commands { GenerateRulesTable(generate_rules_table::Cli), /// Generate a Markdown-compatible listing of configuration options. GenerateOptions(generate_options::Cli), + /// Generate typescript file defining options to be used by the web + /// playground. + GeneratePlaygroundOptions(generate_playground_options::Cli), /// Run round-trip source code generation on a given Python file. GenerateSourceCode(generate_source_code::Cli), /// Print the AST for a given Python file. @@ -54,6 +58,7 @@ fn main() -> Result<()> { Commands::GenerateRulesTable(args) => generate_rules_table::main(args)?, Commands::GenerateSourceCode(args) => generate_source_code::main(args)?, Commands::GenerateOptions(args) => generate_options::main(args)?, + Commands::GeneratePlaygroundOptions(args) => generate_playground_options::main(args)?, Commands::PrintAST(args) => print_ast::main(args)?, Commands::PrintCST(args) => print_cst::main(args)?, Commands::PrintTokens(args) => print_tokens::main(args)?, diff --git a/src/lib.rs b/src/lib.rs index 9e4f15d0db..d918027168 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,19 +11,10 @@ clippy::too_many_lines )] -use std::path::Path; - -use anyhow::Result; -use path_absolutize::path_dedot; -use rustpython_helpers::tokenize; -use rustpython_parser::lexer::LexResult; -use settings::{pyproject, Settings}; +use cfg_if::cfg_if; use crate::checks::Check; -use crate::linter::check_path; -use crate::resolver::Relativity; -use crate::settings::configuration::Configuration; -use crate::settings::flags; +use crate::settings::Settings; use crate::source_code_locator::SourceCodeLocator; mod ast; @@ -34,7 +25,6 @@ pub mod checks; pub mod checks_gen; pub mod cli; pub mod code_gen; -pub mod commands; mod cst; mod directives; mod docstrings; @@ -66,7 +56,6 @@ pub mod logging; pub mod mccabe; pub mod message; mod noqa; -mod packages; mod pandas_vet; pub mod pep8_naming; pub mod printer; @@ -82,58 +71,20 @@ mod ruff; mod rustpython_helpers; pub mod settings; pub mod source_code_locator; -#[cfg(feature = "update-informer")] -pub mod updates; mod vendored; pub mod visibility; -/// Load the relevant `Settings` for a given `Path`. -fn resolve(path: &Path) -> Result { - if let Some(pyproject) = pyproject::find_settings_toml(path)? { - // First priority: `pyproject.toml` in the current `Path`. - resolver::resolve_settings(&pyproject, &Relativity::Parent, None) - } else if let Some(pyproject) = pyproject::find_user_settings_toml() { - // Second priority: user-specific `pyproject.toml`. - resolver::resolve_settings(&pyproject, &Relativity::Cwd, None) +cfg_if! { + if #[cfg(not(target_family = "wasm"))] { + pub mod commands; + mod packages; + #[cfg(all(feature = "update-informer"))] + pub mod updates; + + mod lib_native; + pub use lib_native::check; } else { - // Fallback: default settings. - Settings::from_configuration(Configuration::default(), &path_dedot::CWD) + mod lib_wasm; + pub use lib_wasm::check; } } - -/// Run Ruff over Python source code directly. -pub fn check(path: &Path, contents: &str, autofix: bool) -> Result> { - // Load the relevant `Settings` for the given `Path`. - let settings = resolve(path)?; - - // Validate the `Settings` and return any errors. - settings.validate()?; - - // Tokenize once. - let tokens: Vec = tokenize(contents); - - // Initialize the SourceCodeLocator (which computes offsets lazily). - let locator = SourceCodeLocator::new(contents); - - // Extract the `# noqa` and `# isort: skip` directives from the source. - let directives = directives::extract_directives( - &tokens, - &locator, - directives::Flags::from_settings(&settings), - ); - - // Generate checks. - let checks = check_path( - path, - packages::detect_package_root(path), - contents, - tokens, - &locator, - &directives, - &settings, - autofix.into(), - flags::Noqa::Enabled, - )?; - - Ok(checks) -} diff --git a/src/lib_native.rs b/src/lib_native.rs new file mode 100644 index 0000000000..789a9ea998 --- /dev/null +++ b/src/lib_native.rs @@ -0,0 +1,65 @@ +use std::path::Path; + +use anyhow::Result; +use path_absolutize::path_dedot; +use rustpython_parser::lexer::LexResult; + +use crate::checks::Check; +use crate::linter::check_path; +use crate::resolver::Relativity; +use crate::rustpython_helpers::tokenize; +use crate::settings::configuration::Configuration; +use crate::settings::{flags, pyproject, Settings}; +use crate::source_code_locator::SourceCodeLocator; +use crate::{directives, packages, resolver}; + +/// Load the relevant `Settings` for a given `Path`. +fn resolve(path: &Path) -> Result { + if let Some(pyproject) = pyproject::find_settings_toml(path)? { + // First priority: `pyproject.toml` in the current `Path`. + resolver::resolve_settings(&pyproject, &Relativity::Parent, None) + } else if let Some(pyproject) = pyproject::find_user_settings_toml() { + // Second priority: user-specific `pyproject.toml`. + resolver::resolve_settings(&pyproject, &Relativity::Cwd, None) + } else { + // Fallback: default settings. + Settings::from_configuration(Configuration::default(), &path_dedot::CWD) + } +} + +/// Run Ruff over Python source code directly. +pub fn check(path: &Path, contents: &str, autofix: bool) -> Result> { + // Load the relevant `Settings` for the given `Path`. + let settings = resolve(path)?; + + // Validate the `Settings` and return any errors. + settings.validate()?; + + // Tokenize once. + let tokens: Vec = tokenize(contents); + + // Initialize the SourceCodeLocator (which computes offsets lazily). + let locator = SourceCodeLocator::new(contents); + + // Extract the `# noqa` and `# isort: skip` directives from the source. + let directives = directives::extract_directives( + &tokens, + &locator, + directives::Flags::from_settings(&settings), + ); + + // Generate checks. + let checks = check_path( + path, + packages::detect_package_root(path), + contents, + tokens, + &locator, + &directives, + &settings, + autofix.into(), + flags::Noqa::Enabled, + )?; + + Ok(checks) +} diff --git a/src/lib_wasm.rs b/src/lib_wasm.rs new file mode 100644 index 0000000000..c9bede8c48 --- /dev/null +++ b/src/lib_wasm.rs @@ -0,0 +1,141 @@ +use std::path::Path; + +use rustpython_ast::Location; +use rustpython_parser::lexer::LexResult; +use serde::{Deserialize, Serialize}; +use wasm_bindgen::prelude::*; + +use crate::checks::CheckCode; +use crate::directives; +use crate::linter::check_path; +use crate::rustpython_helpers::tokenize; +use crate::settings::configuration::Configuration; +use crate::settings::options::Options; +use crate::settings::{flags, Settings}; +use crate::source_code_locator::SourceCodeLocator; + +#[wasm_bindgen(typescript_custom_section)] +const TYPES: &'static str = r#" +export interface Check { + code: string; + message: string; + location: { + row: number; + column: number; + }; + end_location: { + row: number; + column: number; + }; +}; +"#; + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +struct Message { + code: CheckCode, + message: String, + location: Location, + end_location: Location, +} + +#[wasm_bindgen(start)] +pub fn run() { + use log::Level; + console_error_panic_hook::set_once(); + console_log::init_with_level(Level::Debug).expect("Initializing logger went wrong."); +} + +#[wasm_bindgen] +pub fn check(contents: &str, options: JsValue) -> Result { + let options: Options = serde_wasm_bindgen::from_value(options).map_err(|e| e.to_string())?; + let configuration = + Configuration::from_options(options, Path::new(".")).map_err(|e| e.to_string())?; + let settings = + Settings::from_configuration(configuration, Path::new(".")).map_err(|e| e.to_string())?; + + // Tokenize once. + let tokens: Vec = tokenize(contents); + + // Initialize the SourceCodeLocator (which computes offsets lazily). + let locator = SourceCodeLocator::new(contents); + + // Extract the `# noqa` and `# isort: skip` directives from the source. + let directives = directives::extract_directives(&tokens, &locator, directives::Flags::empty()); + + // Generate checks. + let checks = check_path( + Path::new(""), + None, + contents, + tokens, + &locator, + &directives, + &settings, + false.into(), + flags::Noqa::Enabled, + ) + .map_err(|e| e.to_string())?; + + let messages: Vec = checks + .into_iter() + .map(|check| Message { + code: check.kind.code().clone(), + message: check.kind.body(), + location: check.location, + end_location: check.end_location, + }) + .collect(); + + Ok(serde_wasm_bindgen::to_value(&messages)?) +} + +#[cfg(test)] +mod test { + use js_sys; + use wasm_bindgen_test::*; + + use super::*; + + macro_rules! check { + ($source:expr, $config:expr, $expected:expr) => {{ + let foo = js_sys::JSON::parse($config).unwrap(); + match check($source, foo) { + Ok(output) => { + let result: Vec = serde_wasm_bindgen::from_value(output).unwrap(); + assert_eq!(result, $expected); + } + Err(e) => assert!(false, "{:#?}", e), + } + }}; + } + + #[wasm_bindgen_test] + fn empty_config() { + check!( + "if (1, 2): pass", + r#"{}"#, + [Message { + code: CheckCode::F634, + message: "If test is a tuple, which is always `True`".to_string(), + location: Location::new(1, 0), + end_location: Location::new(1, 15) + }] + ); + } + + #[wasm_bindgen_test] + fn partial_config() { + check!("if (1, 2): pass", r#"{"ignore": ["F"]}"#, []); + } + + #[wasm_bindgen_test] + fn partial_nested_config() { + let config = r#"{ + "select": ["Q"], + "flake8-quotes": { + "inline-quotes": "single" + } + }"#; + check!(r#"print('hello world')"#, config, []); + } +} diff --git a/src/linter.rs b/src/linter.rs index 0c142f7e63..499446ace2 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -5,7 +5,6 @@ use std::ops::AddAssign; use std::path::Path; use anyhow::Result; -#[cfg(not(target_family = "wasm"))] use log::debug; use rustpython_parser::lexer::LexResult; diff --git a/src/main.rs b/src/main.rs index a8f6fe9aa6..592e86dc87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,263 +11,23 @@ clippy::too_many_lines )] -use std::io::{self}; -use std::path::{Path, PathBuf}; use std::process::ExitCode; -use std::sync::mpsc::channel; -use ::ruff::autofix::fixer; -use ::ruff::cli::{extract_log_level, Cli, Overrides}; -use ::ruff::commands; -use ::ruff::logging::{set_up_logging, LogLevel}; -use ::ruff::printer::{Printer, Violations}; -use ::ruff::resolver::{resolve_settings, FileDiscovery, PyprojectDiscovery, Relativity}; -use ::ruff::settings::configuration::Configuration; -use ::ruff::settings::types::SerializationFormat; -use ::ruff::settings::{pyproject, Settings}; -#[cfg(feature = "update-informer")] -use ::ruff::updates; -use anyhow::Result; -use clap::{CommandFactory, Parser}; +use cfg_if::cfg_if; use colored::Colorize; -use notify::{recommended_watcher, RecursiveMode, Watcher}; -use path_absolutize::path_dedot; -/// Resolve the relevant settings strategy and defaults for the current -/// invocation. -fn resolve( - config: Option<&Path>, - overrides: &Overrides, - stdin_filename: Option<&Path>, -) -> Result { - if let Some(pyproject) = config { - // First priority: the user specified a `pyproject.toml` file. Use that - // `pyproject.toml` for _all_ configuration, and resolve paths relative to the - // current working directory. (This matches ESLint's behavior.) - let settings = resolve_settings(pyproject, &Relativity::Cwd, Some(overrides))?; - Ok(PyprojectDiscovery::Fixed(settings)) - } else if let Some(pyproject) = pyproject::find_settings_toml( - stdin_filename - .as_ref() - .unwrap_or(&path_dedot::CWD.as_path()), - )? { - // Second priority: find a `pyproject.toml` file in either an ancestor of - // `stdin_filename` (if set) or the current working path all paths relative to - // that directory. (With `Strategy::Hierarchical`, we'll end up finding - // the "closest" `pyproject.toml` file for every Python file later on, - // so these act as the "default" settings.) - let settings = resolve_settings(&pyproject, &Relativity::Parent, Some(overrides))?; - Ok(PyprojectDiscovery::Hierarchical(settings)) - } else if let Some(pyproject) = pyproject::find_user_settings_toml() { - // Third priority: find a user-specific `pyproject.toml`, but resolve all paths - // relative the current working directory. (With `Strategy::Hierarchical`, we'll - // end up the "closest" `pyproject.toml` file for every Python file later on, so - // these act as the "default" settings.) - let settings = resolve_settings(&pyproject, &Relativity::Cwd, Some(overrides))?; - Ok(PyprojectDiscovery::Hierarchical(settings)) +cfg_if! { + if #[cfg(not(target_family = "wasm"))] { + mod main_native; + use main_native::inner_main; } else { - // Fallback: load Ruff's default settings, and resolve all paths relative to the - // current working directory. (With `Strategy::Hierarchical`, we'll end up the - // "closest" `pyproject.toml` file for every Python file later on, so these act - // as the "default" settings.) - let mut config = Configuration::default(); - // Apply command-line options that override defaults. - config.apply(overrides.clone()); - let settings = Settings::from_configuration(config, &path_dedot::CWD)?; - Ok(PyprojectDiscovery::Hierarchical(settings)) - } -} + use anyhow::Result; -fn inner_main() -> Result { - // Extract command-line arguments. - let (cli, overrides) = Cli::parse().partition(); - let log_level = extract_log_level(&cli); - set_up_logging(&log_level)?; - - if cli.show_settings && cli.show_files { - anyhow::bail!("specify --show-settings or show-files (not both)") - } - if let Some(shell) = cli.generate_shell_completion { - shell.generate(&mut Cli::command(), &mut io::stdout()); - return Ok(ExitCode::SUCCESS); - } - - // Construct the "default" settings. These are used when no `pyproject.toml` - // files are present, or files are injected from outside of the hierarchy. - let pyproject_strategy = resolve( - cli.config.as_deref(), - &overrides, - cli.stdin_filename.as_deref(), - )?; - - // Validate the `Settings` and return any errors. - match &pyproject_strategy { - PyprojectDiscovery::Fixed(settings) => settings.validate()?, - PyprojectDiscovery::Hierarchical(settings) => settings.validate()?, - }; - - // Extract options that are included in `Settings`, but only apply at the top - // level. - let file_strategy = FileDiscovery { - force_exclude: match &pyproject_strategy { - PyprojectDiscovery::Fixed(settings) => settings.force_exclude, - PyprojectDiscovery::Hierarchical(settings) => settings.force_exclude, - }, - respect_gitignore: match &pyproject_strategy { - PyprojectDiscovery::Fixed(settings) => settings.respect_gitignore, - PyprojectDiscovery::Hierarchical(settings) => settings.respect_gitignore, - }, - }; - let (fix, fix_only, format) = match &pyproject_strategy { - PyprojectDiscovery::Fixed(settings) => (settings.fix, settings.fix_only, settings.format), - PyprojectDiscovery::Hierarchical(settings) => { - (settings.fix, settings.fix_only, settings.format) - } - }; - let autofix = if fix || fix_only { - fixer::Mode::Apply - } else if matches!(format, SerializationFormat::Json) { - fixer::Mode::Generate - } else { - fixer::Mode::None - }; - let violations = if fix_only { - Violations::Hide - } else { - Violations::Show - }; - let cache = !cli.no_cache; - - if let Some(code) = cli.explain { - commands::explain(&code, &format)?; - return Ok(ExitCode::SUCCESS); - } - if cli.show_settings { - commands::show_settings(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; - return Ok(ExitCode::SUCCESS); - } - if cli.show_files { - commands::show_files(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; - return Ok(ExitCode::SUCCESS); - } - - let printer = Printer::new(&format, &log_level, &autofix, &violations); - if cli.watch { - if matches!(autofix, fixer::Mode::Generate | fixer::Mode::Apply) { - eprintln!("Warning: --fix is not enabled in watch mode."); - } - if cli.add_noqa { - eprintln!("Warning: --add-noqa is not enabled in watch mode."); - } - if cli.autoformat { - eprintln!("Warning: --autoformat is not enabled in watch mode."); - } - if format != SerializationFormat::Text { - eprintln!("Warning: --format 'text' is used in watch mode."); - } - - // Perform an initial run instantly. - printer.clear_screen()?; - printer.write_to_user("Starting linter in watch mode...\n"); - - let messages = commands::run( - &cli.files, - &pyproject_strategy, - &file_strategy, - &overrides, - cache.into(), - fixer::Mode::None, - )?; - printer.write_continuously(&messages)?; - - // Configure the file watcher. - let (tx, rx) = channel(); - let mut watcher = recommended_watcher(tx)?; - for file in &cli.files { - watcher.watch(file, RecursiveMode::Recursive)?; - } - - loop { - match rx.recv() { - Ok(event) => { - let paths = event?.paths; - let py_changed = paths.iter().any(|path| { - path.extension() - .map(|ext| ext == "py" || ext == "pyi") - .unwrap_or_default() - }); - if py_changed { - printer.clear_screen()?; - printer.write_to_user("File change detected...\n"); - - let messages = commands::run( - &cli.files, - &pyproject_strategy, - &file_strategy, - &overrides, - cache.into(), - fixer::Mode::None, - )?; - printer.write_continuously(&messages)?; - } - } - Err(err) => return Err(err.into()), - } - } - } else if cli.add_noqa { - let modifications = - commands::add_noqa(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; - if modifications > 0 && log_level >= LogLevel::Default { - println!("Added {modifications} noqa directives."); - } - } else if cli.autoformat { - let modifications = - commands::autoformat(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; - if modifications > 0 && log_level >= LogLevel::Default { - println!("Formatted {modifications} files."); - } - } else { - let is_stdin = cli.files == vec![PathBuf::from("-")]; - - // Generate lint violations. - let diagnostics = if is_stdin { - commands::run_stdin( - cli.stdin_filename.as_deref(), - &pyproject_strategy, - &file_strategy, - &overrides, - autofix, - )? - } else { - commands::run( - &cli.files, - &pyproject_strategy, - &file_strategy, - &overrides, - cache.into(), - autofix, - )? - }; - - // Always try to print violations (the printer itself may suppress output), - // unless we're writing fixes via stdin (in which case, the transformed - // source code goes to stdout). - if !(is_stdin && matches!(autofix, fixer::Mode::Apply)) { - printer.write_once(&diagnostics)?; - } - - // Check for updates if we're in a non-silent log level. - #[cfg(feature = "update-informer")] - if !is_stdin && log_level >= LogLevel::Default && atty::is(atty::Stream::Stdout) { - drop(updates::check_for_updates()); - } - - if !diagnostics.messages.is_empty() && !cli.exit_zero && !fix_only { - return Ok(ExitCode::FAILURE); + #[allow(clippy::unnecessary_wraps)] + fn inner_main() -> Result { + Ok(ExitCode::FAILURE) } } - - Ok(ExitCode::SUCCESS) } fn main() -> ExitCode { diff --git a/src/main_native.rs b/src/main_native.rs new file mode 100644 index 0000000000..19ee5bb6a3 --- /dev/null +++ b/src/main_native.rs @@ -0,0 +1,270 @@ +#![allow( + clippy::collapsible_else_if, + clippy::collapsible_if, + clippy::implicit_hasher, + clippy::match_same_arms, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::similar_names, + clippy::too_many_lines +)] + +use std::io::{self}; +use std::path::{Path, PathBuf}; +use std::process::ExitCode; +use std::sync::mpsc::channel; + +use ::ruff::autofix::fixer; +use ::ruff::cli::{extract_log_level, Cli, Overrides}; +use ::ruff::commands; +use ::ruff::logging::{set_up_logging, LogLevel}; +use ::ruff::printer::{Printer, Violations}; +use ::ruff::resolver::{resolve_settings, FileDiscovery, PyprojectDiscovery, Relativity}; +use ::ruff::settings::configuration::Configuration; +use ::ruff::settings::types::SerializationFormat; +use ::ruff::settings::{pyproject, Settings}; +#[cfg(feature = "update-informer")] +use ::ruff::updates; +use anyhow::Result; +use clap::{CommandFactory, Parser}; +use notify::{recommended_watcher, RecursiveMode, Watcher}; +use path_absolutize::path_dedot; + +/// Resolve the relevant settings strategy and defaults for the current +/// invocation. +fn resolve( + config: Option<&Path>, + overrides: &Overrides, + stdin_filename: Option<&Path>, +) -> Result { + if let Some(pyproject) = config { + // First priority: the user specified a `pyproject.toml` file. Use that + // `pyproject.toml` for _all_ configuration, and resolve paths relative to the + // current working directory. (This matches ESLint's behavior.) + let settings = resolve_settings(pyproject, &Relativity::Cwd, Some(overrides))?; + Ok(PyprojectDiscovery::Fixed(settings)) + } else if let Some(pyproject) = pyproject::find_settings_toml( + stdin_filename + .as_ref() + .unwrap_or(&path_dedot::CWD.as_path()), + )? { + // Second priority: find a `pyproject.toml` file in either an ancestor of + // `stdin_filename` (if set) or the current working path all paths relative to + // that directory. (With `Strategy::Hierarchical`, we'll end up finding + // the "closest" `pyproject.toml` file for every Python file later on, + // so these act as the "default" settings.) + let settings = resolve_settings(&pyproject, &Relativity::Parent, Some(overrides))?; + Ok(PyprojectDiscovery::Hierarchical(settings)) + } else if let Some(pyproject) = pyproject::find_user_settings_toml() { + // Third priority: find a user-specific `pyproject.toml`, but resolve all paths + // relative the current working directory. (With `Strategy::Hierarchical`, we'll + // end up the "closest" `pyproject.toml` file for every Python file later on, so + // these act as the "default" settings.) + let settings = resolve_settings(&pyproject, &Relativity::Cwd, Some(overrides))?; + Ok(PyprojectDiscovery::Hierarchical(settings)) + } else { + // Fallback: load Ruff's default settings, and resolve all paths relative to the + // current working directory. (With `Strategy::Hierarchical`, we'll end up the + // "closest" `pyproject.toml` file for every Python file later on, so these act + // as the "default" settings.) + let mut config = Configuration::default(); + // Apply command-line options that override defaults. + config.apply(overrides.clone()); + let settings = Settings::from_configuration(config, &path_dedot::CWD)?; + Ok(PyprojectDiscovery::Hierarchical(settings)) + } +} + +pub(crate) fn inner_main() -> Result { + // Extract command-line arguments. + let (cli, overrides) = Cli::parse().partition(); + let log_level = extract_log_level(&cli); + set_up_logging(&log_level)?; + + if cli.show_settings && cli.show_files { + anyhow::bail!("specify --show-settings or show-files (not both)") + } + if let Some(shell) = cli.generate_shell_completion { + shell.generate(&mut Cli::command(), &mut io::stdout()); + return Ok(ExitCode::SUCCESS); + } + + // Construct the "default" settings. These are used when no `pyproject.toml` + // files are present, or files are injected from outside of the hierarchy. + let pyproject_strategy = resolve( + cli.config.as_deref(), + &overrides, + cli.stdin_filename.as_deref(), + )?; + + // Validate the `Settings` and return any errors. + match &pyproject_strategy { + PyprojectDiscovery::Fixed(settings) => settings.validate()?, + PyprojectDiscovery::Hierarchical(settings) => settings.validate()?, + }; + + // Extract options that are included in `Settings`, but only apply at the top + // level. + let file_strategy = FileDiscovery { + force_exclude: match &pyproject_strategy { + PyprojectDiscovery::Fixed(settings) => settings.force_exclude, + PyprojectDiscovery::Hierarchical(settings) => settings.force_exclude, + }, + respect_gitignore: match &pyproject_strategy { + PyprojectDiscovery::Fixed(settings) => settings.respect_gitignore, + PyprojectDiscovery::Hierarchical(settings) => settings.respect_gitignore, + }, + }; + let (fix, fix_only, format) = match &pyproject_strategy { + PyprojectDiscovery::Fixed(settings) => (settings.fix, settings.fix_only, settings.format), + PyprojectDiscovery::Hierarchical(settings) => { + (settings.fix, settings.fix_only, settings.format) + } + }; + let autofix = if fix || fix_only { + fixer::Mode::Apply + } else if matches!(format, SerializationFormat::Json) { + fixer::Mode::Generate + } else { + fixer::Mode::None + }; + let violations = if fix_only { + Violations::Hide + } else { + Violations::Show + }; + let cache = !cli.no_cache; + + if let Some(code) = cli.explain { + commands::explain(&code, &format)?; + return Ok(ExitCode::SUCCESS); + } + if cli.show_settings { + commands::show_settings(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; + return Ok(ExitCode::SUCCESS); + } + if cli.show_files { + commands::show_files(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; + return Ok(ExitCode::SUCCESS); + } + + let printer = Printer::new(&format, &log_level, &autofix, &violations); + if cli.watch { + if matches!(autofix, fixer::Mode::Generate | fixer::Mode::Apply) { + eprintln!("Warning: --fix is not enabled in watch mode."); + } + if cli.add_noqa { + eprintln!("Warning: --add-noqa is not enabled in watch mode."); + } + if cli.autoformat { + eprintln!("Warning: --autoformat is not enabled in watch mode."); + } + if format != SerializationFormat::Text { + eprintln!("Warning: --format 'text' is used in watch mode."); + } + + // Perform an initial run instantly. + printer.clear_screen()?; + printer.write_to_user("Starting linter in watch mode...\n"); + + let messages = commands::run( + &cli.files, + &pyproject_strategy, + &file_strategy, + &overrides, + cache.into(), + fixer::Mode::None, + )?; + printer.write_continuously(&messages)?; + + // Configure the file watcher. + let (tx, rx) = channel(); + let mut watcher = recommended_watcher(tx)?; + for file in &cli.files { + watcher.watch(file, RecursiveMode::Recursive)?; + } + + loop { + match rx.recv() { + Ok(event) => { + let paths = event?.paths; + let py_changed = paths.iter().any(|path| { + path.extension() + .map(|ext| ext == "py" || ext == "pyi") + .unwrap_or_default() + }); + if py_changed { + printer.clear_screen()?; + printer.write_to_user("File change detected...\n"); + + let messages = commands::run( + &cli.files, + &pyproject_strategy, + &file_strategy, + &overrides, + cache.into(), + fixer::Mode::None, + )?; + printer.write_continuously(&messages)?; + } + } + Err(err) => return Err(err.into()), + } + } + } else if cli.add_noqa { + let modifications = + commands::add_noqa(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; + if modifications > 0 && log_level >= LogLevel::Default { + println!("Added {modifications} noqa directives."); + } + } else if cli.autoformat { + let modifications = + commands::autoformat(&cli.files, &pyproject_strategy, &file_strategy, &overrides)?; + if modifications > 0 && log_level >= LogLevel::Default { + println!("Formatted {modifications} files."); + } + } else { + let is_stdin = cli.files == vec![PathBuf::from("-")]; + + // Generate lint violations. + let diagnostics = if is_stdin { + commands::run_stdin( + cli.stdin_filename.as_deref(), + &pyproject_strategy, + &file_strategy, + &overrides, + autofix, + )? + } else { + commands::run( + &cli.files, + &pyproject_strategy, + &file_strategy, + &overrides, + cache.into(), + autofix, + )? + }; + + // Always try to print violations (the printer itself may suppress output), + // unless we're writing fixes via stdin (in which case, the transformed + // source code goes to stdout). + if !(is_stdin && matches!(autofix, fixer::Mode::Apply)) { + printer.write_once(&diagnostics)?; + } + + // Check for updates if we're in a non-silent log level. + #[cfg(feature = "update-informer")] + if !is_stdin && log_level >= LogLevel::Default && atty::is(atty::Stream::Stdout) { + drop(updates::check_for_updates()); + } + + if !diagnostics.messages.is_empty() && !cli.exit_zero && !fix_only { + return Ok(ExitCode::FAILURE); + } + } + + Ok(ExitCode::SUCCESS) +} diff --git a/tests/black_compatibility_test.rs b/tests/black_compatibility_test.rs index 18565c099e..84e9db1fca 100644 --- a/tests/black_compatibility_test.rs +++ b/tests/black_compatibility_test.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_family = "wasm"))] + use std::io::{ErrorKind, Read}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener, TcpStream}; use std::path::{Path, PathBuf}; diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 0e6376f200..d7b219be20 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_family = "wasm"))] + use std::str; use anyhow::Result;