Use oxlint (#82015)

This commit is contained in:
Fraser
2026-10-05 22:41:31 +13:00
committed by GitHub
parent ec5eac8463
commit 48b9e66904
333 changed files with 5100 additions and 2031 deletions

View File

@@ -1,7 +1,7 @@
## Linting and Formatting ## Linting and Formatting
- **Lint:** `bun run lint-eslint-pure` - **Lint:** `bun run lint-oxlint-pure`
- Run ESLint on the codebase - Run oxlint on the codebase
- **Format:** `bun run format` - **Format:** `bun run format`
- Format code with oxfmt (`oxfmt --write`); use `bun run lint-format-pure` to check without writing - Format code with oxfmt (`oxfmt --write`); use `bun run lint-format-pure` to check without writing
- **Type Check:** `bun run type-check-pure` - **Type Check:** `bun run type-check-pure`

View File

@@ -39,7 +39,7 @@ what and who may depend on whom.**
| module elements, tiers, `enforceSharedTiers`, `enforcePublicApi` | `frontend/lint/module-boundaries.mjs` | | module elements, tiers, `enforceSharedTiers`, `enforcePublicApi` | `frontend/lint/module-boundaries.mjs` |
| shared sub-tiers and levels, cluster rules | `frontend/lint/shared-tiers.mjs` | | shared sub-tiers and levels, cluster rules | `frontend/lint/shared-tiers.mjs` |
| standalone boundaries lint (all violations, incl. grandfathered) | `bun run module-boundaries` (config `eslint.config.module-boundaries.mjs`) | | standalone boundaries lint (all violations, incl. grandfathered) | `bun run module-boundaries` (config `eslint.config.module-boundaries.mjs`) |
| PR lint (only enforced modules fail CI) | `bun run lint-eslint-pure` | | PR lint (only enforced modules fail CI) | `bun run lint-oxlint-pure` |
| side-effect-free directories and their exceptions | `frontend/build/shared/rspack/side-effect-free-modules.js` (`SIDE_EFFECT_FREE_PATHS`, `SIDE_EFFECT_PATHS`) | | side-effect-free directories and their exceptions | `frontend/build/shared/rspack/side-effect-free-modules.js` (`SIDE_EFFECT_FREE_PATHS`, `SIDE_EFFECT_PATHS`) |
| the lint rules that enforce that promise | `metabase/no-module-side-effects`, `metabase/no-base-api-access` in `frontend/lint/eslint-plugin-metabase/rules/` | | the lint rules that enforce that promise | `metabase/no-module-side-effects`, `metabase/no-base-api-access` in `frontend/lint/eslint-plugin-metabase/rules/` |
| public-api enforcement | `metabase/enforce-module-public-api` rule, driven by `getPublicApiModules()` | | public-api enforcement | `metabase/enforce-module-public-api` rule, driven by `getPublicApiModules()` |
@@ -199,7 +199,7 @@ prefix; never generic `-shared` / `-feature` suffixes.
``` ```
grep -rn "<old path>" frontend enterprise/frontend e2e # must be empty grep -rn "<old path>" frontend enterprise/frontend e2e # must be empty
bunx eslint --no-warn-ignored <touched files> bunx eslint --no-warn-ignored <touched files>
bun run lint-eslint-pure # enforce-module-public-api included bun run lint-oxlint-pure # enforce-module-public-api included
bun run type-check-pure bun run type-check-pure
bun run test-unit-keep-cljs <touched folders' specs> bun run test-unit-keep-cljs <touched folders' specs>
bun run module-boundaries 2>&1 | tail -1 # after; no violation may name the new files bun run module-boundaries 2>&1 | tail -1 # after; no violation may name the new files

View File

@@ -172,7 +172,7 @@ export const OverviewStory = {
- **Scope controls per story.** A static matrix should hide knobs it ignores: `parameters.controls = { include: [...] }` (or `{ disable: true }`). Wire any kept knob (e.g. `children`) through to the cells so it does something. - **Scope controls per story.** A static matrix should hide knobs it ignores: `parameters.controls = { include: [...] }` (or `{ disable: true }`). Wire any kept knob (e.g. `children`) through to the cells so it does something.
- `loki.config.js` has a `storiesFilter`; check it before renaming a story that's already covered. - `loki.config.js` has a `storiesFilter`; check it before renaming a story that's already covered.
Validate: `bun run lint-eslint-pure -- <files>` and `bun run type-check-pure`. Validate: `bun run lint-oxlint-pure -- <files>` and `bun run type-check-pure`.
### Optional: verify in the browser yourself ### Optional: verify in the browser yourself
@@ -217,7 +217,7 @@ General gotchas when extending Mantine components — adapt per component:
- **Built-in icons use `currentColor`**, so they inherit the slot's text color. - **Built-in icons use `currentColor`**, so they inherit the slot's text color.
- For text on a brand fill, follow the existing convention (`text-primary-inverse`) unless the user wants pure white; flag the dark-theme implication. - For text on a brand fill, follow the existing convention (`text-primary-inverse`) unless the user wants pure white; flag the dark-theme implication.
After edits: `npx stylelint <css>`, `LINT_CSS_MODULES=true bun run lint-eslint-pure -- <files>`, `bun run type-check-pure`. After edits: `npx stylelint <css>`, `LINT_CSS_MODULES=true bun run lint-oxlint-pure -- <files>`, `bun run type-check-pure`.
## Phase 5 — Iterate with the user ## Phase 5 — Iterate with the user

View File

@@ -39,6 +39,8 @@ frontend_configs: &frontend_configs
- "package.json" - "package.json"
- "babel.config.json" - "babel.config.json"
- "eslint.config.mjs" - "eslint.config.mjs"
- "oxlint.config.mts"
- ".oxfmtrc.json"
- "postcss.config.js" - "postcss.config.js"
- "rspack.config.js" - "rspack.config.js"
- "rspack.main.config.js" - "rspack.main.config.js"
@@ -75,6 +77,7 @@ frontend_all: &frontend_all
- *frontend_ci - *frontend_ci
- *frontend_sources - *frontend_sources
- *frontend_specs - *frontend_specs
- "frontend/lint/**/!(*.md)"
frontend_loki_ci: &frontend_loki_ci frontend_loki_ci: &frontend_loki_ci
- ".github/workflows/loki.yml" - ".github/workflows/loki.yml"

View File

@@ -78,10 +78,6 @@ CYPRESS_VERSION="$CYPRESS_VERSIONS"
# and the key that identifies its cache entry cannot drift apart. # and the key that identifies its cache entry cannot drift apart.
CLOJURE_VERSION="1.12.0.1488" CLOJURE_VERSION="1.12.0.1488"
# An incremental lint cache is only ever an accelerator, so it keys on the commit and always falls back
# to the newest entry on the prefix. The exact key never pre-exists, which keeps the entry current.
ESLINT_SHA="${GITHUB_SHA:-$(git rev-parse HEAD)}"
emit_multiline() { emit_multiline() {
local name="$1"; shift local name="$1"; shift
printf '%s<<CACHE_KEYS_EOF\n' "$name" printf '%s<<CACHE_KEYS_EOF\n' "$name"
@@ -116,10 +112,6 @@ spec() {
echo "cypress-path=$HOME/.cache/Cypress" echo "cypress-path=$HOME/.cache/Cypress"
echo "cypress-key=cypress-$OS-$CYPRESS_VERSION" echo "cypress-key=cypress-$OS-$CYPRESS_VERSION"
echo "cypress-restore-key=cypress-$OS-" echo "cypress-restore-key=cypress-$OS-"
echo "eslint-path=.eslintcache"
echo "eslint-key=eslint-$OS-$ESLINT_SHA"
echo "eslint-restore-key=eslint-$OS-"
} }
# Print one output's value, including the multiline form, and fail on a name that does not exist. A # Print one output's value, including the multiline form, and fail on a name that does not exist. A

View File

@@ -3,7 +3,7 @@ import { join } from "path";
const SCRIPT = join(__dirname, "cache-keys.sh"); const SCRIPT = join(__dirname, "cache-keys.sh");
const CACHES = ["m2", "bun-store", "cypress", "eslint"]; const CACHES = ["m2", "bun-store", "cypress"];
// stderr is inherited by default, so the deliberate-failure case below would print a literal // stderr is inherited by default, so the deliberate-failure case below would print a literal
// `::error::` line - which GitHub Actions reads as an annotation directive, making a passing run // `::error::` line - which GitHub Actions reads as an annotation directive, making a passing run
@@ -71,10 +71,4 @@ describe("cache-keys.sh", () => {
it("keys the Cypress binary on the resolved version, not the lockfile", () => { it("keys the Cypress binary on the resolved version, not the lockfile", () => {
expect(get("cypress-key")).toMatch(/^cypress-Linux-\d+\.\d+\.\d+/); expect(get("cypress-key")).toMatch(/^cypress-Linux-\d+\.\d+\.\d+/);
}); });
it("keys the ESLint cache on the commit", () => {
expect(get("eslint-key", { GITHUB_SHA: "deadbeef" })).toEqual(
"eslint-Linux-deadbeef",
);
});
}); });

View File

@@ -62,6 +62,32 @@ describe("file-paths.yaml", () => {
expect(matches("ci_scripts", ".nvmrc")).toBe(true); expect(matches("ci_scripts", ".nvmrc")).toBe(true);
}); });
it.each([
"frontend/lint/config.mjs",
"frontend/lint/oxlint/rule-map.json",
"frontend/lint/eslint-plugin-metabase/rules/no-module-side-effects.js",
"frontend/lint/tests/oxlint-config.test.mjs",
])(
"runs frontend checks without forcing full suites when %s changes",
(file) => {
expect(matches("frontend_all", file)).toBe(true);
expect(matches("frontend_unit_infra", file)).toBe(false);
expect(matches("frontend_loki_infra", file)).toBe(false);
},
);
it("treats frontend/lint/OXLINT.md as a documentation-only change", () => {
expect(matches("frontend_all", "frontend/lint/OXLINT.md")).toBe(false);
expect(matches("documentation", "frontend/lint/OXLINT.md")).toBe(true);
});
it.each([
"frontend/lint/module-boundaries.mjs",
"frontend/lint/shared-tiers.mjs",
])("keeps CI script coverage for %s", (file) => {
expect(matches("ci_scripts", file)).toBe(true);
});
it.each([ it.each([
"jest.config.js", "jest.config.js",
"jest.base.conf.js", "jest.base.conf.js",

View File

@@ -5,9 +5,6 @@
# build a 200MB archive and race for one reservation on every lockfile change, and all pull the Cypress # build a 200MB archive and race for one reservation on every lockfile change, and all pull the Cypress
# binary at once on a version bump. # binary at once on a version bump.
# #
# The ESLint cache is the exception and saves from the lint job itself: it is under a megabyte and only a
# couple of jobs write it, so there is no herd to avoid.
#
# A cache is readable from the ref that saved it, from that ref's pull requests, and - for every ref - # A cache is readable from the ref that saved it, from that ref's pull requests, and - for every ref -
# from the default branch. Warming on push to each merge target therefore serves the pull requests aimed # from the default branch. Warming on push to each merge target therefore serves the pull requests aimed
# at it, and master's copy backs up every ref that has none of its own. # at it, and master's copy backs up every ref that has none of its own.

View File

@@ -26,7 +26,7 @@ on:
type: boolean type: boolean
default: false default: false
skip-lint: skip-lint:
description: "Skip linting jobs (oxfmt, eslint, css variables check)" description: "Skip linting jobs (oxfmt, oxlint, css variables check)"
type: boolean type: boolean
default: false default: false
skip-custom-viz: skip-custom-viz:
@@ -57,26 +57,16 @@ jobs:
- name: Prepare back-end environment - name: Prepare back-end environment
uses: ./.github/actions/prepare-backend uses: ./.github/actions/prepare-backend
- name: Cache spec
id: cache-spec
run: .github/scripts/cache-keys.sh | tee -a "$GITHUB_OUTPUT"
# Small enough, and written by few enough jobs, that this one reads and writes its own cache
# rather than waiting on cache-warm.
- name: ESLint cache
uses: actions/cache@v5
with:
path: ${{ steps.cache-spec.outputs.eslint-path }}
key: ${{ steps.cache-spec.outputs.eslint-key }}
restore-keys: ${{ steps.cache-spec.outputs.eslint-restore-key }}
- name: Compile CLJS - name: Compile CLJS
run: bun run build-pure:cljs run: bun run build-pure:cljs
- name: Find CSS variables that are used but never defined - name: Find CSS variables that are used but never defined
run: bun run find-never-defined-css-variables run: bun run find-never-defined-css-variables
- name: Run oxfmt formatting linter - name: Run oxfmt formatting linter
run: bun run lint-format-pure run: bun run lint-format-pure
- name: Run ESLint linter - name: Run oxlint linter (including module boundaries)
run: bun run lint-eslint-pure run: bun run lint-oxlint-pure
- name: Verify lint configuration and behavior
run: bun run test-oxlint
- name: Run CSS linter - name: Run CSS linter
run: bun run lint-css run: bun run lint-css

View File

@@ -1,4 +1,75 @@
{ {
"printWidth": 80, "printWidth": 80,
"trailingComma": "all" "trailingComma": "all",
"sortImports": {
"customGroups": [
{
"groupName": "internal-pre-metabase",
"elementNamePattern": [
"__support__",
"__support__/**",
"assets",
"assets/**",
"build-configs",
"build-configs/**",
"cljs",
"cljs/**",
"docs",
"docs/**",
"e2e",
"e2e/**",
"ee-overrides",
"ee-overrides/**",
"ee-plugins",
"ee-plugins/**",
"embedding",
"embedding/**",
"embedding-sdk-bundle",
"embedding-sdk-bundle/**",
"embedding-sdk-package",
"embedding-sdk-package/**",
"embedding-sdk-shared",
"embedding-sdk-shared/**",
"img",
"img/**"
]
},
{
"groupName": "metabase-core",
"elementNamePattern": ["metabase", "metabase/**"]
},
{
"groupName": "metabase-scoped",
"elementNamePattern": ["metabase-*/**", "metabase-*"]
},
{
"groupName": "internal-post-metabase",
"elementNamePattern": [
"sdk-ee-plugins",
"sdk-ee-plugins/**",
"sdk-iframe-embedding-ee-plugins",
"sdk-iframe-embedding-ee-plugins/**",
"sdk-iframe-embedding-script-ee-plugins",
"sdk-iframe-embedding-script-ee-plugins/**"
]
}
],
"groups": [
["value-builtin", "type-builtin"],
["value-external", "type-external"],
"internal-pre-metabase",
{ "newlinesBetween": false },
"metabase-core",
{ "newlinesBetween": false },
"metabase-scoped",
{ "newlinesBetween": false },
"internal-post-metabase",
["value-parent", "type-parent"],
["value-sibling", "type-sibling"],
["value-index", "type-index"]
],
"newlinesBetween": true,
"order": "asc",
"ignoreCase": false
}
} }

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env node #!/usr/bin/env node
/* eslint-env node */ /* eslint-env node */
/* eslint-disable import/order */
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const { spawn } = require("child_process"); const { spawn } = require("child_process");

308
bun.lock
View File

@@ -115,7 +115,7 @@
"mustache": "^2.3.2", "mustache": "^2.3.2",
"normalizr": "^3.0.2", "normalizr": "^3.0.2",
"ora": "^8.0.1", "ora": "^8.0.1",
"oxlint": "^1.58.0", "oxlint": "1.85.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"process": "^0.11.10", "process": "^0.11.10",
"prosemirror-dropcursor": "1.8.2", "prosemirror-dropcursor": "1.8.2",
@@ -241,6 +241,7 @@
"@types/redux-actions": "^2.6.5", "@types/redux-actions": "^2.6.5",
"@types/semver": "^7.7.1", "@types/semver": "^7.7.1",
"@types/underscore": "^1.13.0", "@types/underscore": "^1.13.0",
"@typescript-eslint/eslint-plugin": "8.60.0",
"@vitejs/plugin-react": "^6.0.2", "@vitejs/plugin-react": "^6.0.2",
"ajv": "^8.5.0", "ajv": "^8.5.0",
"babel-loader": "^9.1.2", "babel-loader": "^9.1.2",
@@ -272,13 +273,12 @@
"eslint-plugin-boundaries": "5.4.0", "eslint-plugin-boundaries": "5.4.0",
"eslint-plugin-chai-friendly": "^1.1.0", "eslint-plugin-chai-friendly": "^1.1.0",
"eslint-plugin-cypress": "6.1.0", "eslint-plugin-cypress": "6.1.0",
"eslint-plugin-depend": "1.4.0", "eslint-plugin-depend": "1.5.0",
"eslint-plugin-i18next": "6.1.3", "eslint-plugin-i18next": "6.1.4",
"eslint-plugin-import-x": "4.16.1", "eslint-plugin-import-x": "4.17.1",
"eslint-plugin-jest": "29.12.1", "eslint-plugin-jest": "29.12.1",
"eslint-plugin-jest-dom": "^5.5.0", "eslint-plugin-jest-dom": "^5.5.0",
"eslint-plugin-jest-formatting": "^3.1.0", "eslint-plugin-no-only-tests": "3.4.0",
"eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-react": "7.37.5", "eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-storybook": "9.1.17", "eslint-plugin-storybook": "9.1.17",
@@ -290,6 +290,7 @@
"get-nonce": "^1.0.1", "get-nonce": "^1.0.1",
"glob": "^7.1.1", "glob": "^7.1.1",
"globals": "^15.14.0", "globals": "^15.14.0",
"html-entities": "2.3.2",
"html-webpack-plugin": "5.5.0", "html-webpack-plugin": "5.5.0",
"husky": "^9.1.7", "husky": "^9.1.7",
"inquirer-file-selector": "^0.2.1", "inquirer-file-selector": "^0.2.1",
@@ -321,6 +322,7 @@
"open-cli": "^8.0.0", "open-cli": "^8.0.0",
"openapi-typescript": "^7.10.0", "openapi-typescript": "^7.10.0",
"otpauth": "^9.5.1", "otpauth": "^9.5.1",
"oxc-resolver": "11.24.2",
"oxfmt": "^0.38.0", "oxfmt": "^0.38.0",
"patch-package": "^8.0.1", "patch-package": "^8.0.1",
"pg": "^8.8.0", "pg": "^8.8.0",
@@ -827,11 +829,11 @@
"@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="], "@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="],
"@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], "@emnapi/core": ["@emnapi/core@1.11.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], "@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
"@emotion/babel-plugin": ["@emotion/babel-plugin@11.11.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.1", "@emotion/memoize": "^0.8.1", "@emotion/serialize": "^1.1.2", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", "stylis": "4.2.0" } }, "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ=="], "@emotion/babel-plugin": ["@emotion/babel-plugin@11.11.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.1", "@emotion/memoize": "^0.8.1", "@emotion/serialize": "^1.1.2", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", "stylis": "4.2.0" } }, "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ=="],
@@ -1167,7 +1169,7 @@
"@mswjs/interceptors": ["@mswjs/interceptors@0.37.6", "", { "dependencies": { "@open-draft/deferred-promise": "^2.2.0", "@open-draft/logger": "^0.3.0", "@open-draft/until": "^2.0.0", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "strict-event-emitter": "^0.5.1" } }, "sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w=="], "@mswjs/interceptors": ["@mswjs/interceptors@0.37.6", "", { "dependencies": { "@open-draft/deferred-promise": "^2.2.0", "@open-draft/logger": "^0.3.0", "@open-draft/until": "^2.0.0", "is-node-process": "^1.2.0", "outvariant": "^1.4.3", "strict-event-emitter": "^0.5.1" } }, "sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="],
"@nicolo-ribaudo/chokidar-2": ["@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3", "", {}, "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ=="], "@nicolo-ribaudo/chokidar-2": ["@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3", "", {}, "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ=="],
@@ -1217,6 +1219,44 @@
"@oxc-project/types": ["@oxc-project/types@0.139.0", "", {}, "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw=="], "@oxc-project/types": ["@oxc-project/types@0.139.0", "", {}, "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw=="],
"@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA=="],
"@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg=="],
"@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w=="],
"@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q=="],
"@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw=="],
"@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg=="],
"@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA=="],
"@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA=="],
"@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw=="],
"@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA=="],
"@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw=="],
"@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w=="],
"@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ=="],
"@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg=="],
"@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw=="],
"@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg=="],
"@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.24.2", "", { "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", "@napi-rs/wasm-runtime": "^1.1.6" }, "cpu": "none" }, "sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q=="],
"@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg=="],
"@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw=="],
"@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.38.0", "", { "os": "android", "cpu": "arm" }, "sha512-lTN4//sgYywK8ulQo7a/EZVzOTGomGQv2IG/7tMYdqTV3xN3QTqWpXcZBGUzaicC4B882N+5zJLYZ37IWfUMcg=="], "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.38.0", "", { "os": "android", "cpu": "arm" }, "sha512-lTN4//sgYywK8ulQo7a/EZVzOTGomGQv2IG/7tMYdqTV3xN3QTqWpXcZBGUzaicC4B882N+5zJLYZ37IWfUMcg=="],
"@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.38.0", "", { "os": "android", "cpu": "arm64" }, "sha512-XbVgqR1WsIcCkfxwh2tdg3M1MWgR23YOboW2nbB8ab0gInNNLGy7cIAdr78XaoG/bGdaF4488XRhuGWq67xrzA=="], "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.38.0", "", { "os": "android", "cpu": "arm64" }, "sha512-XbVgqR1WsIcCkfxwh2tdg3M1MWgR23YOboW2nbB8ab0gInNNLGy7cIAdr78XaoG/bGdaF4488XRhuGWq67xrzA=="],
@@ -1255,43 +1295,43 @@
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.38.0", "", { "os": "win32", "cpu": "x64" }, "sha512-wud1Hz0D2hYrhk6exxQQndn1htcA28wAcFb1vtP3ZXSzPFtMvc7ag/VNPv6nz6mDzM8X660jUwGEac99QcrVsA=="], "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.38.0", "", { "os": "win32", "cpu": "x64" }, "sha512-wud1Hz0D2hYrhk6exxQQndn1htcA28wAcFb1vtP3ZXSzPFtMvc7ag/VNPv6nz6mDzM8X660jUwGEac99QcrVsA=="],
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.58.0", "", { "os": "android", "cpu": "arm" }, "sha512-1T7UN3SsWWxpWyWGn1cT3ASNJOo+pI3eUkmEl7HgtowapcV8kslYpFQcYn431VuxghXakPNlbjRwhqmR37PFOg=="], "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.85.0", "", { "os": "android", "cpu": "arm" }, "sha512-q2KO/Zso9UT+OMn0NF9ywn4E4t0MI3yxiDhNyhsQ7DyQJrC4FhFE4TXOi4bktFnOWXTMds8qZSbpv2XwRaNOBg=="],
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.58.0", "", { "os": "android", "cpu": "arm64" }, "sha512-GryzujxuiRv2YFF7bRy8mKcxlbuAN+euVUtGJt9KKbLT8JBUIosamVhcthLh+VEr6KE6cjeVMAQxKAzJcoN7dg=="], "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.85.0", "", { "os": "android", "cpu": "arm64" }, "sha512-SxLN3ALjoT9NNdvpjEevGeHvfzTAFrF0NBYB5tzK7/GtCKMze3j1e/m/X2ozqGj2U9hfGG/dg/OG8vpVK4PiDA=="],
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.58.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7/bRSJIwl4GxeZL9rPZ11anNTyUO9epZrfEJH/ZMla3+/gbQ6xZixh9nOhsZ0QwsTW7/5J2A/fHbD1udC5DQQA=="], "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.85.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y/Sup/J4f0f9UGsSd/xyCNTeWL+gepO63GBdEDAfue9nBsnk9zMmnIXx1O6b1V8C90vB5nucYNZ0pbMXAp8zJA=="],
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.58.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-EqdtJSiHweS2vfILNrpyJ6HUwpEq2g7+4Zx1FPi4hu3Hu7tC3znF6ufbXO8Ub2LD4mGgznjI7kSdku9NDD1Mkg=="], "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.85.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ApOSNC04ynpDTwvBD+//0wyfODRSbEzvRoKpX8teffmc27z8AockwSNeMXGJXn5KP85eahDgR/2llICWLkzcnw=="],
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.58.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-VQt5TH4M42mY20F545G637RKxV/yjwVtKk2vfXuazfReSIiuvWBnv+FVSvIV5fKVTJNjt3GSJibh6JecbhGdBw=="], "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.85.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-bNrVrCOA/kHky3Tu79IXWXe5bhIgLXfUuUEDHlAGOHUk96MkvDZ1ecaQF19rwstrnaqfP1o9nBTqzIr9+ZHkUg=="],
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.58.0", "", { "os": "linux", "cpu": "arm" }, "sha512-fBYcj4ucwpAtjJT3oeBdFBYKvNyjRSK+cyuvBOTQjh0jvKp4yeA4S/D0IsCHus/VPaNG5L48qQkh+Vjy3HL2/Q=="], "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.85.0", "", { "os": "linux", "cpu": "arm" }, "sha512-NUrzOJ1s/EqsVvfn2L/1D8Wro2LPIZUbihL8kOJLh5fEdGEN3rdOGUYq3HwnUIL8sjpoP+4N6RaGrgmMJnaMPw=="],
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.58.0", "", { "os": "linux", "cpu": "arm" }, "sha512-0BeuFfwlUHlJ1xpEdSD1YO3vByEFGPg36uLjK1JgFaxFb4W6w17F8ET8sz5cheZ4+x5f2xzdnRrrWv83E3Yd8g=="], "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.85.0", "", { "os": "linux", "cpu": "arm" }, "sha512-UJXrAT3E/RWkEqXLIs2ehETja1qfgkPb+5gwLIIS+o/6cf+grHvoOXTa5997a/YNQfcJS0DRBTOfZt95cvOI1g=="],
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.58.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-TXlZgnPTlxrQzxG9ZXU7BNwx1Ilrr17P3GwZY0If2EzrinqRH3zXPc3HrRcBJgcsoZNMuNL5YivtkJYgp467UQ=="], "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.85.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-lK40QLjI0HxigO7CjDDshEtfYIeiYS0020v5BHFPqN4uuQBQxd2K9LNom2dW15o9F1937quSCRVp4ZsVhdbYdg=="],
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.58.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-zSoYRo5dxHLcUx93Stl2hW3hSNjPt99O70eRVWt5A1zwJ+FPjeCCANCD2a9R4JbHsdcl11TIQOjyigcRVOH2mw=="], "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.85.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-c2zbdBwGKreHXwRx3gWBuFGJxLhxgsg6YlZ+3H+RgRusU/UEV9jNwJ3HGYK+nRo0LvBa7mt6Kj86xoVotUo8cw=="],
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.58.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NQ0U/lqxH2/VxBYeAIvMNUK1y0a1bJ3ZicqkF2c6wfakbEciP9jvIE4yNzCFpZaqeIeRYaV7AVGqEO1yrfVPjA=="], "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.85.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tlt/Hy8lZ97/lCPmCgw/B3k/mwh+BzaIPbPkldZEly7TwLmx0xe2CQcaW2g/rR0dOgS9JNGCZsMEqLhUNMGvaw=="],
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-X9J+kr3gIC9FT8GuZt0ekzpNUtkBVzMVU4KiKDSlocyQuEgi3gBbXYN8UkQiV77FTusLDPsovjo95YedHr+3yg=="], "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.85.0", "", { "os": "linux", "cpu": "none" }, "sha512-3tNR9Xey82X0zKuY1d8hJ6Rc9gwRDurmqGLnQZa5xqOXy8/YyiqFXjAtugkKLY82obOlpK1eSiDRlgcNPuxtIg=="],
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.58.0", "", { "os": "linux", "cpu": "none" }, "sha512-CDze3pi1OO3Wvb/QsXjmLEY4XPKGM6kIo82ssNOgmcl1IdndF9VSGAE38YLhADWmOac7fjqhBw82LozuUVxD0Q=="], "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.85.0", "", { "os": "linux", "cpu": "none" }, "sha512-wbGRd5PqCcjkJFHhZuZ2OBSUQY9czlQsoA/cQQB9JK/L9mC5MQgGoKAh+xd8QjA5V+0D3j+Qd1lAWn1I8zlelA=="],
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.58.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-b/89glbxFaEAcA6Uf1FvCNecBJEgcUTsV1quzrqXM/o4R1M4u+2KCVuyGCayN2UpsRWtGGLb+Ver0tBBpxaPog=="], "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.85.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-3Sn0kSrE4DPZCWV/8o+n4x3aFZxI9ulMnkYlwCbJ8eUVkwRK2IerohE/A/z3SNbCwoPFOCJmGE5Avrq0rrvdvQ=="],
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.58.0", "", { "os": "linux", "cpu": "x64" }, "sha512-0/yYpkq9VJFCEcuRlrViGj8pJUFFvNS4EkEREaN7CB1EcLXJIaVSSa5eCihwBGXtOZxhnblWgxks9juRdNQI7w=="], "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.85.0", "", { "os": "linux", "cpu": "x64" }, "sha512-JY2pxxYfB62bAGfejljVCqc44etItehPuAyaeSAdMuEMtwNA00ggMnS66lC1oIhos6oOXUkuU6mZ9bpFh3BqWg=="],
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.58.0", "", { "os": "linux", "cpu": "x64" }, "sha512-hr6FNvmcAXiH+JxSvaJ4SJ1HofkdqEElXICW9sm3/Rd5eC3t7kzvmLyRAB3NngKO2wzXRCAm4Z/mGWfrsS4X8w=="], "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.85.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5k74vZ6qJBjBHEOlBk9B/iv68Yu0F1Afw/vvT2ar6OGCqEeXLaSjXz2n/IPCbhLG22UoKoYEJTzpYraRdcp6PA=="],
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.58.0", "", { "os": "none", "cpu": "arm64" }, "sha512-R+O368VXgRql1K6Xar+FEo7NEwfo13EibPMoTv3sesYQedRXd6m30Dh/7lZMxnrQVFfeo4EOfYIP4FpcgWQNHg=="], "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.85.0", "", { "os": "none", "cpu": "arm64" }, "sha512-GbAl5qt5TCkPLXTaIISZJnugrcBhra6rodcXc9jYt620UtdsTt71NlNmJmm0frxzFpd54x/G+MkitEJA8I/BoA=="],
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.58.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q0FZiAY/3c4YRj4z3h9K1PgaByrifrfbBoODSeX7gy97UtB7pySPUQfC2B/GbxWU6k7CzQrRy5gME10PltLAFQ=="], "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.85.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-kjmws5MK0et2swk4ND85D7NVQyDHw162i6whtZDLUA/lo6FQyBZDcmMRCMcVZcNrAhIaftVb00x9ChGDOjjNJA=="],
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.58.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-Y8FKBABrSPp9H0QkRLHDHOSUgM/309a3IvOVgPcVxYcX70wxJrk608CuTg7w+C6vEd724X5wJoNkBcGYfH7nNQ=="], "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.85.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-eSsIJx9n4yxvOqYTZyPEMyEXRmE60XH7xGAU7i0Qbsn1lf6Za3CWJ9aRd82oSFKXaxhp+sA6/yMJVRIpLpna6A=="],
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.58.0", "", { "os": "win32", "cpu": "x64" }, "sha512-bCn5rbiz5My+Bj7M09sDcnqW0QJyINRVxdZ65x1/Y2tGrMwherwK/lpk+HRQCKvXa8pcaQdF5KY5j54VGZLwNg=="], "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.85.0", "", { "os": "win32", "cpu": "x64" }, "sha512-pBebIPUpKKhWrhSMWhy8TdAZBewiXnfxmaAGxhzxM1068GagqFaTwgKlU6e+UyJ2sPR+VoHouhXuGJkQjsrDvA=="],
"@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="],
@@ -1695,7 +1735,7 @@
"@ts-morph/common": ["@ts-morph/common@0.26.0", "", { "dependencies": { "fast-glob": "^3.3.2", "minimatch": "^9.0.4", "path-browserify": "^1.0.1" } }, "sha512-/RmKAtctStXqM5nECMQ46duT74Hoig/DBzhWXGHcodlDNrgRbsbwwHqSKFNbca6z9Xt/CUWMeXOsC9QEN1+rqw=="], "@ts-morph/common": ["@ts-morph/common@0.26.0", "", { "dependencies": { "fast-glob": "^3.3.2", "minimatch": "^9.0.4", "path-browserify": "^1.0.1" } }, "sha512-/RmKAtctStXqM5nECMQ46duT74Hoig/DBzhWXGHcodlDNrgRbsbwwHqSKFNbca6z9Xt/CUWMeXOsC9QEN1+rqw=="],
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="],
"@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="], "@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="],
@@ -1931,25 +1971,25 @@
"@types/yoga-layout": ["@types/yoga-layout@1.9.2", "", {}, "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw=="], "@types/yoga-layout": ["@types/yoga-layout@1.9.2", "", {}, "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.54.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/type-utils": "8.54.0", "@typescript-eslint/utils": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ=="], "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.60.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.60.0", "@typescript-eslint/type-utils": "8.60.0", "@typescript-eslint/utils": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.60.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.60.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.60.0", "@typescript-eslint/types": "8.60.0", "@typescript-eslint/typescript-estree": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg=="], "@typescript-eslint/parser": ["@typescript-eslint/parser@8.60.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.60.0", "@typescript-eslint/types": "8.60.0", "@typescript-eslint/typescript-estree": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.60.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.60.0", "@typescript-eslint/types": "^8.60.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg=="], "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.60.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.60.0", "@typescript-eslint/types": "^8.60.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="], "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0" } }, "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.60.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ=="], "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.60.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA=="], "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "@typescript-eslint/typescript-estree": "8.60.0", "@typescript-eslint/utils": "8.60.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="], "@typescript-eslint/types": ["@typescript-eslint/types@8.60.0", "", {}, "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.60.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.60.0", "@typescript-eslint/tsconfig-utils": "8.60.0", "@typescript-eslint/types": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g=="], "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.60.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.60.0", "@typescript-eslint/tsconfig-utils": "8.60.0", "@typescript-eslint/types": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="], "@typescript-eslint/utils": ["@typescript-eslint/utils@8.60.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.60.0", "@typescript-eslint/types": "8.60.0", "@typescript-eslint/typescript-estree": "8.60.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="], "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg=="],
"@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="], "@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="],
@@ -2937,19 +2977,17 @@
"eslint-plugin-cypress": ["eslint-plugin-cypress@6.1.0", "", { "dependencies": { "globals": "^17.3.0" }, "peerDependencies": { "eslint": ">=9" } }, "sha512-B8sxtNpINDxFkmsu1qKYjg70VsP8SGneEXgLcZMk1bUZcW08S+JyaiMdof1x6dmt02FgOD7YkT4wOaOD5HotJw=="], "eslint-plugin-cypress": ["eslint-plugin-cypress@6.1.0", "", { "dependencies": { "globals": "^17.3.0" }, "peerDependencies": { "eslint": ">=9" } }, "sha512-B8sxtNpINDxFkmsu1qKYjg70VsP8SGneEXgLcZMk1bUZcW08S+JyaiMdof1x6dmt02FgOD7YkT4wOaOD5HotJw=="],
"eslint-plugin-depend": ["eslint-plugin-depend@1.4.0", "", { "dependencies": { "empathic": "^2.0.0", "module-replacements": "^2.10.1", "semver": "^7.6.3" } }, "sha512-MQs+m4nHSfgAO9bJDsBzqw0ofK/AOA0vfeY/6ahofqcUMLeM6/D1sTYs21fOhc17kNU/gn58YCtj20XaAssh2A=="], "eslint-plugin-depend": ["eslint-plugin-depend@1.5.0", "", { "dependencies": { "empathic": "^2.0.0", "module-replacements": "^2.10.1", "semver": "^7.6.3" }, "peerDependencies": { "eslint": ">=8.40.0" } }, "sha512-i3UeLYmclf1Icp35+6W7CR4Bp2PIpDgBuf/mpmXK5UeLkZlvYJ21VuQKKHHAIBKRTPivPGX/gZl5JGno1o9Y0A=="],
"eslint-plugin-i18next": ["eslint-plugin-i18next@6.1.3", "", { "dependencies": { "lodash": "^4.17.21", "requireindex": "~1.1.0" } }, "sha512-z/h4oBRd9wI1ET60HqcLSU6XPeAh/EPOrBBTyCdkWeMoYrWAaUVA+DOQkWTiNIyCltG4NTmy62SQisVXxoXurw=="], "eslint-plugin-i18next": ["eslint-plugin-i18next@6.1.4", "", { "dependencies": { "lodash": "^4.17.21", "requireindex": "~1.1.0" } }, "sha512-BekXQu1VaVFkREepQGsntBYoKuPsf89V16n/s2xpKMtsw0/lDseds1wBhj3RtO1dKnHsfTPaG+xul1vF0R7LEQ=="],
"eslint-plugin-import-x": ["eslint-plugin-import-x@4.16.1", "", { "dependencies": { "@typescript-eslint/types": "^8.35.0", "comment-parser": "^1.4.1", "debug": "^4.4.1", "eslint-import-context": "^0.1.9", "is-glob": "^4.0.3", "minimatch": "^9.0.3 || ^10.0.1", "semver": "^7.7.2", "stable-hash-x": "^0.2.0", "unrs-resolver": "^1.9.2" }, "peerDependencies": { "@typescript-eslint/utils": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "eslint-import-resolver-node": "*" }, "optionalPeers": ["@typescript-eslint/utils", "eslint-import-resolver-node"] }, "sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ=="], "eslint-plugin-import-x": ["eslint-plugin-import-x@4.17.1", "", { "dependencies": { "@typescript-eslint/types": "^8.56.0", "comment-parser": "^1.4.1", "debug": "^4.4.1", "eslint-import-context": "^0.1.9", "is-glob": "^4.0.3", "minimatch": "^9.0.3 || ^10.1.2", "semver": "^7.7.2", "stable-hash-x": "^0.2.0", "unrs-resolver": "^1.9.2" }, "peerDependencies": { "@typescript-eslint/utils": "^8.56.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "eslint-import-resolver-node": "*" }, "optionalPeers": ["@typescript-eslint/utils", "eslint-import-resolver-node"] }, "sha512-4cdstYkKCyjumM2Q9NSI03K8D2a9F4Ssz33K2lv2hQa4KmR9jPLwk3uWGtNvclfqBrPGfGuMBwsGMbe6dMRbfg=="],
"eslint-plugin-jest": ["eslint-plugin-jest@29.12.1", "", { "dependencies": { "@typescript-eslint/utils": "^8.0.0" }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "jest": "*" }, "optionalPeers": ["@typescript-eslint/eslint-plugin", "jest"] }, "sha512-Rxo7r4jSANMBkXLICJKS0gjacgyopfNAsoS0e3R9AHnjoKuQOaaPfmsDJPi8UWwygI099OV/K/JhpYRVkxD4AA=="], "eslint-plugin-jest": ["eslint-plugin-jest@29.12.1", "", { "dependencies": { "@typescript-eslint/utils": "^8.0.0" }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "jest": "*" }, "optionalPeers": ["@typescript-eslint/eslint-plugin", "jest"] }, "sha512-Rxo7r4jSANMBkXLICJKS0gjacgyopfNAsoS0e3R9AHnjoKuQOaaPfmsDJPi8UWwygI099OV/K/JhpYRVkxD4AA=="],
"eslint-plugin-jest-dom": ["eslint-plugin-jest-dom@5.5.0", "", { "dependencies": { "@babel/runtime": "^7.16.3", "requireindex": "^1.2.0" }, "peerDependencies": { "@testing-library/dom": "^8.0.0 || ^9.0.0 || ^10.0.0", "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "optionalPeers": ["@testing-library/dom"] }, "sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA=="], "eslint-plugin-jest-dom": ["eslint-plugin-jest-dom@5.5.0", "", { "dependencies": { "@babel/runtime": "^7.16.3", "requireindex": "^1.2.0" }, "peerDependencies": { "@testing-library/dom": "^8.0.0 || ^9.0.0 || ^10.0.0", "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "optionalPeers": ["@testing-library/dom"] }, "sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA=="],
"eslint-plugin-jest-formatting": ["eslint-plugin-jest-formatting@3.1.0", "", {}, "sha512-XyysraZ1JSgGbLSDxjj5HzKKh0glgWf+7CkqxbTqb7zEhW7X2WHo5SBQ8cGhnszKN+2Lj3/oevBlHNbHezoc/A=="], "eslint-plugin-no-only-tests": ["eslint-plugin-no-only-tests@3.4.0", "", {}, "sha512-4S3/9Nb7A2tiMcpzEQE9bQSlpeOz6WJkgryBuou/SA8W2x2c8Zf4j0NvTKBjv6qNhF9T79tmkecm/0CHqV0UGg=="],
"eslint-plugin-no-only-tests": ["eslint-plugin-no-only-tests@3.3.0", "", {}, "sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q=="],
"eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="],
@@ -4129,9 +4167,11 @@
"own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="],
"oxc-resolver": ["oxc-resolver@11.24.2", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.24.2", "@oxc-resolver/binding-android-arm64": "11.24.2", "@oxc-resolver/binding-darwin-arm64": "11.24.2", "@oxc-resolver/binding-darwin-x64": "11.24.2", "@oxc-resolver/binding-freebsd-x64": "11.24.2", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.24.2", "@oxc-resolver/binding-linux-arm-musleabihf": "11.24.2", "@oxc-resolver/binding-linux-arm64-gnu": "11.24.2", "@oxc-resolver/binding-linux-arm64-musl": "11.24.2", "@oxc-resolver/binding-linux-ppc64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-musl": "11.24.2", "@oxc-resolver/binding-linux-s390x-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-musl": "11.24.2", "@oxc-resolver/binding-openharmony-arm64": "11.24.2", "@oxc-resolver/binding-wasm32-wasi": "11.24.2", "@oxc-resolver/binding-win32-arm64-msvc": "11.24.2", "@oxc-resolver/binding-win32-x64-msvc": "11.24.2" } }, "sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw=="],
"oxfmt": ["oxfmt@0.38.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.38.0", "@oxfmt/binding-android-arm64": "0.38.0", "@oxfmt/binding-darwin-arm64": "0.38.0", "@oxfmt/binding-darwin-x64": "0.38.0", "@oxfmt/binding-freebsd-x64": "0.38.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.38.0", "@oxfmt/binding-linux-arm-musleabihf": "0.38.0", "@oxfmt/binding-linux-arm64-gnu": "0.38.0", "@oxfmt/binding-linux-arm64-musl": "0.38.0", "@oxfmt/binding-linux-ppc64-gnu": "0.38.0", "@oxfmt/binding-linux-riscv64-gnu": "0.38.0", "@oxfmt/binding-linux-riscv64-musl": "0.38.0", "@oxfmt/binding-linux-s390x-gnu": "0.38.0", "@oxfmt/binding-linux-x64-gnu": "0.38.0", "@oxfmt/binding-linux-x64-musl": "0.38.0", "@oxfmt/binding-openharmony-arm64": "0.38.0", "@oxfmt/binding-win32-arm64-msvc": "0.38.0", "@oxfmt/binding-win32-ia32-msvc": "0.38.0", "@oxfmt/binding-win32-x64-msvc": "0.38.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-RGYfnnxmCz8dMQ1Oo5KrYkNRc9cne2WL2vfE+datWNkgiSAkfUsqpGLR7rnkN6cQFgQkHDZH400eXN6izJ8Lww=="], "oxfmt": ["oxfmt@0.38.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.38.0", "@oxfmt/binding-android-arm64": "0.38.0", "@oxfmt/binding-darwin-arm64": "0.38.0", "@oxfmt/binding-darwin-x64": "0.38.0", "@oxfmt/binding-freebsd-x64": "0.38.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.38.0", "@oxfmt/binding-linux-arm-musleabihf": "0.38.0", "@oxfmt/binding-linux-arm64-gnu": "0.38.0", "@oxfmt/binding-linux-arm64-musl": "0.38.0", "@oxfmt/binding-linux-ppc64-gnu": "0.38.0", "@oxfmt/binding-linux-riscv64-gnu": "0.38.0", "@oxfmt/binding-linux-riscv64-musl": "0.38.0", "@oxfmt/binding-linux-s390x-gnu": "0.38.0", "@oxfmt/binding-linux-x64-gnu": "0.38.0", "@oxfmt/binding-linux-x64-musl": "0.38.0", "@oxfmt/binding-openharmony-arm64": "0.38.0", "@oxfmt/binding-win32-arm64-msvc": "0.38.0", "@oxfmt/binding-win32-ia32-msvc": "0.38.0", "@oxfmt/binding-win32-x64-msvc": "0.38.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-RGYfnnxmCz8dMQ1Oo5KrYkNRc9cne2WL2vfE+datWNkgiSAkfUsqpGLR7rnkN6cQFgQkHDZH400eXN6izJ8Lww=="],
"oxlint": ["oxlint@1.58.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.58.0", "@oxlint/binding-android-arm64": "1.58.0", "@oxlint/binding-darwin-arm64": "1.58.0", "@oxlint/binding-darwin-x64": "1.58.0", "@oxlint/binding-freebsd-x64": "1.58.0", "@oxlint/binding-linux-arm-gnueabihf": "1.58.0", "@oxlint/binding-linux-arm-musleabihf": "1.58.0", "@oxlint/binding-linux-arm64-gnu": "1.58.0", "@oxlint/binding-linux-arm64-musl": "1.58.0", "@oxlint/binding-linux-ppc64-gnu": "1.58.0", "@oxlint/binding-linux-riscv64-gnu": "1.58.0", "@oxlint/binding-linux-riscv64-musl": "1.58.0", "@oxlint/binding-linux-s390x-gnu": "1.58.0", "@oxlint/binding-linux-x64-gnu": "1.58.0", "@oxlint/binding-linux-x64-musl": "1.58.0", "@oxlint/binding-openharmony-arm64": "1.58.0", "@oxlint/binding-win32-arm64-msvc": "1.58.0", "@oxlint/binding-win32-ia32-msvc": "1.58.0", "@oxlint/binding-win32-x64-msvc": "1.58.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-t4s9leczDMqlvOSjnbCQe7gtoLkWgBGZ7sBdCJ9EOj5IXFSG/X7OAzK4yuH4iW+4cAYe8kLFbC8tuYMwWZm+Cg=="], "oxlint": ["oxlint@1.85.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.85.0", "@oxlint/binding-android-arm64": "1.85.0", "@oxlint/binding-darwin-arm64": "1.85.0", "@oxlint/binding-darwin-x64": "1.85.0", "@oxlint/binding-freebsd-x64": "1.85.0", "@oxlint/binding-linux-arm-gnueabihf": "1.85.0", "@oxlint/binding-linux-arm-musleabihf": "1.85.0", "@oxlint/binding-linux-arm64-gnu": "1.85.0", "@oxlint/binding-linux-arm64-musl": "1.85.0", "@oxlint/binding-linux-ppc64-gnu": "1.85.0", "@oxlint/binding-linux-riscv64-gnu": "1.85.0", "@oxlint/binding-linux-riscv64-musl": "1.85.0", "@oxlint/binding-linux-s390x-gnu": "1.85.0", "@oxlint/binding-linux-x64-gnu": "1.85.0", "@oxlint/binding-linux-x64-musl": "1.85.0", "@oxlint/binding-openharmony-arm64": "1.85.0", "@oxlint/binding-win32-arm64-msvc": "1.85.0", "@oxlint/binding-win32-ia32-msvc": "1.85.0", "@oxlint/binding-win32-x64-msvc": "1.85.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-bc26s97nuvPj1ViyPsqmKecVkUWFMEdtayO8MaQ6oiLfs1pj94cQlZZhrh4BPNlr9HQosjhIlwgZKsfcwmcNgg=="],
"p-limit": ["p-limit@7.3.0", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw=="], "p-limit": ["p-limit@7.3.0", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw=="],
@@ -5069,7 +5109,7 @@
"ts-algebra": ["ts-algebra@1.2.2", "", {}, "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA=="], "ts-algebra": ["ts-algebra@1.2.2", "", {}, "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA=="],
"ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
"ts-dedent": ["ts-dedent@2.2.0", "", {}, "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ=="], "ts-dedent": ["ts-dedent@2.2.0", "", {}, "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ=="],
@@ -5579,12 +5619,16 @@
"@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="], "@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
"@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="],
"@rollup/pluginutils/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@rollup/pluginutils/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@rollup/pluginutils/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], "@rollup/pluginutils/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
"@rspack/binding-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
"@rspack/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
"@rspack/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="],
"@rushstack/node-core-library/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], "@rushstack/node-core-library/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
"@rushstack/node-core-library/fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], "@rushstack/node-core-library/fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="],
@@ -5667,7 +5711,7 @@
"@ts-morph/common/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@ts-morph/common/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@tybys/wasm-util/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="], "@tybys/wasm-util/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@types/d3-contour/@types/geojson": ["@types/geojson@7946.0.8", "", {}, "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="], "@types/d3-contour/@types/geojson": ["@types/geojson@7946.0.8", "", {}, "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="],
@@ -5687,37 +5731,15 @@
"@types/leaflet/@types/geojson": ["@types/geojson@7946.0.8", "", {}, "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="], "@types/leaflet/@types/geojson": ["@types/geojson@7946.0.8", "", {}, "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="],
"@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0" } }, "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw=="], "@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
"@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.60.0", "", {}, "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA=="], "@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="],
"@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg=="],
"@typescript-eslint/project-service/@typescript-eslint/types": ["@typescript-eslint/types@8.60.0", "", {}, "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA=="],
"@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="],
"@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.60.0", "", {}, "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA=="],
"@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], "@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="],
"@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="],
"@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
@@ -6053,11 +6075,13 @@
"eslint-plugin-cypress/globals": ["globals@17.3.0", "", {}, "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw=="], "eslint-plugin-cypress/globals": ["globals@17.3.0", "", {}, "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw=="],
"eslint-plugin-depend/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "eslint-plugin-depend/semver": ["semver@7.8.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg=="],
"eslint-plugin-import-x/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "eslint-plugin-import-x/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
"eslint-plugin-import-x/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "eslint-plugin-import-x/semver": ["semver@7.8.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg=="],
"eslint-plugin-jest/@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="],
"eslint-plugin-jest-dom/requireindex": ["requireindex@1.2.0", "", {}, "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww=="], "eslint-plugin-jest-dom/requireindex": ["requireindex@1.2.0", "", {}, "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww=="],
@@ -6067,6 +6091,8 @@
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"eslint-plugin-storybook/@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="],
"espree/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "espree/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], "espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
@@ -6805,10 +6831,6 @@
"typedoc/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "typedoc/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
"typescript-eslint/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.60.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.60.0", "@typescript-eslint/type-utils": "8.60.0", "@typescript-eslint/utils": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.60.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw=="],
"typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.60.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.60.0", "@typescript-eslint/types": "8.60.0", "@typescript-eslint/typescript-estree": "8.60.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA=="],
"unbox-primitive/which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], "unbox-primitive/which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="],
"unified/@types/unist": ["@types/unist@3.0.2", "", {}, "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ=="], "unified/@types/unist": ["@types/unist@3.0.2", "", {}, "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ=="],
@@ -7057,13 +7079,17 @@
"@redocly/cli/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], "@redocly/cli/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
"@rolldown/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
"@rolldown/binding-wasm32-wasi/@emnapi/core/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@rolldown/binding-wasm32-wasi/@emnapi/core/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@rolldown/binding-wasm32-wasi/@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@rolldown/binding-wasm32-wasi/@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], "@rspack/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"@rspack/binding-wasm32-wasi/@emnapi/core/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@rspack/binding-wasm32-wasi/@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@rspack/binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@storybook/addon-docs/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], "@storybook/addon-docs/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
@@ -7103,32 +7129,16 @@
"@types/jest/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "@types/jest/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"@typescript-eslint/parser/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="], "@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"@typescript-eslint/parser/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="], "@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@visx/curve/@types/d3-shape/@types/d3-path": ["@types/d3-path@1.0.11", "", {}, "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw=="], "@visx/curve/@types/d3-shape/@types/d3-path": ["@types/d3-path@1.0.11", "", {}, "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw=="],
"@visx/vendor/@types/d3-interpolate/@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], "@visx/vendor/@types/d3-interpolate/@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
@@ -7303,8 +7313,6 @@
"detective-typescript/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "detective-typescript/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"detective-typescript/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
"es-get-iterator/get-intrinsic/has-proto": ["has-proto@1.0.1", "", {}, "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="], "es-get-iterator/get-intrinsic/has-proto": ["has-proto@1.0.1", "", {}, "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="],
"es-get-iterator/get-intrinsic/hasown": ["hasown@2.0.1", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA=="], "es-get-iterator/get-intrinsic/hasown": ["hasown@2.0.1", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA=="],
@@ -7321,10 +7329,20 @@
"eslint-import-resolver-webpack/resolve/is-core-module": ["is-core-module@2.13.1", "", { "dependencies": { "hasown": "^2.0.0" } }, "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw=="], "eslint-import-resolver-webpack/resolve/is-core-module": ["is-core-module@2.13.1", "", { "dependencies": { "hasown": "^2.0.0" } }, "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw=="],
"eslint-plugin-import-x/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], "eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="],
"eslint-plugin-react/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "eslint-plugin-react/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="],
"eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"eslint/ajv/uri-js": ["uri-js@4.4.0", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g=="], "eslint/ajv/uri-js": ["uri-js@4.4.0", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g=="],
@@ -7811,18 +7829,6 @@
"typed-array-length/is-typed-array/which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], "typed-array-length/is-typed-array/which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0" } }, "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "@typescript-eslint/typescript-estree": "8.60.0", "@typescript-eslint/utils": "8.60.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.0", "", { "dependencies": { "@typescript-eslint/types": "8.60.0", "@typescript-eslint/visitor-keys": "8.60.0" } }, "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw=="],
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.60.0", "", {}, "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA=="],
"unbox-primitive/which-boxed-primitive/is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], "unbox-primitive/which-boxed-primitive/is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="],
"unbox-primitive/which-boxed-primitive/is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], "unbox-primitive/which-boxed-primitive/is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="],
@@ -7973,7 +7979,7 @@
"@redocly/cli/glob/minimatch/brace-expansion": ["brace-expansion@5.0.2", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw=="], "@redocly/cli/glob/minimatch/brace-expansion": ["brace-expansion@5.0.2", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw=="],
"@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "@rspack/binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="],
"@storybook/addon-webpack5-compiler-babel/babel-loader/find-cache-dir/pkg-dir": ["pkg-dir@7.0.0", "", { "dependencies": { "find-up": "^6.3.0" } }, "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA=="], "@storybook/addon-webpack5-compiler-babel/babel-loader/find-cache-dir/pkg-dir": ["pkg-dir@7.0.0", "", { "dependencies": { "find-up": "^6.3.0" } }, "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA=="],
@@ -7995,20 +8001,14 @@
"@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"@typescript-eslint/parser/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"@typescript-eslint/parser/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/runtime/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util/tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="],
"@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@vue/compiler-sfc/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
@@ -8089,7 +8089,33 @@
"eslint-import-resolver-webpack/resolve/is-core-module/hasown": ["hasown@2.0.1", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA=="], "eslint-import-resolver-webpack/resolve/is-core-module/hasown": ["hasown@2.0.1", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA=="],
"eslint-plugin-import-x/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
"eslint/ajv/uri-js/punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="], "eslint/ajv/uri-js/punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="],
@@ -8397,10 +8423,6 @@
"test-exclude/glob/path-scurry/lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="], "test-exclude/glob/path-scurry/lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.60.0", "", {}, "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
"webpack-dev-middleware/schema-utils/ajv-formats/ajv": ["ajv@8.10.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw=="], "webpack-dev-middleware/schema-utils/ajv-formats/ajv": ["ajv@8.10.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw=="],
"webpack/browserslist/update-browserslist-db/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "webpack/browserslist/update-browserslist-db/escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
@@ -8497,10 +8519,6 @@
"@storybook/builder-webpack5/terser-webpack-plugin/schema-utils/ajv-formats/ajv": ["ajv@8.10.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw=="], "@storybook/builder-webpack5/terser-webpack-plugin/schema-utils/ajv-formats/ajv": ["ajv@8.10.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"assert/object.assign/call-bind/get-intrinsic/has-proto": ["has-proto@1.0.1", "", {}, "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="], "assert/object.assign/call-bind/get-intrinsic/has-proto": ["has-proto@1.0.1", "", {}, "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="],
"assert/object.assign/call-bind/get-intrinsic/hasown": ["hasown@2.0.1", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA=="], "assert/object.assign/call-bind/get-intrinsic/hasown": ["hasown@2.0.1", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA=="],
@@ -8519,6 +8537,18 @@
"es-get-iterator/stop-iteration-iterator/internal-slot/side-channel/object-inspect": ["object-inspect@1.13.0", "", {}, "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g=="], "es-get-iterator/stop-iteration-iterator/internal-slot/side-channel/object-inspect": ["object-inspect@1.13.0", "", {}, "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"fork-ts-checker-webpack-plugin/schema-utils/ajv/uri-js/punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="], "fork-ts-checker-webpack-plugin/schema-utils/ajv/uri-js/punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="],
"is-typed-array/es-abstract/function.prototype.name/define-properties/has-property-descriptors": ["has-property-descriptors@1.0.0", "", { "dependencies": { "get-intrinsic": "^1.1.1" } }, "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ=="], "is-typed-array/es-abstract/function.prototype.name/define-properties/has-property-descriptors": ["has-property-descriptors@1.0.0", "", { "dependencies": { "get-intrinsic": "^1.1.1" } }, "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ=="],
@@ -8679,10 +8709,6 @@
"test-exclude/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.2", "", { "dependencies": { "jackspeak": "^4.2.3" } }, "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg=="], "test-exclude/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.2", "", { "dependencies": { "jackspeak": "^4.2.3" } }, "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"webpack-dev-middleware/schema-utils/ajv-formats/ajv/uri-js": ["uri-js@4.4.0", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g=="], "webpack-dev-middleware/schema-utils/ajv-formats/ajv/uri-js": ["uri-js@4.4.0", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g=="],
"webpack/schema-utils/ajv-formats/ajv/uri-js": ["uri-js@4.4.0", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g=="], "webpack/schema-utils/ajv-formats/ajv/uri-js": ["uri-js@4.4.0", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g=="],
@@ -8731,6 +8757,10 @@
"compression-rspack-plugin/schema-utils/ajv-formats/ajv/uri-js/punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="], "compression-rspack-plugin/schema-utils/ajv-formats/ajv/uri-js/punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="],
"eslint-plugin-jest/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"jest-config/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "jest-config/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
"jest-config/glob/jackspeak/@isaacs/cliui/string-width/strip-ansi": ["strip-ansi@7.0.1", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw=="], "jest-config/glob/jackspeak/@isaacs/cliui/string-width/strip-ansi": ["strip-ansi@7.0.1", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw=="],

View File

@@ -174,11 +174,11 @@ const output = c("{0} and {2} are people's names, and {1} is a place")
The first rule of frontend style, is we want to avoid talking about frontend style. Wherever possible, style-level considerations should be encapsulated in lint rules. The first rule of frontend style, is we want to avoid talking about frontend style. Wherever possible, style-level considerations should be encapsulated in lint rules.
### oxfmt + ESlint ### oxfmt + oxlint
We use [oxfmt](https://oxc.rs/) to format our JavaScript and TypeScript code, and it is enforced by CI. We recommend setting your editor to "format on save". You can also format code using `bun run format`, and verify it has been formatted correctly using `bun run lint-format-pure`. We use [oxfmt](https://oxc.rs/) to format our JavaScript and TypeScript code, and it is enforced by CI. We recommend setting your editor to "format on save". You can also format code using `bun run format`, and verify it has been formatted correctly using `bun run lint-format-pure`. Oxfmt also sorts imports, so `bun run format` fixes import order too.
We use ESLint to enforce additional rules. It is integrated into the Webpack build, or you can manually run `bun run lint-eslint` to check. Nitpicky things like import order, spacing, etc. are all enforced by eslint. We use [oxlint](https://oxc.rs/) to enforce JavaScript and TypeScript lint rules, including module boundaries. Run `bun run lint-oxlint` to lint, or `bun run lint-oxlint-fix` to apply lint fixes. Both commands build the CLJS output first. If you've already built it, `bun run lint-oxlint-pure` skips that step. For how the lint configuration works, see `frontend/lint/OXLINT.md`.
### Miscellaneous notes on coding style ### Miscellaneous notes on coding style

View File

@@ -1,11 +1,11 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { createProbes } from "./probes";
import { import {
REACT_PROBES, REACT_PROBES,
ReactProbeHost, ReactProbeHost,
useProbeCustomElement, useProbeCustomElement,
} from "./ReactProbes"; } from "./ReactProbes";
import { createProbes } from "./probes";
import type { ReactMode } from "./types"; import type { ReactMode } from "./types";
import { describeError, getEnv } from "./utils"; import { describeError, getEnv } from "./utils";

View File

@@ -1,5 +1,4 @@
import "cypress-iframe"; import "cypress-iframe";
// this is the only place we allow direct helper import // this is the only place we allow direct helper import
// eslint-disable-next-line metabase/no-direct-helper-import // eslint-disable-next-line metabase/no-direct-helper-import
import { H } from "e2e/support"; import { H } from "e2e/support";
@@ -7,25 +6,17 @@ import { H } from "e2e/support";
import "./commands/ui/button"; import "./commands/ui/button";
import "./commands/ui/icon"; import "./commands/ui/icon";
import "./commands/ui/paste"; import "./commands/ui/paste";
import "./commands/user/createUser"; import "./commands/user/createUser";
import "./commands/user/authentication"; import "./commands/user/authentication";
import "./commands/permissions/updatePermissions"; import "./commands/permissions/updatePermissions";
import "./commands/permissions/sandboxTable"; import "./commands/permissions/sandboxTable";
import "./commands/database/addSQLiteDatabase"; import "./commands/database/addSQLiteDatabase";
import "./commands/visibility/isVisibleInPopover"; import "./commands/visibility/isVisibleInPopover";
import "./commands/visibility/findByTextEnsureVisible"; import "./commands/visibility/findByTextEnsureVisible";
import "./commands/visibility/isRenderedWithinViewport"; import "./commands/visibility/isRenderedWithinViewport";
import "./commands/overwrites/log"; import "./commands/overwrites/log";
import "./commands/skip-test"; import "./commands/skip-test";
import "./commands/component"; import "./commands/component";
import { addCustomCommands } from "./commands/downloads/downloadUtils"; import { addCustomCommands } from "./commands/downloads/downloadUtils";
addCustomCommands(); addCustomCommands();

View File

@@ -1,11 +1,9 @@
// To apply cypress-level mantine styles // To apply cypress-level mantine styles
import "@mantine/core/styles.css"; import "@mantine/core/styles.css";
import "@mantine/dates/styles.css"; import "@mantine/dates/styles.css";
// Mimics behavior when an app adds its own styles // Mimics behavior when an app adds its own styles
// We need to do it before importing the SDK // We need to do it before importing the SDK
import "e2e/support/helpers/embedding-sdk-helpers/host-app-styles.css"; import "e2e/support/helpers/embedding-sdk-helpers/host-app-styles.css";
import { Button, MantineProvider, Title } from "@mantine/core"; import { Button, MantineProvider, Title } from "@mantine/core";
import { import {
InteractiveQuestion, InteractiveQuestion,

View File

@@ -6,7 +6,6 @@
* bun run build:custom-viz-fixtures * bun run build:custom-viz-fixtures
*/ */
/* global console */
import { execFileSync } from "node:child_process"; import { execFileSync } from "node:child_process";
import { cpSync, mkdirSync, rmSync, statSync } from "node:fs"; import { cpSync, mkdirSync, rmSync, statSync } from "node:fs";
import { dirname, resolve } from "node:path"; import { dirname, resolve } from "node:path";
@@ -37,7 +36,10 @@ const visualizations = [
}, },
{ {
index: resolve(PLUGIN_ROOT, "src/index-widget-security-component.tsx"), index: resolve(PLUGIN_ROOT, "src/index-widget-security-component.tsx"),
manifest: resolve(PLUGIN_ROOT, "manifests/demo-viz-security-component.json"), manifest: resolve(
PLUGIN_ROOT,
"manifests/demo-viz-security-component.json",
),
out: resolve( out: resolve(
E2E_ASSETS, E2E_ASSETS,
"example_custom_viz_plugin_4_security_component.tgz", "example_custom_viz_plugin_4_security_component.tgz",

View File

@@ -1,5 +1,6 @@
import type { MouseEvent } from "react"; import type { MouseEvent } from "react";
import { useState } from "react"; import { useState } from "react";
import { type CustomVisualizationProps, formatValue } from "../../../src/index"; import { type CustomVisualizationProps, formatValue } from "../../../src/index";
type Settings = { type Settings = {

View File

@@ -1,5 +1,6 @@
import { defineConfig } from "../../../src/index"; import { defineConfig } from "../../../src/index";
import type { CreateCustomVisualization } from "../../../src/types/viz"; import type { CreateCustomVisualization } from "../../../src/types/viz";
import { Visualization } from "./Visualization"; import { Visualization } from "./Visualization";
type Settings = { type Settings = {

View File

@@ -3,6 +3,7 @@ import type {
BaseWidgetProps, BaseWidgetProps,
CreateCustomVisualization, CreateCustomVisualization,
} from "../../../src/types/viz"; } from "../../../src/types/viz";
import { Visualization } from "./Visualization"; import { Visualization } from "./Visualization";
type Settings = { type Settings = {

View File

@@ -3,12 +3,6 @@
import type { AsyncThunkAction } from "@reduxjs/toolkit"; import type { AsyncThunkAction } from "@reduxjs/toolkit";
import { EMBEDDING_SDK_PACKAGE_UNKNOWN_VERSION } from "build-configs/embedding-sdk/constants/versions"; import { EMBEDDING_SDK_PACKAGE_UNKNOWN_VERSION } from "build-configs/embedding-sdk/constants/versions";
import {
connectToInstanceAuthSso,
jwtDefaultRefreshTokenFunction,
openSamlLoginPopup,
validateSession,
} from "embedding/auth-common";
import { getIsLocalhost } from "embedding-sdk-bundle/lib/get-is-localhost"; import { getIsLocalhost } from "embedding-sdk-bundle/lib/get-is-localhost";
import { import {
PLUGIN_EMBEDDING_SDK_AUTH, PLUGIN_EMBEDDING_SDK_AUTH,
@@ -28,15 +22,18 @@ import { getWindow } from "embedding-sdk-shared/lib/get-window";
import type { MetabaseAuthConfig } from "embedding-sdk-shared/types/auth-config"; import type { MetabaseAuthConfig } from "embedding-sdk-shared/types/auth-config";
import type { SdkAuthState } from "embedding-sdk-shared/types/auth-state"; import type { SdkAuthState } from "embedding-sdk-shared/types/auth-state";
import { SDK_AUTH_STATE_KEY } from "embedding-sdk-shared/types/auth-state"; import { SDK_AUTH_STATE_KEY } from "embedding-sdk-shared/types/auth-state";
import {
connectToInstanceAuthSso,
jwtDefaultRefreshTokenFunction,
openSamlLoginPopup,
validateSession,
} from "embedding/auth-common";
import { PLUGIN_API } from "metabase/api/client"; import { PLUGIN_API } from "metabase/api/client";
import { import {
currentUserApi, currentUserApi,
loadCurrentUser, loadCurrentUser,
refetchCurrentUser, refetchCurrentUser,
} from "metabase/current-user"; } from "metabase/current-user";
import { requestSessionTokenFromEmbedJs } from "metabase/embedding/embedding-iframe-sdk/utils";
import { getSessionTokenHeaders } from "metabase/embedding/lib/auth/get-session-token-headers";
import { setApiKeyHeader } from "metabase/embedding/lib/auth/set-api-key-header";
import { import {
EMBEDDING_SDK_IFRAME_EMBEDDING_CONFIG, EMBEDDING_SDK_IFRAME_EMBEDDING_CONFIG,
isEmbeddingEajs, isEmbeddingEajs,
@@ -44,6 +41,9 @@ import {
} from "metabase/embedding-sdk/config"; } from "metabase/embedding-sdk/config";
import { samlTokenStorage } from "metabase/embedding-sdk/lib/saml-token-storage"; import { samlTokenStorage } from "metabase/embedding-sdk/lib/saml-token-storage";
import type { MetabaseEmbeddingSessionToken } from "metabase/embedding-sdk/types/refresh-token"; import type { MetabaseEmbeddingSessionToken } from "metabase/embedding-sdk/types/refresh-token";
import { requestSessionTokenFromEmbedJs } from "metabase/embedding/embedding-iframe-sdk/utils";
import { getSessionTokenHeaders } from "metabase/embedding/lib/auth/get-session-token-headers";
import { setApiKeyHeader } from "metabase/embedding/lib/auth/set-api-key-header";
import { createAsyncThunk } from "metabase/redux/utils"; import { createAsyncThunk } from "metabase/redux/utils";
import { refetchSiteSettings, settingsApi } from "metabase/settings"; import { refetchSiteSettings, settingsApi } from "metabase/settings";
import MetabaseSettings from "metabase/utils/settings"; import MetabaseSettings from "metabase/utils/settings";

View File

@@ -1,7 +1,6 @@
// Contains side effects that puts `MetabotQuestion` and `useMetabot` in the plugin // Contains side effects that puts `MetabotQuestion` and `useMetabot` in the plugin
import "./MetabotQuestion"; import "./MetabotQuestion";
import "./hooks/use-metabot"; import "./hooks/use-metabot";
import { METABOT_SDK_EE_PLUGIN } from "embedding-sdk-bundle/components/public/MetabotQuestion/MetabotQuestion"; import { METABOT_SDK_EE_PLUGIN } from "embedding-sdk-bundle/components/public/MetabotQuestion/MetabotQuestion";
import { MetabotProvider } from "metabase/metabot/context"; import { MetabotProvider } from "metabase/metabot/context";

View File

@@ -1,7 +1,7 @@
// eslint-disable-next-line metabase/no-external-references-for-sdk-package-code
import { getSdkLoaderCss } from "embedding/sdk-common/lib/get-sdk-loader-css";
import type { CommonStylingProps } from "embedding-sdk-bundle/types/props"; import type { CommonStylingProps } from "embedding-sdk-bundle/types/props";
import { useMetabaseProviderPropsStore } from "embedding-sdk-package/lib/provider-props-store"; import { useMetabaseProviderPropsStore } from "embedding-sdk-package/lib/provider-props-store";
// eslint-disable-next-line metabase/no-external-references-for-sdk-package-code
import { getSdkLoaderCss } from "embedding/sdk-common/lib/get-sdk-loader-css";
import type { MetabaseTheme } from "metabase/embedding-sdk/theme"; import type { MetabaseTheme } from "metabase/embedding-sdk/theme";
type SpinnerProps = { type SpinnerProps = {

View File

@@ -1,9 +1,3 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import * as ReactDOMClient from "react-dom/client";
import * as ReactDOMServer from "react-dom/server";
import * as ReactJsxDevRuntime from "react/jsx-dev-runtime";
import * as ReactJsxRuntime from "react/jsx-runtime";
import * as sdkExports from "@metabase/embedding-sdk-react"; import * as sdkExports from "@metabase/embedding-sdk-react";
import * as dataAppExports from "@metabase/embedding-sdk-react/data-app"; import * as dataAppExports from "@metabase/embedding-sdk-react/data-app";
import { import {
@@ -15,6 +9,13 @@ import {
devDiagnostics, devDiagnostics,
instanceConnectionCheck, instanceConnectionCheck,
} from "@metabase/embedding-sdk-react/data-app-dev"; } from "@metabase/embedding-sdk-react/data-app-dev";
import * as React from "react";
import * as ReactDOM from "react-dom";
import * as ReactDOMClient from "react-dom/client";
import { createRoot } from "react-dom/client";
import * as ReactDOMServer from "react-dom/server";
import * as ReactJsxDevRuntime from "react/jsx-dev-runtime";
import * as ReactJsxRuntime from "react/jsx-runtime";
import { import {
allowedHosts, allowedHosts,
appSlug, appSlug,
@@ -24,10 +25,8 @@ import {
rebuiltEvent, rebuiltEvent,
sdkVersion, sdkVersion,
} from "virtual:metabase-data-app-dev-config"; } from "virtual:metabase-data-app-dev-config";
import { createRoot } from "react-dom/client";
import { DATA_APP_PROVIDER_PROP_KEYS } from "metabase-enterprise/data_apps/sandbox/types"; import { DATA_APP_PROVIDER_PROP_KEYS } from "metabase-enterprise/data_apps/sandbox/types";
// The same baseline reset the production iframe loads (`iframe-vendors.ts`), so the // The same baseline reset the production iframe loads (`iframe-vendors.ts`), so the
// dev preview matches production. style-loader injects it at runtime. // dev preview matches production. style-loader injects it at runtime.
import "metabase-enterprise/data_apps/sandbox/iframe-baseline.css"; import "metabase-enterprise/data_apps/sandbox/iframe-baseline.css";

View File

@@ -1,13 +1,14 @@
/* eslint-disable import/order */ // Register mocks before loading the modules under test.
// oxfmt-ignore
import { createMockStore, resetTestState, stagesOf } from "./setup"; import { createMockStore, resetTestState, stagesOf } from "./setup";
import { TEST_SCHEMA } from "./fixtures";
import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query"; import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query";
import { EMBEDDING_SDK_CONFIG } from "metabase/embedding-sdk/config"; import { EMBEDDING_SDK_CONFIG } from "metabase/embedding-sdk/config";
import { count, filter, orderBy, sum } from ".."; import { count, filter, orderBy, sum } from "..";
import { TEST_SCHEMA } from "./fixtures";
beforeEach(resetTestState); beforeEach(resetTestState);
afterEach(() => { afterEach(() => {
EMBEDDING_SDK_CONFIG.isDataApp = false; EMBEDDING_SDK_CONFIG.isDataApp = false;

View File

@@ -1,12 +1,13 @@
/* eslint-disable import/order */ // Register mocks before loading the modules under test.
// oxfmt-ignore
import { createMockStore, resetTestState } from "./setup"; import { createMockStore, resetTestState } from "./setup";
import { TEST_SCHEMA } from "./fixtures";
import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query"; import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query";
import { avg, breakout, filter, orderBy, sum } from ".."; import { avg, breakout, filter, orderBy, sum } from "..";
import { TEST_SCHEMA } from "./fixtures";
beforeEach(resetTestState); beforeEach(resetTestState);
describe("resolveDatasetQuery validation", () => { describe("resolveDatasetQuery validation", () => {

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/order */ // Register mocks before loading the modules under test.
// oxfmt-ignore
import { import {
createMockStore, createMockStore,
mockFetchTableMetadata, mockFetchTableMetadata,
@@ -8,7 +8,6 @@ import {
resetTestState, resetTestState,
stagesOf, stagesOf,
} from "./setup"; } from "./setup";
import { TEST_METADATA, TEST_SCHEMA } from "./fixtures";
import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query"; import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query";
import { cardApi } from "metabase/api"; import { cardApi } from "metabase/api";
@@ -16,6 +15,8 @@ import * as Lib from "metabase-lib";
import { avg, breakout, count, filter, orderBy, sum } from ".."; import { avg, breakout, count, filter, orderBy, sum } from "..";
import { TEST_METADATA, TEST_SCHEMA } from "./fixtures";
beforeEach(resetTestState); beforeEach(resetTestState);
describe("resolveDatasetQuery", () => { describe("resolveDatasetQuery", () => {

View File

@@ -1,7 +1,3 @@
/* eslint-disable import/order */
import { TEST_SCHEMA } from "./fixtures";
import type { MetabaseCard } from "metabase/embedding-sdk/types/question"; import type { MetabaseCard } from "metabase/embedding-sdk/types/question";
import type { MetabaseQueryOptions, UseMetabaseQueryObjectResult } from ".."; import type { MetabaseQueryOptions, UseMetabaseQueryObjectResult } from "..";
@@ -12,8 +8,10 @@ import {
useMetabaseQuery, useMetabaseQuery,
useMetabaseQueryObject, useMetabaseQueryObject,
} from ".."; } from "..";
import { useAction, useDataAppAction } from "../../use-action";
import { defineAction, defineQuery } from "../../../../data-app"; import { defineAction, defineQuery } from "../../../../data-app";
import { useAction, useDataAppAction } from "../../use-action";
import { TEST_SCHEMA } from "./fixtures";
type OrdersTable = (typeof TEST_SCHEMA)["tables"]["orders"]; type OrdersTable = (typeof TEST_SCHEMA)["tables"]["orders"];

View File

@@ -1,9 +1,3 @@
/* eslint-disable import/order */
import { TEST_SCHEMA } from "./fixtures";
import type { RowValue } from "../../data-schema";
import type { MetabaseCard } from "metabase/embedding-sdk/types/question"; import type { MetabaseCard } from "metabase/embedding-sdk/types/question";
import type { UseMetabaseQueryObjectResult } from ".."; import type { UseMetabaseQueryObjectResult } from "..";
@@ -16,8 +10,11 @@ import {
useMetabaseQuery, useMetabaseQuery,
useMetabaseQueryObject, useMetabaseQueryObject,
} from ".."; } from "..";
import { useAction, useDataAppAction } from "../../use-action";
import { defineAction, defineQuery } from "../../../../data-app"; import { defineAction, defineQuery } from "../../../../data-app";
import type { RowValue } from "../../data-schema";
import { useAction, useDataAppAction } from "../../use-action";
import { TEST_SCHEMA } from "./fixtures";
type OrdersTable = (typeof TEST_SCHEMA)["tables"]["orders"]; type OrdersTable = (typeof TEST_SCHEMA)["tables"]["orders"];

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/order */ // Register mocks before loading the modules under test.
// oxfmt-ignore
import { import {
TEST_DATASET_QUERY, TEST_DATASET_QUERY,
createDeferred, createDeferred,
@@ -8,7 +8,6 @@ import {
resetTestState, resetTestState,
stubSdkBundle, stubSdkBundle,
} from "./setup"; } from "./setup";
import { TEST_SCHEMA } from "./fixtures";
import { act, renderHook, waitFor } from "@testing-library/react"; import { act, renderHook, waitFor } from "@testing-library/react";
@@ -19,6 +18,8 @@ import type { DatasetQuery } from "metabase-types/api";
import { filter, useMetabaseQuery, useMetabaseQueryObject } from ".."; import { filter, useMetabaseQuery, useMetabaseQueryObject } from "..";
import { defineQuery } from "../define-query"; import { defineQuery } from "../define-query";
import { TEST_SCHEMA } from "./fixtures";
beforeEach(resetTestState); beforeEach(resetTestState);
describe("useMetabaseQueryObject", () => { describe("useMetabaseQueryObject", () => {

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line eslint-js/no-restricted-imports
import { MantineProvider } from "@mantine/core"; import { MantineProvider } from "@mantine/core";
import type { StoryContext, StoryFn } from "@storybook/react"; import type { StoryContext, StoryFn } from "@storybook/react";
import { useEffect } from "react"; import { useEffect } from "react";

View File

@@ -1,5 +1,5 @@
import * as MetabaseError from "embedding-sdk-shared/errors"; import * as MetabaseError from "embedding-sdk-shared/errors";
// eslint-disable-next-line no-restricted-imports -- import type // eslint-disable-next-line eslint-js/no-restricted-imports -- import type
import type { MetabaseEmbeddingSessionToken } from "metabase/embedding-sdk/types/refresh-token"; import type { MetabaseEmbeddingSessionToken } from "metabase/embedding-sdk/types/refresh-token";
/* /*

View File

@@ -1,6 +1,4 @@
import "@mantine/core/styles.css"; import "@mantine/core/styles.css";
import "@mantine/dates/styles.css"; import "@mantine/dates/styles.css";
import "metabase-enterprise/data_apps/sandbox/iframe-baseline.css"; import "metabase-enterprise/data_apps/sandbox/iframe-baseline.css";
import "metabase/utils/csp-setup"; import "metabase/utils/csp-setup";

View File

@@ -1,8 +1,8 @@
import * as React from "react"; import * as React from "react";
import * as ReactJsxRuntime from "react/jsx-runtime";
import * as ReactDOM from "react-dom"; import * as ReactDOM from "react-dom";
import * as ReactDOMClient from "react-dom/client"; import * as ReactDOMClient from "react-dom/client";
import * as ReactDOMServer from "react-dom/server"; import * as ReactDOMServer from "react-dom/server";
import * as ReactJsxRuntime from "react/jsx-runtime";
import { pick } from "underscore"; import { pick } from "underscore";
import * as sdkExports from "embedding-sdk-package"; import * as sdkExports from "embedding-sdk-package";

View File

@@ -2,7 +2,6 @@
// chunk. If this module is ever declared side-effect free, the bundler would // chunk. If this module is ever declared side-effect free, the bundler would
// drop this import and the graph would render unstyled. // drop this import and the graph would render unstyled.
import "@xyflow/react/dist/style.css"; import "@xyflow/react/dist/style.css";
import { import {
Background, Background,
Controls, Controls,

View File

@@ -1,15 +1,15 @@
import {
INVALID_AUTH_METHOD,
MetabaseError,
} from "embedding-sdk-shared/errors";
import { import {
connectToInstanceAuthSso, connectToInstanceAuthSso,
jwtDefaultRefreshTokenFunction, jwtDefaultRefreshTokenFunction,
openSamlLoginPopup, openSamlLoginPopup,
validateSession, validateSession,
} from "embedding/auth-common"; } from "embedding/auth-common";
import {
INVALID_AUTH_METHOD,
MetabaseError,
} from "embedding-sdk-shared/errors";
import type { EmbedAuthManagerContext } from "metabase/embedding/embedding-iframe-sdk/types/auth-manager";
import type { MetabaseEmbeddingSessionToken } from "metabase/embedding-sdk/types/refresh-token"; import type { MetabaseEmbeddingSessionToken } from "metabase/embedding-sdk/types/refresh-token";
import type { EmbedAuthManagerContext } from "metabase/embedding/embedding-iframe-sdk/types/auth-manager";
/** /**
* Manages authentication for embedded Metabase components. * Manages authentication for embedded Metabase components.

View File

@@ -51,10 +51,11 @@ const BillingInfoError = () => {
<br /> <br />
<strong>{t`Need help?`}</strong> {t`You can ask for billing help at `} <strong>{t`Need help?`}</strong> {t`You can ask for billing help at `}
<strong> <strong>
{/* eslint-disable-next-line i18next/no-literal-string */} {/* eslint-disable i18next/no-literal-string -- untranslated billing address */}
<Anchor href="mailto:billing@metabase.com"> <Anchor href="mailto:billing@metabase.com">
billing@metabase.com billing@metabase.com
</Anchor> </Anchor>
{/* eslint-enable i18next/no-literal-string */}
</strong> </strong>
</Alert> </Alert>
</Box> </Box>
@@ -90,10 +91,11 @@ const BillingInfoNotStoreManaged = () => {
description={ description={
<> <>
{t`To manage your billing preferences, please email `} {t`To manage your billing preferences, please email `}
{/* eslint-disable-next-line i18next/no-literal-string */} {/* eslint-disable i18next/no-literal-string -- untranslated billing address */}
<Anchor href="mailto:billing@metabase.com"> <Anchor href="mailto:billing@metabase.com">
billing@metabase.com billing@metabase.com
</Anchor> </Anchor>
{/* eslint-enable i18next/no-literal-string */}
</> </>
} }
/> />

View File

@@ -24,9 +24,9 @@ import {
MCP_EVENT_SORT_COLUMNS, MCP_EVENT_SORT_COLUMNS,
type McpEventSortColumn, type McpEventSortColumn,
type McpFilters, type McpFilters,
buildEventsQuery,
mcpEventColumnKeys, mcpEventColumnKeys,
} from "metabase-enterprise/monitor/ai-auditing/mcp-analytics/query-utils"; } from "metabase-enterprise/monitor/ai-auditing/mcp-analytics/query-utils";
import { buildEventsQuery } from "metabase-enterprise/monitor/ai-auditing/mcp-analytics/query-utils";
import type { import type {
CardMetadata, CardMetadata,
MetadataProvider, MetadataProvider,

View File

@@ -4,10 +4,8 @@ import { PLUGIN_IS_EE_BUILD } from "metabase/plugins";
PLUGIN_IS_EE_BUILD.isEEBuild = () => true; PLUGIN_IS_EE_BUILD.isEEBuild = () => true;
import "./shared"; import "./shared";
// PLUGINS THAT DON'T USE hasPremiumFeature (imported immediately): // PLUGINS THAT DON'T USE hasPremiumFeature (imported immediately):
import "./license"; import "./license";
// PLUGINS THAT USE hasPremiumFeature (import initialization functions): // PLUGINS THAT USE hasPremiumFeature (import initialization functions):
import { initializePlugin as initializeAdvancedPermissions } from "./advanced_permissions"; import { initializePlugin as initializeAdvancedPermissions } from "./advanced_permissions";
import { initializePlugin as initializeAiControls } from "./ai-controls"; import { initializePlugin as initializeAiControls } from "./ai-controls";

View File

@@ -2,7 +2,6 @@
// chunk. If this module is ever declared side-effect free, the bundler would // chunk. If this module is ever declared side-effect free, the bundler would
// drop this import and the graph would render unstyled. // drop this import and the graph would render unstyled.
import "@xyflow/react/dist/style.css"; import "@xyflow/react/dist/style.css";
import { import {
Background, Background,
Panel, Panel,

View File

@@ -1,23 +1,34 @@
/* eslint-disable import/order */ // oxfmt-ignore
import { PLUGIN_IS_EE_BUILD } from "metabase/plugins"; import { PLUGIN_IS_EE_BUILD } from "metabase/plugins";
// oxfmt-ignore
import { initializeSdkCustomVizPlugin } from "../embedding-sdk-ee/custom-viz/initialize"; import { initializeSdkCustomVizPlugin } from "../embedding-sdk-ee/custom-viz/initialize";
// oxfmt-ignore
import { initializeHandleLinkPlugin } from "../embedding-sdk-ee/handle-link/handle-link"; import { initializeHandleLinkPlugin } from "../embedding-sdk-ee/handle-link/handle-link";
// SETTINGS OVERRIDES: // SETTINGS OVERRIDES:
PLUGIN_IS_EE_BUILD.isEEBuild = () => true; PLUGIN_IS_EE_BUILD.isEEBuild = () => true;
// oxfmt-ignore
import "./shared"; import "./shared";
// CORE APP PLUGINS THAT USE hasPremiumFeature (import initialization functions): // CORE APP PLUGINS THAT USE hasPremiumFeature (import initialization functions):
// oxfmt-ignore
import { initializePlugin as initializeContentTranslation } from "./content_translation"; import { initializePlugin as initializeContentTranslation } from "./content_translation";
// oxfmt-ignore
import { initializePlugin as initializeEmbedding } from "./embedding"; import { initializePlugin as initializeEmbedding } from "./embedding";
// oxfmt-ignore
import { initializePlugin as initializeEmbeddingSdk } from "./embedding-sdk"; import { initializePlugin as initializeEmbeddingSdk } from "./embedding-sdk";
// oxfmt-ignore
import { initializePlugin as initializeSharing } from "./sharing"; import { initializePlugin as initializeSharing } from "./sharing";
// oxfmt-ignore
import { initializePlugin as initializeTenants } from "./tenants"; import { initializePlugin as initializeTenants } from "./tenants";
// oxfmt-ignore
import { initializePlugin as initializeWhitelabelPlugin } from "./whitelabel"; import { initializePlugin as initializeWhitelabelPlugin } from "./whitelabel";
// oxfmt-ignore
import { initializePlugin as initializeWhitelabelOverridePlugin } from "./whitelabel/sdk-overrides"; import { initializePlugin as initializeWhitelabelOverridePlugin } from "./whitelabel/sdk-overrides";
// oxfmt-ignore
import { initializePlugin as initializeNotifications } from "../embedding-sdk-ee/notifications"; import { initializePlugin as initializeNotifications } from "../embedding-sdk-ee/notifications";
/** /**
@@ -39,5 +50,7 @@ export function initializePlugins() {
// "SDK EE-plugins", that are specific to the embedding sdk. // "SDK EE-plugins", that are specific to the embedding sdk.
// These only apply to the SDK, not to the core app // These only apply to the SDK, not to the core app
// oxfmt-ignore
import "../embedding-sdk-ee/auth"; import "../embedding-sdk-ee/auth";
// oxfmt-ignore
import "../embedding-sdk-ee/metabot"; import "../embedding-sdk-ee/metabot";

View File

@@ -1,10 +1,10 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { msgid, ngettext, t } from "ttag"; import { msgid, ngettext, t } from "ttag";
import { Ellipsified } from "metabase/ui";
import { import {
Box, Box,
Card, Card,
Ellipsified,
SimpleGrid, SimpleGrid,
Stack, Stack,
Text, Text,

View File

@@ -3,8 +3,8 @@ import { c, t } from "ttag";
import { getFormattedTime } from "metabase/common/components/DateTime"; import { getFormattedTime } from "metabase/common/components/DateTime";
import { formatNumber } from "metabase/static-viz/lib/numbers"; import { formatNumber } from "metabase/static-viz/lib/numbers";
import { Ellipsified } from "metabase/ui";
import { import {
Ellipsified,
EntityNameCell, EntityNameCell,
Flex, Flex,
Text, Text,

File diff suppressed because it is too large Load Diff

View File

@@ -4,10 +4,11 @@
import path from "path"; import path from "path";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import boundaries from "eslint-plugin-boundaries"; import boundaries from "eslint-plugin-boundaries";
import react from "eslint-plugin-react"; import react from "eslint-plugin-react";
import tseslint from "typescript-eslint";
import { globalIgnores, defineConfig } from "eslint/config"; import { globalIgnores, defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -15,6 +16,7 @@ import {
elements as boundaryElements, elements as boundaryElements,
rules as boundaryRules, rules as boundaryRules,
} from "./frontend/lint/module-boundaries.mjs"; } from "./frontend/lint/module-boundaries.mjs";
import { ruleAliases } from "./frontend/lint/oxlint/rule-aliases.mjs";
// dummy plugins to keep eslint from complaining about missing plugins and settings // dummy plugins to keep eslint from complaining about missing plugins and settings
const alwaysPassingRule = { const alwaysPassingRule = {
@@ -63,6 +65,12 @@ export default defineConfig([
}, },
}, },
plugins: { plugins: {
...Object.fromEntries(
Object.values(ruleAliases).map((rule) => [
rule.split("/")[0],
alwaysPassingPlugin,
]),
),
ttag: alwaysPassingPlugin, ttag: alwaysPassingPlugin,
metabase: alwaysPassingPlugin, metabase: alwaysPassingPlugin,
import: alwaysPassingPlugin, import: alwaysPassingPlugin,

View File

@@ -0,0 +1,18 @@
const { ENTERPRISE_SRC_PATH } = require("../../shared/rspack/resolve-aliases");
const { resolve } = require("../../shared/rspack/resolve-config");
const { EXTERNAL_DEPENDENCIES } = require("../constants/external-dependencies");
module.exports = {
resolve: {
...resolve,
// The SDK bundle ships the enterprise implementations in every edition.
alias: {
...resolve.alias,
"sdk-ee-plugins": ENTERPRISE_SRC_PATH + "/sdk-plugins",
"sdk-iframe-embedding-ee-plugins":
ENTERPRISE_SRC_PATH + "/sdk-iframe-embedding-plugins",
"ee-overrides": ENTERPRISE_SRC_PATH + "/overrides",
},
},
externals: EXTERNAL_DEPENDENCIES,
};

View File

@@ -80,4 +80,4 @@ const RESOLVE_ALIASES = {
: SRC_PATH + "/plugins/noop", : SRC_PATH + "/plugins/noop",
}; };
module.exports = { RESOLVE_ALIASES }; module.exports = { ENTERPRISE_SRC_PATH, RESOLVE_ALIASES };

View File

@@ -0,0 +1,15 @@
const { RESOLVE_ALIASES } = require("./resolve-aliases");
module.exports = {
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx", ".css", ".svg"],
alias: RESOLVE_ALIASES,
fallback: {
buffer: require.resolve("buffer/"),
url: require.resolve("url/"),
events: require.resolve("events/"),
querystring: require.resolve("querystring-es3"),
},
},
externals: { canvg: "canvg" },
};

38
frontend/lint/OXLINT.md Normal file
View File

@@ -0,0 +1,38 @@
# JavaScript and TypeScript linting
Oxlint runs the JavaScript and TypeScript checks in `bun run lint`, the
staged-file checks and frontend CI, including module boundaries. Oxfmt formats
the code and sorts imports. ESLint stays installed for the plugins oxlint runs
through its JS plugin API, the compatibility tests and `bun run
module-boundaries`, which the weekly stats collector runs.
Oxfmt moves value imports past side-effect imports when it sorts. A file whose
import order matters at runtime keeps that order with `// oxfmt-ignore` comments.
## Where the configuration lives
These files hold the lint configuration. Paths are relative to `frontend/lint`
unless they say otherwise.
- `oxlint.config.mts` in the repo root is the entry point oxlint loads.
- `config.mjs` holds the rule options, file scopes, globals and settings. Both
engines read it.
- `oxlint/config.mjs` translates that policy into an oxlint config.
- `oxlint/rule-map.json` maps each ESLint rule name to a native oxlint rule or a
JS plugin rule.
- `recommended-rules.json` and `oxlint/rule-defaults.json` are generated
snapshots of the plugin presets and rule defaults.
- `eslint.config.mjs` in the repo root supplies the parsers and plugins for the
ESLint side of the compatibility tests.
## After a dependency upgrade
Run `bun run lint-config-update` and review the snapshot changes. `createConfig`
throws on an enabled rule that has no entry in `oxlint/rule-map.json`, so add an
entry for each rule the upgrade enables. Then run `bun run test-oxlint`.
## Known limits
The import resolver reuses its results within one CLI run over a fixed tree.
Persistent caching and invalidation for editors or watch mode are not
implemented.

1216
frontend/lint/config.mjs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,17 @@
const micromatch = require("micromatch"); const micromatch = require("micromatch");
const matchers = new WeakMap();
function matcherFor(globs) {
let matcher = matchers.get(globs);
if (!matcher) {
// Checkouts under dotted directories must match `**`.
matcher = micromatch.matcher(globs, { dot: true });
matchers.set(globs, matcher);
}
return matcher;
}
// The base api objects. An owner's slice (`cardApi.endpoints`) is the intended way in and is not tracked. // The base api objects. An owner's slice (`cardApi.endpoints`) is the intended way in and is not tracked.
const DEFAULT_BASE_APIS = [ const DEFAULT_BASE_APIS = [
{ module: "metabase/api", name: "Api" }, { module: "metabase/api", name: "Api" },
@@ -70,14 +81,12 @@ module.exports = {
}, },
create(context) { create(context) {
const sourceCode = context.sourceCode || context.getSourceCode(); const { sourceCode, filename } = context;
const filename = context.filename || context.getFilename();
const options = context.options[0] || {}; const options = context.options[0] || {};
const baseApis = options.baseApis || DEFAULT_BASE_APIS; const baseApis = options.baseApis || DEFAULT_BASE_APIS;
// `dot: true` so a checkout under a dotted directory still matches `**`
const isAllowedIn = (globs = []) => const isAllowedIn = (globs = []) =>
globs.length > 0 && micromatch.isMatch(filename, globs, { dot: true }); globs.length > 0 && matcherFor(globs)(filename);
const injectionAllowed = isAllowedIn(options.allowInjectionIn); const injectionAllowed = isAllowedIn(options.allowInjectionIn);
const reachAllowed = isAllowedIn(options.allowReachIn); const reachAllowed = isAllowedIn(options.allowReachIn);

View File

@@ -218,8 +218,13 @@ module.exports = {
const sourceRoots = (options.sourceRoots || DEFAULT_SOURCE_ROOTS).map( const sourceRoots = (options.sourceRoots || DEFAULT_SOURCE_ROOTS).map(
(root) => path.resolve(REPO_ROOT, root), (root) => path.resolve(REPO_ROOT, root),
); );
// getScope() on the Program node returns the outer global scope, so ask the scope manager for the module scope itself. let moduleScope;
const moduleScope = sourceCode.scopeManager.acquire(sourceCode.ast, true); function getModuleScope() {
// Accessing scope constructs the scope tree for the whole file.
// getScope(Program) returns the global scope.
moduleScope ??= sourceCode.scopeManager.acquire(sourceCode.ast, true);
return moduleScope;
}
function isInternalModule(source) { function isInternalModule(source) {
return ( return (
@@ -229,8 +234,8 @@ module.exports = {
// The import a module-scope name refers to, or null when this file declares the name or it is a global. // The import a module-scope name refers to, or null when this file declares the name or it is a global.
function importOf(name) { function importOf(name) {
const def = moduleScope.set const def = getModuleScope()
.get(name) .set.get(name)
?.defs.find( ?.defs.find(
(def) => (def) =>
def.type === "ImportBinding" && def.type === "ImportBinding" &&
@@ -245,7 +250,7 @@ module.exports = {
} }
function isDeclaredHere(name) { function isDeclaredHere(name) {
return moduleScope.set.has(name) && importOf(name) == null; return getModuleScope().set.has(name) && importOf(name) == null;
} }
// The annotation may sit on the call or on a wrapper around it (`/* #__PURE__ */ foo()!`). // The annotation may sit on the call or on a wrapper around it (`/* #__PURE__ */ foo()!`).
@@ -572,7 +577,7 @@ function resolveSourceFile(base) {
return ( return (
candidates.find((candidate) => { candidates.find((candidate) => {
try { try {
return fs.statSync(candidate).isFile(); return fs.statSync(candidate, { throwIfNoEntry: false })?.isFile();
} catch { } catch {
return false; return false;
} }

View File

@@ -24,7 +24,7 @@ module.exports = {
}, },
create(context) { create(context) {
const sourceCode = context.sourceCode || context.getSourceCode(); const { sourceCode } = context;
function checkCast(node) { function checkCast(node) {
if (isConstAssertion(node)) { if (isConstAssertion(node)) {

View File

@@ -570,3 +570,14 @@ export {
getFeatureModules, getFeatureModules,
getPublicApiModules, getPublicApiModules,
}; };
export const boundarySettings = {
"boundaries/elements": elements,
"boundaries/ignore": ["**/e2e/**", "test/**"],
"boundaries/dependency-nodes": ["import", "dynamic-import"],
};
export const boundaryOptions = {
default: "disallow",
rules: enforcedRules,
message: "${file.type} cannot import from ${dependency.type}",
};

View File

@@ -0,0 +1,196 @@
import path from "node:path";
import micromatch from "micromatch";
import {
elements,
enforcedRules,
boundarySettings,
boundaryOptions,
} from "./module-boundaries.mjs";
const rootPath = path.resolve(import.meta.dirname, "../..");
const ignorePatterns = boundarySettings["boundaries/ignore"];
const defaultPolicy = boundaryOptions.default;
const message = boundaryOptions.message;
const normalize = (value) => value.replaceAll("\\", "/");
export function createBoundaryChecker({ elements, rules, rootPath }) {
const regexes = new Map();
const compile = (pattern) => {
if (typeof pattern !== "string") {
throw new Error("Boundary selectors must be strings");
}
if (!regexes.has(pattern)) {
regexes.set(pattern, micromatch.makeRe(pattern));
}
return regexes.get(pattern);
};
const descriptors = elements.map((element) => {
if (
element.capture ||
element.baseCapture ||
element.basePattern ||
![undefined, "folder", "full"].includes(element.mode) ||
typeof element.pattern !== "string"
) {
throw new Error(`Unsupported boundary descriptor: ${element.type}`);
}
return {
...element,
regex: compile(
element.mode === "full" ? element.pattern : `${element.pattern}/**/*`,
),
};
});
const ordered = [
...descriptors.filter((element) => element.mode === "full"),
...descriptors.filter((element) => element.mode !== "full"),
];
const ignores = ignorePatterns.map(compile);
const classifications = new Map();
function classify(filename) {
const relativePath = normalize(path.relative(rootPath, filename));
if (!classifications.has(relativePath)) {
const isIgnored = ignores.some((regex) => regex.test(relativePath));
const match = isIgnored
? undefined
: ordered.find((element) => element.regex.test(relativePath));
classifications.set(relativePath, {
type: match?.type ?? null,
isIgnored,
isUnknown: !match && !isIgnored,
});
}
return classifications.get(relativePath);
}
const policies = rules.map((rule) => {
const supported = new Set(["from", "allow", "disallow", "message"]);
if (Object.keys(rule).some((key) => !supported.has(key))) {
throw new Error("Unsupported boundary policy selector");
}
if (!Array.isArray(rule.from)) {
throw new Error("Boundary policies require a from array");
}
return {
...rule,
from: rule.from.map(compile),
allow: (rule.allow ?? []).map(compile),
disallow: (rule.disallow ?? []).map(compile),
};
});
const types = [...new Set(elements.map((element) => element.type))];
const decisions = new Map();
for (const from of types) {
const destinations = new Map();
decisions.set(from, destinations);
const applicable = policies.filter((policy) =>
policy.from.some((regex) => regex.test(from)),
);
for (const to of types) {
let allowed = defaultPolicy === "allow";
let finalMessage = message;
for (const policy of applicable) {
// A denial wins within a policy.
// Later matching policies take precedence.
if (policy.disallow.some((regex) => regex.test(to))) {
allowed = false;
finalMessage = policy.message ?? message;
} else if (policy.allow.some((regex) => regex.test(to))) {
allowed = true;
finalMessage = policy.message ?? message;
}
}
destinations.set(to, {
allowed,
message: finalMessage
.replaceAll("${file.type}", from)
.replaceAll("${dependency.type}", to),
});
if (from === to && !allowed) {
throw new Error(
"Self-denial requires upstream element-identity semantics",
);
}
}
}
function decision(from, to) {
const result = decisions.get(from)?.get(to);
if (!result) {
throw new Error(`Unclassified boundary pair: ${from} -> ${to}`);
}
return result;
}
return { classify, decision, types };
}
const checker = createBoundaryChecker({
elements,
rules: enforcedRules,
rootPath,
});
export function createBoundaryPlugin({ resolve }) {
return {
meta: { name: "boundaries", version: "0.0.0-experimental" },
rules: {
"no-unknown-files": {
meta: { type: "problem", schema: [] },
create(context) {
if (!checker.classify(context.filename).isUnknown) {
return {};
}
return {
Program(node) {
context.report({
node,
message: "File is not of any known element type",
});
},
};
},
},
"element-types": {
meta: { type: "problem", schema: [{ type: "object" }] },
create(context) {
const from = checker.classify(context.filename);
if (!from.type || from.isIgnored) {
return {};
}
function check(node) {
if (typeof node.value !== "string") {
return;
}
const resolved = resolve(node.value, context);
if (!resolved || normalize(resolved).includes("/node_modules/")) {
return;
}
const to = checker.classify(resolved);
if (!to.type || to.isIgnored) {
return;
}
const result = checker.decision(from.type, to.type);
if (!result.allowed) {
context.report({ node, message: result.message });
}
}
return {
ImportDeclaration(node) {
check(node.source);
},
ImportExpression(node) {
check(node.source);
if (node.options) {
check(node.options);
}
},
};
},
},
},
};
}

View File

@@ -0,0 +1,225 @@
import { existsSync } from "node:fs";
import { isBuiltin, createRequire } from "node:module";
import path from "node:path";
const require = createRequire(import.meta.url);
const legacyNode = require("eslint-import-resolver-node");
function aliases(values = {}) {
return Object.fromEntries(
Object.entries(values).map(([key, value]) => {
const entries = Array.isArray(value) ? value : [value];
if (
entries.some(
(entry) => typeof entry !== "string" || !path.isAbsolute(entry),
)
) {
throw new Error(
`Unsupported resolver alias: ${key} must contain absolute paths for reuse across package directories`,
);
}
return [key, entries];
}),
);
}
const isBare = (source) => /^[\w@]/.test(source) && !/[?#!]/.test(source);
function memoize(resolve, packageRoot) {
const cache = new Map();
return (source, file) => {
const directory = path.dirname(file);
const key = `${isBare(source) ? packageRoot(directory) : directory}\0${source}`;
if (!cache.has(key)) {
if (cache.size >= 50_000) {
cache.clear();
}
cache.set(key, resolve(source, file));
}
return cache.get(key);
};
}
// Construct a fresh service after filesystem, dependency or configuration changes.
export function createImportResolverService({ ResolverFactory }) {
const settingsCache = new WeakMap();
const resolverSettingsCache = new WeakMap();
const webpackResolvers = new Map();
const resolvers = new Map();
const packageRoots = new Map();
// Absolute aliases and a shared node_modules ancestor make bare imports independent of subdirectory.
function packageRoot(directory) {
if (!packageRoots.has(directory)) {
const parent = path.dirname(directory);
const isRoot =
parent === directory ||
existsSync(path.join(directory, "package.json")) ||
existsSync(path.join(directory, "node_modules"));
packageRoots.set(directory, isRoot ? directory : packageRoot(parent));
}
return packageRoots.get(directory);
}
const node = new ResolverFactory({
extensions: [".mjs", ".cjs", ".js", ".json", ".node"],
conditionNames: ["import", "require", "default"],
mainFields: ["module", "main"],
symlinks: false,
});
// eslint-import-resolver-node ignores exports and prioritizes module, jsnext:main, then main.
const legacyNative = new ResolverFactory({
extensions: [".mjs", ".js", ".json", ".node"],
exportsFields: [],
importsFields: [],
mainFields: ["module", "jsnext:main", "main"],
symlinks: false,
});
const resolveLegacyNode = memoize((source, file) => {
// eslint-import-resolver-node treats queries and fragments as filename characters.
if (/[?#!]/.test(source)) {
return legacyNode.resolve(source, file);
}
if (isBuiltin(source)) return { found: true, path: null };
const result = legacyNative.sync(path.dirname(file), source);
return result.path ? { found: true, path: result.path } : { found: false };
}, packageRoot);
function webpackResolver(configPath) {
if (webpackResolvers.has(configPath)) {
return webpackResolvers.get(configPath);
}
const config = require(configPath);
if (!config || typeof config !== "object" || Array.isArray(config)) {
throw new Error("The resolver adapter needs an object Rspack config");
}
const supported = new Set(["extensions", "alias", "fallback"]);
for (const key of Object.keys(config.resolve ?? {})) {
if (!supported.has(key)) {
throw new Error(`Unsupported Rspack resolve option: ${key}`);
}
}
const externals = config.externals ?? {};
if (
typeof externals !== "object" ||
Array.isArray(externals) ||
Object.getPrototypeOf(externals) !== Object.prototype
) {
throw new Error("The resolver adapter needs an object externals map");
}
const resolver = new ResolverFactory({
// Match eslint-import-resolver-webpack's enhanced-resolve defaults.
aliasFields: ["browser"],
mainFields: ["browser", "module", "main"],
extensions: config.resolve?.extensions ?? [".js", ".json"],
alias: aliases(config.resolve?.alias),
fallback: aliases(config.resolve?.fallback),
});
const resolve = (source, file) => {
source = source.slice(source.lastIndexOf("!") + 1);
const query = source.lastIndexOf("?");
if (query >= 0) {
source = source.slice(0, query);
}
if (Object.hasOwn(externals, source)) {
return { found: true, path: null };
}
const result = resolver.sync(path.dirname(file), source);
if (result.path) {
return { found: true, path: result.path };
}
if (isBuiltin(source)) {
return { found: true, path: null };
}
return { found: false };
};
webpackResolvers.set(configPath, resolve);
return resolve;
}
function forSettings(settings, mode = "import-x") {
if (mode !== "import-x" && mode !== "import") {
throw new Error(`Unsupported resolver mode: ${mode}`);
}
const cached = resolverSettingsCache.get(settings)?.get(mode);
if (cached) {
return cached;
}
for (const key of ["resolver-next", "resolver-legacy", "resolve"]) {
if (`${mode}/${key}` in settings) {
throw new Error(`Unsupported resolver setting: ${mode}/${key}`);
}
}
const config = settings[`${mode}/resolver`];
if (
config !== undefined &&
(config?.node !== true ||
Object.keys(config)[0] !== "node" ||
Object.keys(config).some(
(key) => key !== "node" && key !== "webpack",
) ||
(config.webpack &&
(typeof config.webpack.config !== "string" ||
!path.isAbsolute(config.webpack.config) ||
Object.keys(config.webpack).some(
(key) => key !== "config" && key !== "typescript",
))))
) {
throw new Error("Unsupported resolver configuration in adapter");
}
const configPath = config?.webpack?.config;
const key = `${mode}\0${configPath ?? ""}`;
if (!resolvers.has(key)) {
const webpack = configPath ? webpackResolver(configPath) : undefined;
const resolveFallback = (source, file) => {
const result = resolveLegacyNode(source, file);
return result.found ? result : (webpack?.(source, file) ?? result);
};
const resolveImportX = (source, file) => {
if (isBuiltin(source) || source.startsWith("data:")) {
return { found: true, path: null };
}
const result = node.sync(path.dirname(file), source);
return result.path
? { found: true, path: result.path }
: resolveFallback(source, file);
};
// import-x tries the exports-aware resolver before the node/webpack chain.
const resolve = memoize(
mode === "import-x" ? resolveImportX : resolveFallback,
packageRoot,
);
resolvers.set(key, {
interfaceVersion: 3,
name: `metabase-oxc-${mode}`,
resolve,
});
}
const resolver = resolvers.get(key);
if (!resolverSettingsCache.has(settings)) {
resolverSettingsCache.set(settings, new Map());
}
resolverSettingsCache.get(settings).set(mode, resolver);
return resolver;
}
function importSettings(settings) {
if (!settingsCache.has(settings)) {
settingsCache.set(settings, {
...settings,
"import-x/resolver-next": [forSettings(settings)],
});
}
return settingsCache.get(settings);
}
function resolveImport(source, context) {
if (context.settings["import/core-modules"]?.includes(source)) {
return null;
}
return forSettings(context.settings, "import").resolve(
source,
context.physicalFilename ?? context.filename,
).path;
}
return { forSettings, importSettings, resolveImport };
}

View File

@@ -0,0 +1,230 @@
import { createRequire } from "node:module";
import path from "node:path";
import { isDeepStrictEqual } from "node:util";
import micromatch from "micromatch";
import policy from "../config.mjs";
import { boundarySettings, boundaryOptions } from "../module-boundaries.mjs";
import defaults from "./rule-defaults.json" with { type: "json" };
import ruleMap from "./rule-map.json" with { type: "json" };
export const root = path.resolve(import.meta.dirname, "../../..");
function merge(left, right) {
const result = { ...left };
for (const [key, value] of Object.entries(right)) {
result[key] =
value && typeof value === "object" && !Array.isArray(value)
? merge(result[key] ?? {}, value)
: value;
}
return result;
}
function options(name, value) {
const [severity, ...supplied] = Array.isArray(value) ? value : [value];
if (severity === "off" || severity === 0) return "off";
// Without an options object, native no-unused-vars ignores names matching /^_/.
// ESLint's no-unused-vars with no options reports those names.
const result = [
...(defaults[name] ?? (name === "no-unused-vars" ? [{}] : [])),
];
supplied.forEach((value, index) => {
result[index] =
value && typeof value === "object" && !Array.isArray(value)
? merge(result[index] ?? {}, value)
: value;
});
return [severity, ...result];
}
// Oxlint does not apply per-file settings overrides.
const settingsEntries = policy
.filter(
(entry) =>
entry.settings ||
entry.languageOptions?.parserOptions ||
entry.languageOptions?.sourceType,
)
.map((entry) => ({
matches: entry.files
? micromatch.matcher(entry.files, { dot: true })
: () => true,
sourceType: entry.languageOptions?.sourceType,
settings: entry.settings ?? {},
parserOptions: entry.languageOptions?.parserOptions ?? {},
}));
// Files matching the same scopes share one settings object,
// because the resolver adapter keys its WeakMaps by settings identity.
const combinations = new Map();
let lastFile;
let lastSettings;
export function settingsForFile(filename) {
if (filename === lastFile) return lastSettings;
const relative = path.relative(root, filename).replaceAll("\\", "/");
const matched = settingsEntries.flatMap((entry, index) =>
entry.matches(relative) ? [index] : [],
);
const key = matched.join(",");
if (!combinations.has(key)) {
combinations.set(
key,
matched.reduce(
(result, index) => ({
sourceType: settingsEntries[index].sourceType ?? result.sourceType,
settings: merge(result.settings, settingsEntries[index].settings),
parserOptions: merge(
result.parserOptions,
settingsEntries[index].parserOptions,
),
}),
{ settings: {}, parserOptions: {} },
),
);
}
lastFile = filename;
lastSettings = combinations.get(key);
return lastSettings;
}
const nativePlugins = ["typescript", "react", "import", "jest"];
const jsNamespaces = [
...new Set(
Object.values(ruleMap)
.filter((name) => name.includes("/"))
.map((name) => name.slice(0, name.indexOf("/"))),
),
].filter((name) => !nativePlugins.includes(name));
export const jsRules = Object.fromEntries(
jsNamespaces
.filter((name) => name !== "no-only-tests")
.map((namespace) => [
namespace,
[
...new Set(
Object.values(ruleMap)
.filter((name) => name.startsWith(`${namespace}/`))
.map((name) => name.slice(namespace.length + 1)),
),
],
]),
);
const require = createRequire(import.meta.url);
function hasCssModulesPlugin() {
if (!(process.env.CI || process.env.LINT_CSS_MODULES === "true"))
return false;
try {
require.resolve("eslint-plugin-postcss-modules");
return true;
} catch {
return false;
}
}
function glob(pattern) {
// globset's brace alternatives are equivalent to these simple extglobs.
const translated = pattern.replace(
/@\(([^)]+)\)/g,
(_, alternatives) => `{${alternatives.replaceAll("|", ",")}}`,
);
// Unlike ESLint flat config, oxlint matches a glob without a slash at any depth.
return translated.includes("/") ? translated : `./${translated}`;
}
export function createConfig() {
const overrides = [];
const ignorePatterns = [];
const configuredExtensions = new Set();
for (const entry of policy) {
for (const [name, value] of Object.entries(entry.settings ?? {})) {
if (
name.startsWith("boundaries/") &&
(!Object.hasOwn(boundarySettings, name) ||
!isDeepStrictEqual(value, boundarySettings[name]))
) {
throw new Error(`Unsupported boundary checker setting: ${name}`);
}
}
if (entry.ignores && !entry.files) {
ignorePatterns.push(...entry.ignores);
continue;
}
const rules = {};
for (const [name, value] of Object.entries(entry.rules ?? {})) {
// Native unused-vars accounts for JSX references itself.
if (name === "react/jsx-uses-vars") continue;
const mapped = ruleMap[name];
const normalized = options(name, value);
if (
name === "boundaries/element-types" &&
normalized !== "off" &&
!isDeepStrictEqual(normalized.slice(1), [boundaryOptions])
) {
throw new Error(
"The boundary checker requires the shared enforced policy",
);
}
if (!mapped) {
if (normalized === "off") continue;
throw new Error(
`Map the new lint rule to oxlint or a JS plugin: ${name}`,
);
}
// A TypeScript extension can share its native rule with the disabled ESLint base rule.
const extension = `@typescript-eslint/${name}`;
if (normalized === "off" && ruleMap[extension] === mapped) {
if (Object.hasOwn(entry.rules, extension)) continue;
// An earlier policy entry enabled the TypeScript extension.
// Turning the shared native rule off here disables it in every file both entries match.
if (configuredExtensions.has(extension)) {
throw new Error(
`Disabling ${name} after ${extension} requires an explicit ${extension} setting in the same policy entry`,
);
}
}
if (name.startsWith("@typescript-eslint/") && normalized !== "off") {
configuredExtensions.add(name);
}
rules[mapped] = normalized;
}
const globals = Object.fromEntries(
Object.entries(entry.languageOptions?.globals ?? {}).map(
([name, value]) => [
name,
value === false ? "readonly" : value === true ? "writable" : value,
],
),
);
overrides.push({
files: (entry.files ?? ["**/*"]).map(glob),
...(entry.ignores ? { excludeFiles: entry.ignores.map(glob) } : {}),
...(Object.keys(globals).length ? { globals } : {}),
rules,
});
}
const namespaces = [...jsNamespaces];
if (hasCssModulesPlugin()) {
jsRules["postcss-modules"] = ["no-undef-class"];
namespaces.push("postcss-modules");
overrides.push({
files: ["**/*.{js,jsx,ts,tsx}"],
rules: { "postcss-modules/no-undef-class": "error" },
});
}
return {
categories: { correctness: "off" },
plugins: nativePlugins,
settings: { react: { version: "18.2.0" } },
ignorePatterns,
overrides,
jsPlugins: namespaces.map((name) => ({
name,
specifier: path.join(import.meta.dirname, "plugins", `${name}.mjs`),
})),
};
}

View File

@@ -0,0 +1,45 @@
import { decode } from "html-entities";
// JSX uses XML numeric references and requires lowercase x for hexadecimal references.
export function decodeJsxText(text) {
return text.replace(
/&(?:#(\d+)|#x([\da-fA-F]+)|([a-zA-Z][a-zA-Z0-9]*));/g,
(entity, decimal, hexadecimal, named) => {
if (named) return decode(entity, { level: "html4", scope: "strict" });
const codePoint = Number.parseInt(
decimal ?? hexadecimal,
decimal ? 10 : 16,
);
return codePoint <= 0x10ffff ? String.fromCodePoint(codePoint) : entity;
},
);
}
// Translation rules expect decoded JSX text.
// Oxlint exposes the source spelling.
export function withDecodedJsxText(plugin) {
const rule = plugin.rules["no-literal-string"];
return {
...plugin,
rules: {
...plugin.rules,
"no-literal-string": {
...rule,
create(context) {
const visitors = rule.create(context);
return {
...visitors,
JSXText(node) {
const value = decodeJsxText(node.value);
return visitors.JSXText(
value === node.value
? node
: Object.create(node, { value: { value } }),
);
},
};
},
},
},
};
}

View File

@@ -0,0 +1,39 @@
import { settingsForFile } from "./config.mjs";
// Oxlint parses import-free JS files as scripts, where local bindings can appear to redeclare globals.
// Our policy treats those bindings as module-local.
export function moduleScopeContext(context) {
const sourceCode = context.sourceCode;
if (
sourceCode.ast.sourceType !== "script" ||
settingsForFile(context.filename).sourceType !== "module"
)
return context;
const views = new WeakMap();
const getScope = (node) => {
const scope = sourceCode.getScope(node);
if (scope.type !== "global") return scope;
if (!views.has(scope)) {
views.set(
scope,
Object.create(scope, {
variables: {
value: scope.variables.map((variable) =>
variable.identifiers.length
? Object.create(variable, {
eslintImplicitGlobalSetting: { value: undefined },
})
: variable,
),
},
}),
);
}
return views.get(scope);
};
return Object.create(context, {
sourceCode: {
value: Object.create(sourceCode, { getScope: { value: getScope } }),
},
});
}

View File

@@ -0,0 +1,55 @@
import { jsRules, settingsForFile } from "./config.mjs";
export function wrap(
namespace,
plugin,
transformSettings = (settings) => settings,
transformContext = (context) => context,
) {
// Oxlint reuses one context object per rule for every file it lints.
const contexts = new WeakMap();
return {
meta: { name: namespace },
rules: Object.fromEntries(
jsRules[namespace].map((name) => {
const rule = plugin.rules[name];
if (!rule)
throw new Error(`Missing JS lint rule: ${namespace}/${name}`);
if (typeof rule.create !== "function") {
throw new Error(`Wrapped rule requires create: ${namespace}/${name}`);
}
// Oxlint runs createOnce instead of create whenever the property is present.
// The getters below read context.filename, which throws inside createOnce.
const legacyRule = { ...rule };
delete legacyRule.createOnce;
return [
name,
{
...legacyRule,
create(context) {
let wrapped = contexts.get(context);
if (!wrapped) {
wrapped = transformContext(
Object.create(context, {
settings: {
get: () =>
transformSettings(
settingsForFile(context.filename).settings,
),
},
parserOptions: {
get: () =>
settingsForFile(context.filename).parserOptions,
},
}),
);
contexts.set(context, wrapped);
}
return rule.create(wrapped);
},
},
];
}),
),
};
}

View File

@@ -0,0 +1,7 @@
import { createBoundaryPlugin } from "../../oxlint-boundaries.mjs";
import { wrap } from "../plugin.mjs";
import { resolver } from "../resolver.mjs";
export default wrap(
"boundaries",
createBoundaryPlugin({ resolve: resolver.resolveImport }),
);

View File

@@ -0,0 +1,3 @@
import plugin from "eslint-plugin-chai-friendly";
import { wrap } from "../plugin.mjs";
export default wrap("chai-friendly", plugin);

View File

@@ -0,0 +1,3 @@
import plugin from "eslint-plugin-cypress";
import { wrap } from "../plugin.mjs";
export default wrap("cypress", plugin);

View File

@@ -0,0 +1,4 @@
import * as imported from "eslint-plugin-depend";
import { wrap } from "../plugin.mjs";
const plugin = imported.default ?? imported;
export default wrap("depend", plugin);

View File

@@ -0,0 +1,20 @@
import { builtinRules } from "eslint/use-at-your-own-risk";
import { jsRules } from "../config.mjs";
import { moduleScopeContext } from "../module-scope.mjs";
import { wrap } from "../plugin.mjs";
export default wrap("eslint-js", {
rules: Object.fromEntries(
jsRules["eslint-js"].map((name) => {
const rule = builtinRules.get(name);
return [
name,
name === "no-redeclare"
? {
...rule,
create: (context) => rule.create(moduleScopeContext(context)),
}
: rule,
];
}),
),
});

View File

@@ -0,0 +1,4 @@
import plugin from "eslint-plugin-i18next";
import { withDecodedJsxText } from "../jsx-text.mjs";
import { wrap } from "../plugin.mjs";
export default wrap("i18next", withDecodedJsxText(plugin));

View File

@@ -0,0 +1,34 @@
import { createRequire } from "node:module";
import plugin from "eslint-plugin-import-x";
import { wrap } from "../plugin.mjs";
import { resolver } from "../resolver.mjs";
const require = createRequire(import.meta.url);
// import-x needs a working parser for export * analysis.
// Oxlint supplies a stub.
const parser = (typescript) => ({
meta: {
name: typescript ? "typescript-eslint/parser" : "babel/eslint-parser",
},
parseForESLint(code, options) {
const implementation = typescript
? require("typescript-eslint").parser
: require("@babel/eslint-parser");
return implementation.parseForESLint(code, options);
},
});
const tsParser = parser(true);
const jsParser = parser(false);
export default wrap("import-js", plugin, resolver.importSettings, (context) =>
Object.create(context, {
languageOptions: {
// Spreading languageOptions eagerly evaluates its AST and global getters.
value: Object.create(context.languageOptions, {
parser: {
get: () =>
/\.[cm]?tsx?$/.test(context.filename) ? tsParser : jsParser,
},
}),
},
}),
);

View File

@@ -0,0 +1,3 @@
import plugin from "eslint-plugin-jest-dom";
import { wrap } from "../plugin.mjs";
export default wrap("jest-dom", plugin);

View File

@@ -0,0 +1,3 @@
import plugin from "eslint-plugin-jest";
import { wrap } from "../plugin.mjs";
export default wrap("jest-js", plugin);

View File

@@ -0,0 +1,3 @@
import plugin from "../../eslint-plugin-metabase/index.js";
import { wrap } from "../plugin.mjs";
export default wrap("metabase", plugin);

View File

@@ -0,0 +1 @@
export { default } from "eslint-plugin-no-only-tests";

View File

@@ -0,0 +1,12 @@
import { fixupPluginRules } from "@eslint/compat";
import plugin from "eslint-plugin-postcss-modules";
import { wrap } from "../plugin.mjs";
export default wrap(
"postcss-modules",
fixupPluginRules(plugin),
(settings) => ({
...settings,
"postcss-modules": { baseDir: "./frontend/src" },
}),
);

View File

@@ -0,0 +1,3 @@
import plugin from "eslint-plugin-react";
import { wrap } from "../plugin.mjs";
export default wrap("react-js", plugin);

View File

@@ -0,0 +1,3 @@
import plugin from "eslint-plugin-storybook";
import { wrap } from "../plugin.mjs";
export default wrap("storybook", plugin);

View File

@@ -0,0 +1,3 @@
import plugin from "eslint-plugin-testing-library";
import { wrap } from "../plugin.mjs";
export default wrap("testing-library", plugin);

View File

@@ -0,0 +1,4 @@
import plugin from "eslint-plugin-ttag";
import { wrap } from "../plugin.mjs";
import { fixupPluginRules } from "@eslint/compat";
export default wrap("ttag", fixupPluginRules(plugin));

View File

@@ -0,0 +1,3 @@
import rules from "@typescript-eslint/eslint-plugin/use-at-your-own-risk/rules";
import { wrap } from "../plugin.mjs";
export default wrap("typescript-js", { rules });

View File

@@ -0,0 +1,5 @@
import { ResolverFactory } from "oxc-resolver";
import { createImportResolverService } from "../oxlint-import-resolver.mjs";
export const resolver = createImportResolverService({ ResolverFactory });

View File

@@ -0,0 +1,16 @@
import ruleMap from "./rule-map.json" with { type: "json" };
// Oxlint reserves native namespaces, so retained JS rules need distinct suppression names.
export const ruleAliases = Object.fromEntries(
Object.entries(ruleMap).filter(([, target]) =>
/^(?:eslint|import|react|jest|typescript)-js\//.test(target),
),
);
export function aliasRules(rules = {}) {
return Object.fromEntries(
Object.entries(rules).map(([name, value]) => [
ruleAliases[name] ?? name,
value,
]),
);
}

View File

@@ -0,0 +1,139 @@
{
"getter-return": [
{
"allowImplicit": false
}
],
"no-cond-assign": ["except-parens"],
"no-constant-condition": [
{
"checkLoops": "allExceptWhileTrue"
}
],
"no-empty": [
{
"allowEmptyCatch": false
}
],
"no-empty-pattern": [
{
"allowObjectPatternsAsParameters": false
}
],
"no-extra-boolean-cast": [{}],
"no-fallthrough": [
{
"allowEmptyCase": false,
"reportUnusedFallthroughComment": false
}
],
"no-global-assign": [
{
"exceptions": []
}
],
"no-invalid-regexp": [{}],
"no-irregular-whitespace": [
{
"skipComments": false,
"skipJSXText": false,
"skipRegExps": false,
"skipStrings": true,
"skipTemplates": false
}
],
"no-misleading-character-class": [
{
"allowEscape": false
}
],
"no-redeclare": [
{
"builtinGlobals": true
}
],
"no-self-assign": [
{
"props": true
}
],
"no-shadow-restricted-names": [
{
"reportGlobalThis": false
}
],
"no-undef": [
{
"typeof": false
}
],
"no-unsafe-negation": [
{
"enforceForOrderingRelations": false
}
],
"no-unsafe-optional-chaining": [
{
"disallowArithmeticOperators": false
}
],
"no-useless-escape": [
{
"allowRegexCharacters": []
}
],
"use-isnan": [
{
"enforceForIndexOf": false,
"enforceForSwitchCase": true
}
],
"valid-typeof": [
{
"requireStringLiterals": false
}
],
"strict": ["safe"],
"curly": ["all"],
"prefer-const": [
{
"destructuring": "any",
"ignoreReadBeforeAssign": false
}
],
"complexity": [20],
"sort-imports": [
{
"allowSeparatedGroups": false,
"ignoreCase": false,
"ignoreDeclarationSort": false,
"ignoreMemberSort": false,
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
}
],
"depend/ban-dependencies": [{}],
"no-console": [{}],
"@typescript-eslint/no-unused-expressions": [
{
"allowShortCircuit": false,
"allowTaggedTemplates": false,
"allowTernary": false
}
],
"storybook/await-interactions": [],
"storybook/context-in-play-function": [],
"storybook/default-exports": [],
"storybook/hierarchy-separator": [],
"storybook/no-redundant-story-name": [],
"storybook/prefer-pascal-case": [],
"storybook/story-exports": [],
"storybook/use-storybook-expect": [],
"storybook/use-storybook-testing-library": [],
"storybook/no-renderer-packages": [],
"storybook/no-uninstalled-addons": [
{
"packageJsonLocation": "",
"ignore": []
}
]
}

View File

@@ -0,0 +1,217 @@
{
"constructor-super": "constructor-super",
"for-direction": "for-direction",
"getter-return": "getter-return",
"no-async-promise-executor": "no-async-promise-executor",
"no-case-declarations": "no-case-declarations",
"no-class-assign": "no-class-assign",
"no-compare-neg-zero": "no-compare-neg-zero",
"no-cond-assign": "no-cond-assign",
"no-const-assign": "no-const-assign",
"no-constant-binary-expression": "no-constant-binary-expression",
"no-constant-condition": "no-constant-condition",
"no-control-regex": "no-control-regex",
"no-debugger": "no-debugger",
"no-delete-var": "no-delete-var",
"no-dupe-args": "eslint-js/no-dupe-args",
"no-dupe-class-members": "no-dupe-class-members",
"no-dupe-else-if": "no-dupe-else-if",
"no-dupe-keys": "no-dupe-keys",
"no-duplicate-case": "no-duplicate-case",
"no-empty": "no-empty",
"no-empty-character-class": "no-empty-character-class",
"no-empty-pattern": "no-empty-pattern",
"no-empty-static-block": "no-empty-static-block",
"no-ex-assign": "no-ex-assign",
"no-extra-boolean-cast": "no-extra-boolean-cast",
"no-fallthrough": "no-fallthrough",
"no-func-assign": "no-func-assign",
"no-global-assign": "no-global-assign",
"no-import-assign": "no-import-assign",
"no-invalid-regexp": "no-invalid-regexp",
"no-irregular-whitespace": "no-irregular-whitespace",
"no-loss-of-precision": "no-loss-of-precision",
"no-misleading-character-class": "no-misleading-character-class",
"no-new-native-nonconstructor": "no-new-native-nonconstructor",
"no-nonoctal-decimal-escape": "no-nonoctal-decimal-escape",
"no-obj-calls": "no-obj-calls",
"no-octal": "eslint-js/no-octal",
"no-prototype-builtins": "no-prototype-builtins",
"no-redeclare": "eslint-js/no-redeclare",
"no-regex-spaces": "no-regex-spaces",
"no-self-assign": "no-self-assign",
"no-setter-return": "no-setter-return",
"no-shadow-restricted-names": "no-shadow-restricted-names",
"no-sparse-arrays": "no-sparse-arrays",
"no-this-before-super": "no-this-before-super",
"no-undef": "no-undef",
"no-unexpected-multiline": "no-unexpected-multiline",
"no-unreachable": "no-unreachable",
"no-unsafe-finally": "no-unsafe-finally",
"no-unsafe-negation": "no-unsafe-negation",
"no-unsafe-optional-chaining": "eslint-js/no-unsafe-optional-chaining",
"no-unused-labels": "no-unused-labels",
"no-unused-private-class-members": "no-unused-private-class-members",
"no-unused-vars": "no-unused-vars",
"no-useless-backreference": "no-useless-backreference",
"no-useless-catch": "no-useless-catch",
"no-useless-escape": "no-useless-escape",
"no-with": "no-with",
"require-yield": "require-yield",
"use-isnan": "use-isnan",
"valid-typeof": "valid-typeof",
"metabase/no-unscoped-text-selectors": "metabase/no-unscoped-text-selectors",
"cypress/no-assigning-return-values": "cypress/no-assigning-return-values",
"cypress/no-async-tests": "cypress/no-async-tests",
"cypress/no-pause": "cypress/no-pause",
"chai-friendly/no-unused-expressions": "chai-friendly/no-unused-expressions",
"quotes": "eslint-js/quotes",
"no-restricted-imports": "eslint-js/no-restricted-imports",
"import/no-unresolved": "import-js/no-unresolved",
"metabase/no-direct-helper-import": "metabase/no-direct-helper-import",
"metabase/no-unsafe-element-filtering": "metabase/no-unsafe-element-filtering",
"metabase/no-unordered-test-helpers": "metabase/no-unordered-test-helpers",
"strict": "eslint-js/strict",
"no-restricted-syntax": "eslint-js/no-restricted-syntax",
"no-var": "no-var",
"curly": "curly",
"eqeqeq": "eqeqeq",
"prefer-const": "prefer-const",
"no-restricted-globals": "no-restricted-globals",
"complexity": "complexity",
"import/export": "import-js/export",
"import/no-duplicates": "import/no-duplicates",
"import/no-default-export": "import/no-default-export",
"sort-imports": "sort-imports",
"react/display-name": "react/display-name",
"react/jsx-key": "react/jsx-key",
"react/jsx-no-comment-textnodes": "react/jsx-no-comment-textnodes",
"react/jsx-no-duplicate-props": "react/jsx-no-duplicate-props",
"react/jsx-no-target-blank": "react/jsx-no-target-blank",
"react/jsx-no-undef": "react/jsx-no-undef",
"react/no-children-prop": "react/no-children-prop",
"react/no-danger-with-children": "react/no-danger-with-children",
"react/no-deprecated": "react-js/no-deprecated",
"react/no-direct-mutation-state": "react/no-direct-mutation-state",
"react/no-is-mounted": "react/no-is-mounted",
"react/no-render-return-value": "react/no-render-return-value",
"react/no-string-refs": "react/no-string-refs",
"react/no-unescaped-entities": "react/no-unescaped-entities",
"react/no-unknown-property": "react/no-unknown-property",
"react/require-render-return": "react/require-render-return",
"react/prefer-es6-class": "react/prefer-es6-class",
"react/forbid-component-props": "react/forbid-component-props",
"react-hooks/rules-of-hooks": "react/rules-of-hooks",
"react-hooks/exhaustive-deps": "react/exhaustive-deps",
"no-only-tests/no-only-tests": "no-only-tests/no-only-tests",
"metabase/jtag-missing-key": "metabase/jtag-missing-key",
"metabase/valid-theme-tokens": "metabase/valid-theme-tokens",
"metabase/no-analytics-import-outside-analytics-files": "metabase/no-analytics-import-outside-analytics-files",
"metabase/no-module-level-memoize": "metabase/no-module-level-memoize",
"metabase/no-direct-memoize-import": "metabase/no-direct-memoize-import",
"depend/ban-dependencies": "depend/ban-dependencies",
"jest/expect-expect": "jest/expect-expect",
"jest/no-alias-methods": "jest/no-alias-methods",
"jest/no-commented-out-tests": "jest/no-commented-out-tests",
"jest/no-conditional-expect": "jest-js/no-conditional-expect",
"jest/no-deprecated-functions": "jest/no-deprecated-functions",
"jest/no-disabled-tests": "jest/no-disabled-tests",
"jest/no-done-callback": "jest/no-done-callback",
"jest/no-export": "jest/no-export",
"jest/no-focused-tests": "jest/no-focused-tests",
"jest/no-identical-title": "jest/no-identical-title",
"jest/no-interpolation-in-snapshots": "jest/no-interpolation-in-snapshots",
"jest/no-jasmine-globals": "jest/no-jasmine-globals",
"jest/no-mocks-import": "jest/no-mocks-import",
"jest/no-standalone-expect": "jest/no-standalone-expect",
"jest/no-test-prefixes": "jest/no-test-prefixes",
"jest/valid-describe-callback": "jest/valid-describe-callback",
"jest/valid-expect": "jest-js/valid-expect",
"jest/valid-expect-in-promise": "jest/valid-expect-in-promise",
"jest/valid-title": "jest/valid-title",
"jest-dom/prefer-checked": "jest-dom/prefer-checked",
"jest-dom/prefer-empty": "jest-dom/prefer-empty",
"jest-dom/prefer-enabled-disabled": "jest-dom/prefer-enabled-disabled",
"jest-dom/prefer-focus": "jest-dom/prefer-focus",
"jest-dom/prefer-in-document": "jest-dom/prefer-in-document",
"jest-dom/prefer-required": "jest-dom/prefer-required",
"jest-dom/prefer-to-have-attribute": "jest-dom/prefer-to-have-attribute",
"jest-dom/prefer-to-have-class": "jest-dom/prefer-to-have-class",
"jest-dom/prefer-to-have-style": "jest-dom/prefer-to-have-style",
"jest-dom/prefer-to-have-text-content": "jest-dom/prefer-to-have-text-content",
"jest-dom/prefer-to-have-value": "jest-dom/prefer-to-have-value",
"testing-library/await-async-events": "testing-library/await-async-events",
"testing-library/await-async-queries": "testing-library/await-async-queries",
"testing-library/await-async-utils": "testing-library/await-async-utils",
"testing-library/no-await-sync-events": "testing-library/no-await-sync-events",
"testing-library/no-await-sync-queries": "testing-library/no-await-sync-queries",
"testing-library/no-container": "testing-library/no-container",
"testing-library/no-debugging-utils": "testing-library/no-debugging-utils",
"testing-library/no-dom-import": "testing-library/no-dom-import",
"testing-library/no-global-regexp-flag-in-query": "testing-library/no-global-regexp-flag-in-query",
"testing-library/no-manual-cleanup": "testing-library/no-manual-cleanup",
"testing-library/no-node-access": "testing-library/no-node-access",
"testing-library/no-promise-in-fire-event": "testing-library/no-promise-in-fire-event",
"testing-library/no-render-in-lifecycle": "testing-library/no-render-in-lifecycle",
"testing-library/no-unnecessary-act": "testing-library/no-unnecessary-act",
"testing-library/no-wait-for-multiple-assertions": "testing-library/no-wait-for-multiple-assertions",
"testing-library/no-wait-for-side-effects": "testing-library/no-wait-for-side-effects",
"testing-library/no-wait-for-snapshot": "testing-library/no-wait-for-snapshot",
"testing-library/prefer-find-by": "testing-library/prefer-find-by",
"testing-library/prefer-presence-queries": "testing-library/prefer-presence-queries",
"testing-library/prefer-query-by-disappearance": "testing-library/prefer-query-by-disappearance",
"testing-library/prefer-screen-queries": "testing-library/prefer-screen-queries",
"testing-library/render-result-naming-convention": "testing-library/render-result-naming-convention",
"prefer-spread": "prefer-spread",
"@typescript-eslint/ban-ts-comment": "typescript/ban-ts-comment",
"@typescript-eslint/no-array-constructor": "typescript-js/no-array-constructor",
"@typescript-eslint/no-duplicate-enum-values": "typescript/no-duplicate-enum-values",
"@typescript-eslint/no-empty-object-type": "typescript-js/no-empty-object-type",
"@typescript-eslint/no-extra-non-null-assertion": "typescript/no-extra-non-null-assertion",
"@typescript-eslint/no-misused-new": "typescript/no-misused-new",
"@typescript-eslint/no-non-null-asserted-optional-chain": "typescript/no-non-null-asserted-optional-chain",
"@typescript-eslint/no-require-imports": "typescript/no-require-imports",
"@typescript-eslint/no-unnecessary-type-constraint": "typescript/no-unnecessary-type-constraint",
"@typescript-eslint/no-unsafe-function-type": "typescript/no-unsafe-function-type",
"@typescript-eslint/no-unused-vars": "no-unused-vars",
"@typescript-eslint/no-wrapper-object-types": "typescript/no-wrapper-object-types",
"@typescript-eslint/prefer-as-const": "typescript/prefer-as-const",
"@typescript-eslint/prefer-namespace-keyword": "typescript/prefer-namespace-keyword",
"@typescript-eslint/triple-slash-reference": "typescript/triple-slash-reference",
"metabase/no-unjustified-type-casts": "metabase/no-unjustified-type-casts",
"@typescript-eslint/consistent-type-imports": "typescript/consistent-type-imports",
"@typescript-eslint/no-import-type-side-effects": "typescript/no-import-type-side-effects",
"no-console": "no-console",
"@typescript-eslint/no-restricted-imports": "typescript-js/no-restricted-imports",
"ttag/no-module-declaration": "ttag/no-module-declaration",
"import/no-commonjs": "import/no-commonjs",
"metabase/no-unconditional-metabase-links-render": "metabase/no-unconditional-metabase-links-render",
"metabase/no-color-literals": "metabase/no-color-literals",
"metabase/no-literal-metabase-strings": "metabase/no-literal-metabase-strings",
"i18next/no-literal-string": "i18next/no-literal-string",
"boundaries/element-types": "boundaries/element-types",
"metabase/enforce-module-public-api": "metabase/enforce-module-public-api",
"boundaries/no-unknown-files": "boundaries/no-unknown-files",
"@typescript-eslint/no-namespace": "typescript/no-namespace",
"@typescript-eslint/no-unused-expressions": "no-unused-expressions",
"metabase/no-base-api-access": "metabase/no-base-api-access",
"metabase/no-plugin-slot-outside-plugins-files": "metabase/no-plugin-slot-outside-plugins-files",
"storybook/await-interactions": "storybook/await-interactions",
"storybook/context-in-play-function": "storybook/context-in-play-function",
"storybook/default-exports": "storybook/default-exports",
"storybook/hierarchy-separator": "storybook/hierarchy-separator",
"storybook/no-redundant-story-name": "storybook/no-redundant-story-name",
"storybook/prefer-pascal-case": "storybook/prefer-pascal-case",
"storybook/story-exports": "storybook/story-exports",
"storybook/use-storybook-expect": "storybook/use-storybook-expect",
"storybook/use-storybook-testing-library": "storybook/use-storybook-testing-library",
"metabase/no-external-references-for-sdk-package-code": "metabase/no-external-references-for-sdk-package-code",
"import/no-cycle": "import/no-cycle",
"metabase/no-module-side-effects": "metabase/no-module-side-effects",
"prefer-rest-params": "prefer-rest-params",
"@typescript-eslint/no-explicit-any": "typescript/no-explicit-any",
"@typescript-eslint/no-this-alias": "typescript/no-this-alias",
"@typescript-eslint/no-unsafe-declaration-merging": "typescript/no-unsafe-declaration-merging",
"storybook/no-renderer-packages": "storybook/no-renderer-packages",
"storybook/no-uninstalled-addons": "storybook/no-uninstalled-addons"
}

View File

@@ -0,0 +1,280 @@
{
"javascript": {
"constructor-super": "error",
"for-direction": "error",
"getter-return": "error",
"no-async-promise-executor": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-const-assign": "error",
"no-constant-binary-expression": "error",
"no-constant-condition": "error",
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-else-if": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-empty-static-block": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-fallthrough": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-import-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-new-native-nonconstructor": "error",
"no-nonoctal-decimal-escape": "error",
"no-obj-calls": "error",
"no-octal": "error",
"no-prototype-builtins": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-self-assign": "error",
"no-setter-return": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-this-before-super": "error",
"no-undef": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unsafe-optional-chaining": "error",
"no-unused-labels": "error",
"no-unused-private-class-members": "error",
"no-unused-vars": "error",
"no-useless-backreference": "error",
"no-useless-catch": "error",
"no-useless-escape": "error",
"no-with": "error",
"require-yield": "error",
"use-isnan": "error",
"valid-typeof": "error"
},
"react": {
"react/display-name": 2,
"react/jsx-key": 2,
"react/jsx-no-comment-textnodes": 2,
"react/jsx-no-duplicate-props": 2,
"react/jsx-no-target-blank": 2,
"react/jsx-no-undef": 2,
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/no-children-prop": 2,
"react/no-danger-with-children": 2,
"react/no-deprecated": 2,
"react/no-direct-mutation-state": 2,
"react/no-find-dom-node": 2,
"react/no-is-mounted": 2,
"react/no-render-return-value": 2,
"react/no-string-refs": 2,
"react/no-unescaped-entities": 2,
"react/no-unknown-property": 2,
"react/no-unsafe": 0,
"react/prop-types": 2,
"react/react-in-jsx-scope": 2,
"react/require-render-return": 2
},
"jsxRuntime": {
"react/react-in-jsx-scope": 0,
"react/jsx-uses-react": 0
},
"hooks": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
},
"i18next": {
"i18next/no-literal-string": [
2
]
},
"typescript": [
{
"name": "typescript-eslint/base",
"languageOptions": {
"sourceType": "module"
}
},
{
"files": [
"**/*.ts",
"**/*.tsx",
"**/*.mts",
"**/*.cts"
],
"rules": {
"constructor-super": "off",
"getter-return": "off",
"no-class-assign": "off",
"no-const-assign": "off",
"no-dupe-args": "off",
"no-dupe-class-members": "off",
"no-dupe-keys": "off",
"no-func-assign": "off",
"no-import-assign": "off",
"no-new-native-nonconstructor": "off",
"no-new-symbol": "off",
"no-obj-calls": "off",
"no-redeclare": "off",
"no-setter-return": "off",
"no-this-before-super": "off",
"no-undef": "off",
"no-unreachable": "off",
"no-unsafe-negation": "off",
"no-var": "error",
"no-with": "off",
"prefer-const": "error",
"prefer-rest-params": "error",
"prefer-spread": "error"
},
"name": "typescript-eslint/eslint-recommended"
},
{
"name": "typescript-eslint/recommended",
"rules": {
"@typescript-eslint/ban-ts-comment": "error",
"no-array-constructor": "off",
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-extra-non-null-assertion": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/no-this-alias": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"@typescript-eslint/no-unsafe-declaration-merging": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": "error",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/prefer-as-const": "error",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/triple-slash-reference": "error"
}
}
],
"jest": {
"jest/expect-expect": "warn",
"jest/no-alias-methods": "error",
"jest/no-commented-out-tests": "warn",
"jest/no-conditional-expect": "error",
"jest/no-deprecated-functions": "error",
"jest/no-disabled-tests": "warn",
"jest/no-done-callback": "error",
"jest/no-export": "error",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/no-interpolation-in-snapshots": "error",
"jest/no-jasmine-globals": "error",
"jest/no-mocks-import": "error",
"jest/no-standalone-expect": "error",
"jest/no-test-prefixes": "error",
"jest/valid-describe-callback": "error",
"jest/valid-expect": "error",
"jest/valid-expect-in-promise": "error",
"jest/valid-title": "error"
},
"jestDom": {
"jest-dom/prefer-checked": "error",
"jest-dom/prefer-empty": "error",
"jest-dom/prefer-enabled-disabled": "error",
"jest-dom/prefer-focus": "error",
"jest-dom/prefer-in-document": "error",
"jest-dom/prefer-required": "error",
"jest-dom/prefer-to-have-attribute": "error",
"jest-dom/prefer-to-have-class": "error",
"jest-dom/prefer-to-have-style": "error",
"jest-dom/prefer-to-have-text-content": "error",
"jest-dom/prefer-to-have-value": "error"
},
"testingLibrary": {
"testing-library/await-async-events": [
"error",
{
"eventModule": "userEvent"
}
],
"testing-library/await-async-queries": "error",
"testing-library/await-async-utils": "error",
"testing-library/no-await-sync-events": [
"error",
{
"eventModules": [
"fire-event"
]
}
],
"testing-library/no-await-sync-queries": "error",
"testing-library/no-container": "error",
"testing-library/no-debugging-utils": "warn",
"testing-library/no-dom-import": [
"error",
"react"
],
"testing-library/no-global-regexp-flag-in-query": "error",
"testing-library/no-manual-cleanup": "error",
"testing-library/no-node-access": "error",
"testing-library/no-promise-in-fire-event": "error",
"testing-library/no-render-in-lifecycle": "error",
"testing-library/no-unnecessary-act": "error",
"testing-library/no-wait-for-multiple-assertions": "error",
"testing-library/no-wait-for-side-effects": "error",
"testing-library/no-wait-for-snapshot": "error",
"testing-library/prefer-find-by": "error",
"testing-library/prefer-presence-queries": "error",
"testing-library/prefer-query-by-disappearance": "error",
"testing-library/prefer-screen-queries": "error",
"testing-library/render-result-naming-convention": "error"
},
"storybook": [
{
"name": "storybook:recommended:setup"
},
{
"name": "storybook:recommended:stories-rules",
"files": [
"**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)",
"**/*.story.@(ts|tsx|js|jsx|mjs|cjs)"
],
"rules": {
"react-hooks/rules-of-hooks": "off",
"import/no-anonymous-default-export": "off",
"storybook/await-interactions": "error",
"storybook/context-in-play-function": "error",
"storybook/default-exports": "error",
"storybook/hierarchy-separator": "warn",
"storybook/no-redundant-story-name": "warn",
"storybook/no-renderer-packages": "error",
"storybook/prefer-pascal-case": "warn",
"storybook/story-exports": "error",
"storybook/use-storybook-expect": "error",
"storybook/use-storybook-testing-library": "error"
}
},
{
"name": "storybook:recommended:main-rules",
"files": [
".storybook/main.@(js|cjs|mjs|ts)"
],
"rules": {
"storybook/no-uninstalled-addons": "error"
}
}
]
}

View File

@@ -25,10 +25,19 @@ function loadRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
}; };
} }
const patternMatchers = new WeakMap();
function matchingPatterns(registry, file) { function matchingPatterns(registry, file) {
return registry.patterns.filter((pattern) => let matchers = patternMatchers.get(registry);
micromatch.isMatch(file, pattern), if (!matchers) {
); matchers = registry.patterns.map((pattern) => ({
pattern,
isMatch: micromatch.matcher(pattern),
}));
patternMatchers.set(registry, matchers);
}
return matchers
.filter(({ isMatch }) => isMatch(file))
.map(({ pattern }) => pattern);
} }
// An unclassified file counts as "global", and an exact key wins over a pattern. // An unclassified file counts as "global", and an exact key wins over a pattern.

View File

@@ -1,11 +1,9 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/enforce-module-public-api"; import rule from "../eslint-plugin-metabase/rules/enforce-module-public-api";
import { getPublicApiModules } from "../module-boundaries.mjs"; import { getPublicApiModules } from "../module-boundaries.mjs";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: { ecmaVersion: 2022, sourceType: "module" },
}); const ruleTester = createRuleTester();
const options = [{ modules: ["metabase/analytics"] }]; const options = [{ modules: ["metabase/analytics"] }];

View File

@@ -0,0 +1,62 @@
const assert = require("node:assert/strict");
const path = require("node:path");
const sdk = require("../../../build/embedding-sdk/rspack/resolve-config");
const {
ENTERPRISE_SRC_PATH,
} = require("../../../build/shared/rspack/resolve-aliases");
const app = require("../../../build/shared/rspack/resolve-config");
// Snapshot what lint sees before full configuration loading can mutate shared objects.
const light = { app: structuredClone(app), sdk: structuredClone(sdk) };
const fromNodeModules = Object.keys(require.cache).find((file) =>
file.includes(`${path.sep}node_modules${path.sep}`),
);
assert.equal(
fromNodeModules,
undefined,
`lint's resolve configs must stay dependency free, but loaded ${fromNodeModules}`,
);
const SDK_ENTERPRISE_ALIASES = {
"sdk-ee-plugins": "/sdk-plugins",
"sdk-iframe-embedding-ee-plugins": "/sdk-iframe-embedding-plugins",
"ee-overrides": "/overrides",
};
for (const [alias, subpath] of Object.entries(SDK_ENTERPRISE_ALIASES)) {
assert.equal(
light.sdk.resolve.alias[alias],
ENTERPRISE_SRC_PATH + subpath,
`${alias}: the SDK resolves to the enterprise tree in every edition`,
);
if (process.env.MB_EDITION === "ee") {
assert.equal(
light.app.resolve.alias[alias],
light.sdk.resolve.alias[alias],
`${alias}: EE app`,
);
} else {
assert.ok(
!light.app.resolve.alias[alias].startsWith(ENTERPRISE_SRC_PATH),
`${alias}: the OSS app must resolve to a noop stub, got ${light.app.resolve.alias[alias]}`,
);
}
}
for (const { name, snapshot, full } of [
{
name: "app",
snapshot: light.app,
full: require("../../../../rspack.main.config"),
},
{
name: "sdk",
snapshot: light.sdk,
full: require("../../../../rspack.embedding-sdk-bundle.config"),
},
]) {
assert.deepEqual(snapshot.resolve, full.resolve, `${name}: resolve`);
assert.deepEqual(snapshot.externals, full.externals, `${name}: externals`);
}

View File

@@ -1,16 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/jtag-missing-key"; import rule from "../eslint-plugin-metabase/rules/jtag-missing-key";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
ecmaVersion: 2015, const ruleTester = createRuleTester();
sourceType: "module",
parserOptions: {
ecmaFeatures: { jsx: true },
},
},
});
const VALID_CASES = [ const VALID_CASES = [
{ {

View File

@@ -1,14 +1,8 @@
import { RuleTester } from "eslint";
import tseslint from "typescript-eslint";
import rule from "../eslint-plugin-metabase/rules/no-analytics-import-outside-analytics-files"; import rule from "../eslint-plugin-metabase/rules/no-analytics-import-outside-analytics-files";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
parser: tseslint.parser, const ruleTester = createRuleTester();
sourceType: "module",
},
});
const errorMessage = const errorMessage =
/is only allowed in files named "analytics" or inside an "analytics\/" directory/; /is only allowed in files named "analytics" or inside an "analytics\/" directory/;

View File

@@ -1,15 +1,8 @@
import { RuleTester } from "eslint";
import tseslint from "typescript-eslint";
import rule from "../eslint-plugin-metabase/rules/no-base-api-access"; import rule from "../eslint-plugin-metabase/rules/no-base-api-access";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
parser: tseslint.parser, const ruleTester = createRuleTester();
parserOptions: { ecmaFeatures: { jsx: true } },
sourceType: "module",
},
});
const COMPONENT_FILE = "/repo/frontend/src/metabase/foo/components/Foo.tsx"; const COMPONENT_FILE = "/repo/frontend/src/metabase/foo/components/Foo.tsx";
const OWNER_FILE = "/repo/frontend/src/metabase/foo/api/bar.ts"; const OWNER_FILE = "/repo/frontend/src/metabase/foo/api/bar.ts";

View File

@@ -1,10 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-direct-memoize-import"; import rule from "../eslint-plugin-metabase/rules/no-direct-memoize-import";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: { ecmaVersion: 2022, sourceType: "module" },
}); const ruleTester = createRuleTester();
const error = { messageId: "noDirectMemoizeImport" }; const error = { messageId: "noDirectMemoizeImport" };
const FILE = "/repo/frontend/src/metabase/thing/new-file.ts"; const FILE = "/repo/frontend/src/metabase/thing/new-file.ts";

View File

@@ -1,16 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-literal-metabase-strings"; import rule from "../eslint-plugin-metabase/rules/no-literal-metabase-strings";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
ecmaVersion: 2015, const ruleTester = createRuleTester();
sourceType: "module",
parserOptions: {
ecmaFeatures: { jsx: true },
},
},
});
const VALID_CASES = [ const VALID_CASES = [
{ {

View File

@@ -1,16 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-locale-with-intl-functions"; import rule from "../eslint-plugin-metabase/rules/no-locale-with-intl-functions";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
ecmaVersion: 2015, const ruleTester = createRuleTester();
sourceType: "module",
parserOptions: {
ecmaFeatures: { jsx: true },
},
},
});
const VALID_CASES = [ const VALID_CASES = [
{ {

View File

@@ -1,10 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-module-level-memoize"; import rule from "../eslint-plugin-metabase/rules/no-module-level-memoize";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: { ecmaVersion: 2022, sourceType: "module" },
}); const ruleTester = createRuleTester();
const error = { messageId: "noModuleLevelMemoize" }; const error = { messageId: "noModuleLevelMemoize" };
const FILE = "/repo/frontend/src/metabase/thing/new-file.ts"; const FILE = "/repo/frontend/src/metabase/thing/new-file.ts";

View File

@@ -1,17 +1,10 @@
import path from "path"; import path from "path";
import { RuleTester } from "eslint";
import tseslint from "typescript-eslint";
import rule from "../eslint-plugin-metabase/rules/no-module-side-effects"; import rule from "../eslint-plugin-metabase/rules/no-module-side-effects";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
parser: tseslint.parser, const ruleTester = createRuleTester();
parserOptions: { ecmaFeatures: { jsx: true } },
sourceType: "module",
},
});
const FILENAME = "/repo/frontend/src/metabase/widgets/Widget/Widget.tsx"; const FILENAME = "/repo/frontend/src/metabase/widgets/Widget/Widget.tsx";
const REGISTRATION_FILE = const REGISTRATION_FILE =
@@ -21,10 +14,8 @@ const REGISTRATION_DIR = "/repo/frontend/src/metabase/widgets/api/";
const options = [{ sideEffectPaths: [REGISTRATION_FILE, REGISTRATION_DIR] }]; const options = [{ sideEffectPaths: [REGISTRATION_FILE, REGISTRATION_DIR] }];
// Real files, because the import check resolves each import on disk before looking it up. // The import checks resolve each specifier on disk before consulting the registry,
// registry.json classifies effects/{global,entry,self,registration}.ts, leaves unclassified.ts // so these cases point at real fixture files.
// unclassified, names facade/ a facade, and lists the packages leaflet-draw and @mantine/core/styles.css.
// pure.ts is not listed.
const FIXTURES = path.resolve(__dirname, "fixtures/side-effect-files"); const FIXTURES = path.resolve(__dirname, "fixtures/side-effect-files");
const IMPORTER = path.join(FIXTURES, "importer/Widget.tsx"); const IMPORTER = path.join(FIXTURES, "importer/Widget.tsx");
const registryOptions = { const registryOptions = {

View File

@@ -1,14 +1,8 @@
import { RuleTester } from "eslint";
import tseslint from "typescript-eslint";
import rule from "../eslint-plugin-metabase/rules/no-plugin-slot-outside-plugins-files"; import rule from "../eslint-plugin-metabase/rules/no-plugin-slot-outside-plugins-files";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
parser: tseslint.parser, const ruleTester = createRuleTester();
sourceType: "module",
},
});
const MODULE_FILE = "/repo/frontend/src/metabase/search/slots.ts"; const MODULE_FILE = "/repo/frontend/src/metabase/search/slots.ts";
const MODULE_INDEX = "/repo/frontend/src/metabase/search/index.ts"; const MODULE_INDEX = "/repo/frontend/src/metabase/search/index.ts";

View File

@@ -1,16 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-unconditional-metabase-links-render"; import rule from "../eslint-plugin-metabase/rules/no-unconditional-metabase-links-render";
const ruleTester = new RuleTester({ import { createRuleTester } from "./rule-tester";
languageOptions: {
ecmaVersion: 2015, const ruleTester = createRuleTester();
sourceType: "module",
parserOptions: {
ecmaFeatures: { jsx: true },
},
},
});
// Only importing `getShowMetabaseLinks` is not enough to pass the rule. // Only importing `getShowMetabaseLinks` is not enough to pass the rule.
// This doesn't necessarily mean that the link would be definitely conditionally // This doesn't necessarily mean that the link would be definitely conditionally

View File

@@ -1,17 +1,11 @@
import { RuleTester } from "eslint";
import tseslint from "typescript-eslint";
import rule from "../eslint-plugin-metabase/rules/no-unjustified-type-casts"; import rule from "../eslint-plugin-metabase/rules/no-unjustified-type-casts";
import { createRuleTester } from "./rule-tester";
const TS_FILENAME = "spec.ts"; // Angle-bracket casts only parse with JSX off const TS_FILENAME = "spec.ts"; // Angle-bracket casts only parse with JSX off
const TSX_FILENAME = "spec.tsx"; const TSX_FILENAME = "spec.tsx";
const ruleTester = new RuleTester({ const ruleTester = createRuleTester();
languageOptions: {
parser: tseslint.parser,
sourceType: "module",
},
});
const message = /Type casts .* must be preceded by a comment/; const message = /Type casts .* must be preceded by a comment/;

View File

@@ -1,8 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-unordered-test-helpers"; import rule from "../eslint-plugin-metabase/rules/no-unordered-test-helpers";
const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 2015 } }); import { createRuleTester } from "./rule-tester";
const ruleTester = createRuleTester();
const orderError = { const orderError = {
message: "H.restore() must come before H.resetTestTable()", message: "H.restore() must come before H.resetTestTable()",

View File

@@ -1,8 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-unsafe-element-filtering"; import rule from "../eslint-plugin-metabase/rules/no-unsafe-element-filtering";
const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 2015 } }); import { createRuleTester } from "./rule-tester";
const ruleTester = createRuleTester();
const unsafeError = { const unsafeError = {
messageId: "unexpected", messageId: "unexpected",

View File

@@ -1,8 +1,8 @@
import { RuleTester } from "eslint";
import rule from "../eslint-plugin-metabase/rules/no-unscoped-text-selectors"; import rule from "../eslint-plugin-metabase/rules/no-unscoped-text-selectors";
const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 2015 } }); import { createRuleTester } from "./rule-tester";
const ruleTester = createRuleTester();
const scopeError = { message: /should be scoped/i }; const scopeError = { message: /should be scoped/i };

View File

@@ -0,0 +1,236 @@
import assert from "node:assert/strict";
import { createRequire } from "node:module";
import path from "node:path";
import test from "node:test";
import { ESLint } from "eslint";
import {
elements,
enforcedRules,
boundaryOptions,
boundarySettings,
} from "../module-boundaries.mjs";
import {
createBoundaryChecker,
createBoundaryPlugin,
} from "../oxlint-boundaries.mjs";
import { ruleAliases } from "../oxlint/rule-aliases.mjs";
const root = path.resolve(import.meta.dirname, "../../..");
const require = createRequire(import.meta.url);
const checker = createBoundaryChecker({
elements,
rules: enforcedRules,
rootPath: root,
});
test("should accept aliased suppressions in the standalone boundary command", async () => {
const eslint = new ESLint({
cwd: root,
overrideConfigFile: path.join(root, "eslint.config.module-boundaries.mjs"),
});
const suppression = `/* eslint-disable ${Object.values(ruleAliases).join(", ")} */`;
const [valid] = await eslint.lintText(`${suppression}\nconst unused = 1;`, {
filePath: "frontend/src/metabase/dayjs/index.ts",
});
assert.deepEqual(valid.messages, []);
const [invalid] = await eslint.lintText(
`${suppression}\nimport "metabase/ui";`,
{ filePath: "frontend/src/metabase/dayjs/index.ts" },
);
assert.deepEqual(
invalid.messages.map((message) => message.ruleId),
["boundaries/element-types"],
);
});
test("should classify full paths before folders, including dot directories", () => {
const expectedTypes = {
"frontend/src/metabase/static-viz/index.tsx": "app/misc",
"frontend/src/metabase/static-viz/other.tsx": "shared/static-viz",
"frontend/src/metabase-lib/v1/metadata/Field.ts": "basic/mlv1",
"frontend/src/metabase-lib/query.ts": "lib/mlv2",
"frontend/src/embedding-sdk-shared/.storybook/preview.tsx": "app/misc",
"frontend/src/metabase/env.ts": "lib/env",
"frontend/src/metabase/unknown-module/file.ts": null,
"frontend/src/metabase/dayjs/.hidden/file.ts": null,
};
for (const [file, type] of Object.entries(expectedTypes)) {
assert.equal(checker.classify(path.join(root, file)).type, type, file);
}
assert.equal(
checker.classify(path.join(root, "e2e/fixture.ts")).isIgnored,
true,
);
});
test("should match upstream decisions for every declared module pair", () => {
const pluginRoot = path.dirname(require.resolve("eslint-plugin-boundaries"));
const { getSettings } = require(
path.join(pluginRoot, "Settings/Validations.js"),
);
const { elementRulesAllowDependency } = require(
path.join(pluginRoot, "Rules/ElementTypes.js"),
);
const settings = getSettings({
settings: { ...boundarySettings, "boundaries/root-path": root },
});
assert.deepEqual(checker.types, [
...new Set(elements.map((element) => element.type)),
]);
const element = (type) => ({
type,
origin: "local",
category: null,
captured: {},
path: `${type}/file.ts`,
elementPath: type,
internalPath: "file.ts",
parents: [],
isIgnored: false,
isUnknown: false,
});
for (const from of checker.types) {
for (const to of checker.types) {
const dependency = {
from: element(from),
to: { ...element(to), source: to },
dependency: {
kind: "value",
nodeKind: "import",
relationship: { from: null, to: null },
specifiers: [],
},
};
const expected = elementRulesAllowDependency(
dependency,
settings,
boundaryOptions,
);
assert.equal(
checker.decision(from, to).allowed,
expected.result,
`${from} -> ${to}`,
);
}
}
});
test("should enforce shared-tier restrictions and exceptions", () => {
for (const { from, to, allowed } of [
{
from: "shared/current-user",
to: "shared/metadata-store",
allowed: false,
},
{ from: "shared/metadata-store", to: "shared/current-user", allowed: true },
{ from: "shared/nav", to: "shared/palette", allowed: true },
{ from: "shared/palette", to: "shared/nav", allowed: true },
{ from: "lib/dayjs", to: "feature/query_builder", allowed: false },
]) {
assert.equal(
checker.decision(from, to).allowed,
allowed,
`${from} -> ${to}`,
);
}
for (const type of checker.types) {
assert.equal(checker.decision(type, type).allowed, true, type);
}
});
function elementTypes(from, to) {
const reports = [];
const plugin = createBoundaryPlugin({ resolve: () => path.join(root, to) });
const visitor = plugin.rules["element-types"].create({
filename: path.join(root, from),
options: [],
report: (report) => reports.push(report),
});
return { visitor, reports };
}
test("should check static and dynamic imports with string sources", () => {
const from = "frontend/src/metabase/dayjs/index.ts";
const to = "frontend/src/metabase/query_builder/index.ts";
const message = "lib/dayjs cannot import from feature/query_builder";
const source = { type: "Literal", value: "metabase/query_builder" };
const attributes = { type: "ObjectExpression", properties: [] };
const stringAttributes = {
type: "Literal",
value: "metabase/query_builder/attributes",
};
const template = { type: "TemplateLiteral", quasis: [], expressions: [] };
for (const { name, visit, reported } of [
{
name: "static import",
visit: (visitor) => visitor.ImportDeclaration({ source }),
reported: [source],
},
{
name: "dynamic import",
visit: (visitor) => visitor.ImportExpression({ source, options: null }),
reported: [source],
},
{
name: "dynamic import with attributes",
visit: (visitor) =>
visitor.ImportExpression({ source, options: attributes }),
reported: [source],
},
{
name: "dynamic import with a string second argument",
visit: (visitor) =>
visitor.ImportExpression({ source, options: stringAttributes }),
reported: [source, stringAttributes],
},
{
name: "template literal source",
visit: (visitor) =>
visitor.ImportExpression({ source: template, options: null }),
reported: [],
},
]) {
const { visitor, reports } = elementTypes(from, to);
visit(visitor);
assert.deepEqual(
reports,
reported.map((node) => ({ node, message })),
name,
);
}
const allowed = elementTypes(to, from);
allowed.visitor.ImportDeclaration({
source: { type: "Literal", value: "metabase/dayjs" },
});
assert.deepEqual(allowed.reports, []);
});
test("should reject unsupported boundary policies", () => {
for (const { input, error } of [
{
input: {
elements,
rules: [{ from: ["lib/*"], allow: ["lib/*"], importKind: "type" }],
},
error: /Unsupported boundary policy/,
},
{
input: {
elements: [{ type: "lib/a", pattern: "a/*", capture: ["name"] }],
rules: [],
},
error: /Unsupported boundary descriptor/,
},
]) {
assert.throws(
() => createBoundaryChecker({ ...input, rootPath: root }),
error,
);
}
});

Some files were not shown because too many files have changed in this diff Show More