Use oxlint (#82015)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
## Linting and Formatting
|
||||
|
||||
- **Lint:** `bun run lint-eslint-pure`
|
||||
- Run ESLint on the codebase
|
||||
- **Lint:** `bun run lint-oxlint-pure`
|
||||
- Run oxlint on the codebase
|
||||
- **Format:** `bun run format`
|
||||
- Format code with oxfmt (`oxfmt --write`); use `bun run lint-format-pure` to check without writing
|
||||
- **Type Check:** `bun run type-check-pure`
|
||||
|
||||
@@ -39,7 +39,7 @@ what and who may depend on whom.**
|
||||
| module elements, tiers, `enforceSharedTiers`, `enforcePublicApi` | `frontend/lint/module-boundaries.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`) |
|
||||
| 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`) |
|
||||
| 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()` |
|
||||
@@ -199,7 +199,7 @@ prefix; never generic `-shared` / `-feature` suffixes.
|
||||
```
|
||||
grep -rn "<old path>" frontend enterprise/frontend e2e # must be empty
|
||||
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 test-unit-keep-cljs <touched folders' specs>
|
||||
bun run module-boundaries 2>&1 | tail -1 # after; no violation may name the new files
|
||||
|
||||
@@ -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.
|
||||
- `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
|
||||
|
||||
@@ -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.
|
||||
- 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
|
||||
|
||||
|
||||
3
.github/file-paths.yaml
vendored
3
.github/file-paths.yaml
vendored
@@ -39,6 +39,8 @@ frontend_configs: &frontend_configs
|
||||
- "package.json"
|
||||
- "babel.config.json"
|
||||
- "eslint.config.mjs"
|
||||
- "oxlint.config.mts"
|
||||
- ".oxfmtrc.json"
|
||||
- "postcss.config.js"
|
||||
- "rspack.config.js"
|
||||
- "rspack.main.config.js"
|
||||
@@ -75,6 +77,7 @@ frontend_all: &frontend_all
|
||||
- *frontend_ci
|
||||
- *frontend_sources
|
||||
- *frontend_specs
|
||||
- "frontend/lint/**/!(*.md)"
|
||||
|
||||
frontend_loki_ci: &frontend_loki_ci
|
||||
- ".github/workflows/loki.yml"
|
||||
|
||||
8
.github/scripts/cache-keys.sh
vendored
8
.github/scripts/cache-keys.sh
vendored
@@ -78,10 +78,6 @@ CYPRESS_VERSION="$CYPRESS_VERSIONS"
|
||||
# and the key that identifies its cache entry cannot drift apart.
|
||||
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() {
|
||||
local name="$1"; shift
|
||||
printf '%s<<CACHE_KEYS_EOF\n' "$name"
|
||||
@@ -116,10 +112,6 @@ spec() {
|
||||
echo "cypress-path=$HOME/.cache/Cypress"
|
||||
echo "cypress-key=cypress-$OS-$CYPRESS_VERSION"
|
||||
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
|
||||
|
||||
8
.github/scripts/cache-keys.unit.spec.ts
vendored
8
.github/scripts/cache-keys.unit.spec.ts
vendored
@@ -3,7 +3,7 @@ import { join } from "path";
|
||||
|
||||
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
|
||||
// `::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", () => {
|
||||
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",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
26
.github/scripts/file-paths.unit.spec.ts
vendored
26
.github/scripts/file-paths.unit.spec.ts
vendored
@@ -62,6 +62,32 @@ describe("file-paths.yaml", () => {
|
||||
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([
|
||||
"jest.config.js",
|
||||
"jest.base.conf.js",
|
||||
|
||||
3
.github/workflows/cache-warm.yml
vendored
3
.github/workflows/cache-warm.yml
vendored
@@ -5,9 +5,6 @@
|
||||
# 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.
|
||||
#
|
||||
# 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 -
|
||||
# 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.
|
||||
|
||||
20
.github/workflows/frontend.yml
vendored
20
.github/workflows/frontend.yml
vendored
@@ -26,7 +26,7 @@ on:
|
||||
type: boolean
|
||||
default: false
|
||||
skip-lint:
|
||||
description: "Skip linting jobs (oxfmt, eslint, css variables check)"
|
||||
description: "Skip linting jobs (oxfmt, oxlint, css variables check)"
|
||||
type: boolean
|
||||
default: false
|
||||
skip-custom-viz:
|
||||
@@ -57,26 +57,16 @@ jobs:
|
||||
- name: Prepare back-end environment
|
||||
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
|
||||
run: bun run build-pure:cljs
|
||||
- name: Find CSS variables that are used but never defined
|
||||
run: bun run find-never-defined-css-variables
|
||||
- name: Run oxfmt formatting linter
|
||||
run: bun run lint-format-pure
|
||||
- name: Run ESLint linter
|
||||
run: bun run lint-eslint-pure
|
||||
- name: Run oxlint linter (including module boundaries)
|
||||
run: bun run lint-oxlint-pure
|
||||
- name: Verify lint configuration and behavior
|
||||
run: bun run test-oxlint
|
||||
- name: Run CSS linter
|
||||
run: bun run lint-css
|
||||
|
||||
|
||||
@@ -1,4 +1,75 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-env node */
|
||||
/* eslint-disable import/order */
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { spawn } = require("child_process");
|
||||
|
||||
308
bun.lock
308
bun.lock
@@ -115,7 +115,7 @@
|
||||
"mustache": "^2.3.2",
|
||||
"normalizr": "^3.0.2",
|
||||
"ora": "^8.0.1",
|
||||
"oxlint": "^1.58.0",
|
||||
"oxlint": "1.85.0",
|
||||
"prettier": "^3.3.3",
|
||||
"process": "^0.11.10",
|
||||
"prosemirror-dropcursor": "1.8.2",
|
||||
@@ -241,6 +241,7 @@
|
||||
"@types/redux-actions": "^2.6.5",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/underscore": "^1.13.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.60.0",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"ajv": "^8.5.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
@@ -272,13 +273,12 @@
|
||||
"eslint-plugin-boundaries": "5.4.0",
|
||||
"eslint-plugin-chai-friendly": "^1.1.0",
|
||||
"eslint-plugin-cypress": "6.1.0",
|
||||
"eslint-plugin-depend": "1.4.0",
|
||||
"eslint-plugin-i18next": "6.1.3",
|
||||
"eslint-plugin-import-x": "4.16.1",
|
||||
"eslint-plugin-depend": "1.5.0",
|
||||
"eslint-plugin-i18next": "6.1.4",
|
||||
"eslint-plugin-import-x": "4.17.1",
|
||||
"eslint-plugin-jest": "29.12.1",
|
||||
"eslint-plugin-jest-dom": "^5.5.0",
|
||||
"eslint-plugin-jest-formatting": "^3.1.0",
|
||||
"eslint-plugin-no-only-tests": "^3.3.0",
|
||||
"eslint-plugin-no-only-tests": "3.4.0",
|
||||
"eslint-plugin-react": "7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-storybook": "9.1.17",
|
||||
@@ -290,6 +290,7 @@
|
||||
"get-nonce": "^1.0.1",
|
||||
"glob": "^7.1.1",
|
||||
"globals": "^15.14.0",
|
||||
"html-entities": "2.3.2",
|
||||
"html-webpack-plugin": "5.5.0",
|
||||
"husky": "^9.1.7",
|
||||
"inquirer-file-selector": "^0.2.1",
|
||||
@@ -321,6 +322,7 @@
|
||||
"open-cli": "^8.0.0",
|
||||
"openapi-typescript": "^7.10.0",
|
||||
"otpauth": "^9.5.1",
|
||||
"oxc-resolver": "11.24.2",
|
||||
"oxfmt": "^0.38.0",
|
||||
"patch-package": "^8.0.1",
|
||||
"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=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
@@ -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=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
@@ -1217,6 +1219,44 @@
|
||||
|
||||
"@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-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=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
@@ -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=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
@@ -1931,25 +1971,25 @@
|
||||
|
||||
"@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/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/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/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=="],
|
||||
|
||||
@@ -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-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-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.3.0", "", {}, "sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q=="],
|
||||
"eslint-plugin-no-only-tests": ["eslint-plugin-no-only-tests@3.4.0", "", {}, "sha512-4S3/9Nb7A2tiMcpzEQE9bQSlpeOz6WJkgryBuou/SA8W2x2c8Zf4j0NvTKBjv6qNhF9T79tmkecm/0CHqV0UGg=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -5069,7 +5109,7 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -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/@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/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/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=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
@@ -5687,37 +5731,15 @@
|
||||
|
||||
"@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/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/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="],
|
||||
|
||||
"@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/ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="],
|
||||
|
||||
"@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=="],
|
||||
"@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.39.0", "", {}, "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg=="],
|
||||
|
||||
"@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-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=="],
|
||||
|
||||
@@ -6067,6 +6091,8 @@
|
||||
|
||||
"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/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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"@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/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=="],
|
||||
|
||||
@@ -7103,32 +7129,16 @@
|
||||
|
||||
"@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/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=="],
|
||||
"@typescript-eslint/scope-manager/@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/@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/@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/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/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/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-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-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/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=="],
|
||||
|
||||
"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-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=="],
|
||||
|
||||
"@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=="],
|
||||
|
||||
@@ -7995,20 +8001,14 @@
|
||||
|
||||
"@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/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-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-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=="],
|
||||
|
||||
@@ -8397,10 +8423,6 @@
|
||||
|
||||
"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/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=="],
|
||||
|
||||
"@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/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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"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/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=="],
|
||||
|
||||
"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/strip-ansi": ["strip-ansi@7.0.1", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw=="],
|
||||
|
||||
@@ -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.
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { createProbes } from "./probes";
|
||||
import {
|
||||
REACT_PROBES,
|
||||
ReactProbeHost,
|
||||
useProbeCustomElement,
|
||||
} from "./ReactProbes";
|
||||
import { createProbes } from "./probes";
|
||||
import type { ReactMode } from "./types";
|
||||
import { describeError, getEnv } from "./utils";
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import "cypress-iframe";
|
||||
|
||||
// this is the only place we allow direct helper import
|
||||
// eslint-disable-next-line metabase/no-direct-helper-import
|
||||
import { H } from "e2e/support";
|
||||
@@ -7,25 +6,17 @@ import { H } from "e2e/support";
|
||||
import "./commands/ui/button";
|
||||
import "./commands/ui/icon";
|
||||
import "./commands/ui/paste";
|
||||
|
||||
import "./commands/user/createUser";
|
||||
import "./commands/user/authentication";
|
||||
|
||||
import "./commands/permissions/updatePermissions";
|
||||
import "./commands/permissions/sandboxTable";
|
||||
|
||||
import "./commands/database/addSQLiteDatabase";
|
||||
|
||||
import "./commands/visibility/isVisibleInPopover";
|
||||
import "./commands/visibility/findByTextEnsureVisible";
|
||||
import "./commands/visibility/isRenderedWithinViewport";
|
||||
|
||||
import "./commands/overwrites/log";
|
||||
|
||||
import "./commands/skip-test";
|
||||
|
||||
import "./commands/component";
|
||||
|
||||
import { addCustomCommands } from "./commands/downloads/downloadUtils";
|
||||
addCustomCommands();
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// To apply cypress-level mantine styles
|
||||
import "@mantine/core/styles.css";
|
||||
import "@mantine/dates/styles.css";
|
||||
|
||||
// Mimics behavior when an app adds its own styles
|
||||
// We need to do it before importing the SDK
|
||||
import "e2e/support/helpers/embedding-sdk-helpers/host-app-styles.css";
|
||||
|
||||
import { Button, MantineProvider, Title } from "@mantine/core";
|
||||
import {
|
||||
InteractiveQuestion,
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* bun run build:custom-viz-fixtures
|
||||
*/
|
||||
|
||||
/* global console */
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { cpSync, mkdirSync, rmSync, statSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
@@ -37,7 +36,10 @@ const visualizations = [
|
||||
},
|
||||
{
|
||||
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(
|
||||
E2E_ASSETS,
|
||||
"example_custom_viz_plugin_4_security_component.tgz",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { MouseEvent } from "react";
|
||||
import { useState } from "react";
|
||||
|
||||
import { type CustomVisualizationProps, formatValue } from "../../../src/index";
|
||||
|
||||
type Settings = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { defineConfig } from "../../../src/index";
|
||||
import type { CreateCustomVisualization } from "../../../src/types/viz";
|
||||
|
||||
import { Visualization } from "./Visualization";
|
||||
|
||||
type Settings = {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
BaseWidgetProps,
|
||||
CreateCustomVisualization,
|
||||
} from "../../../src/types/viz";
|
||||
|
||||
import { Visualization } from "./Visualization";
|
||||
|
||||
type Settings = {
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
import type { AsyncThunkAction } from "@reduxjs/toolkit";
|
||||
|
||||
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 {
|
||||
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 { SdkAuthState } 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 {
|
||||
currentUserApi,
|
||||
loadCurrentUser,
|
||||
refetchCurrentUser,
|
||||
} 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 {
|
||||
EMBEDDING_SDK_IFRAME_EMBEDDING_CONFIG,
|
||||
isEmbeddingEajs,
|
||||
@@ -44,6 +41,9 @@ import {
|
||||
} from "metabase/embedding-sdk/config";
|
||||
import { samlTokenStorage } from "metabase/embedding-sdk/lib/saml-token-storage";
|
||||
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 { refetchSiteSettings, settingsApi } from "metabase/settings";
|
||||
import MetabaseSettings from "metabase/utils/settings";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Contains side effects that puts `MetabotQuestion` and `useMetabot` in the plugin
|
||||
import "./MetabotQuestion";
|
||||
import "./hooks/use-metabot";
|
||||
|
||||
import { METABOT_SDK_EE_PLUGIN } from "embedding-sdk-bundle/components/public/MetabotQuestion/MetabotQuestion";
|
||||
import { MetabotProvider } from "metabase/metabot/context";
|
||||
|
||||
|
||||
@@ -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 { 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";
|
||||
|
||||
type SpinnerProps = {
|
||||
|
||||
@@ -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 dataAppExports from "@metabase/embedding-sdk-react/data-app";
|
||||
import {
|
||||
@@ -15,6 +9,13 @@ import {
|
||||
devDiagnostics,
|
||||
instanceConnectionCheck,
|
||||
} 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 {
|
||||
allowedHosts,
|
||||
appSlug,
|
||||
@@ -24,10 +25,8 @@ import {
|
||||
rebuiltEvent,
|
||||
sdkVersion,
|
||||
} 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";
|
||||
|
||||
// The same baseline reset the production iframe loads (`iframe-vendors.ts`), so the
|
||||
// dev preview matches production. style-loader injects it at runtime.
|
||||
import "metabase-enterprise/data_apps/sandbox/iframe-baseline.css";
|
||||
|
||||
@@ -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 { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query";
|
||||
import { EMBEDDING_SDK_CONFIG } from "metabase/embedding-sdk/config";
|
||||
|
||||
import { count, filter, orderBy, sum } from "..";
|
||||
|
||||
import { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
beforeEach(resetTestState);
|
||||
afterEach(() => {
|
||||
EMBEDDING_SDK_CONFIG.isDataApp = false;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/* eslint-disable import/order */
|
||||
|
||||
// Register mocks before loading the modules under test.
|
||||
// oxfmt-ignore
|
||||
import { createMockStore, resetTestState } from "./setup";
|
||||
import { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query";
|
||||
|
||||
import { avg, breakout, filter, orderBy, sum } from "..";
|
||||
|
||||
import { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
beforeEach(resetTestState);
|
||||
|
||||
describe("resolveDatasetQuery validation", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable import/order */
|
||||
|
||||
// Register mocks before loading the modules under test.
|
||||
// oxfmt-ignore
|
||||
import {
|
||||
createMockStore,
|
||||
mockFetchTableMetadata,
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
resetTestState,
|
||||
stagesOf,
|
||||
} from "./setup";
|
||||
import { TEST_METADATA, TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
import { resolveDatasetQuery as resolveDatasetQueryInBundle } from "embedding-sdk-bundle/lib/create-metabase-query";
|
||||
import { cardApi } from "metabase/api";
|
||||
@@ -16,6 +15,8 @@ import * as Lib from "metabase-lib";
|
||||
|
||||
import { avg, breakout, count, filter, orderBy, sum } from "..";
|
||||
|
||||
import { TEST_METADATA, TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
beforeEach(resetTestState);
|
||||
|
||||
describe("resolveDatasetQuery", () => {
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/* eslint-disable import/order */
|
||||
|
||||
import { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
import type { MetabaseCard } from "metabase/embedding-sdk/types/question";
|
||||
|
||||
import type { MetabaseQueryOptions, UseMetabaseQueryObjectResult } from "..";
|
||||
@@ -12,8 +8,10 @@ import {
|
||||
useMetabaseQuery,
|
||||
useMetabaseQueryObject,
|
||||
} from "..";
|
||||
import { useAction, useDataAppAction } from "../../use-action";
|
||||
import { defineAction, defineQuery } from "../../../../data-app";
|
||||
import { useAction, useDataAppAction } from "../../use-action";
|
||||
|
||||
import { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
type OrdersTable = (typeof TEST_SCHEMA)["tables"]["orders"];
|
||||
|
||||
|
||||
@@ -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 { UseMetabaseQueryObjectResult } from "..";
|
||||
@@ -16,8 +10,11 @@ import {
|
||||
useMetabaseQuery,
|
||||
useMetabaseQueryObject,
|
||||
} from "..";
|
||||
import { useAction, useDataAppAction } from "../../use-action";
|
||||
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"];
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable import/order */
|
||||
|
||||
// Register mocks before loading the modules under test.
|
||||
// oxfmt-ignore
|
||||
import {
|
||||
TEST_DATASET_QUERY,
|
||||
createDeferred,
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
resetTestState,
|
||||
stubSdkBundle,
|
||||
} from "./setup";
|
||||
import { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
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 { defineQuery } from "../define-query";
|
||||
|
||||
import { TEST_SCHEMA } from "./fixtures";
|
||||
|
||||
beforeEach(resetTestState);
|
||||
|
||||
describe("useMetabaseQueryObject", () => {
|
||||
|
||||
@@ -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 type { StoryContext, StoryFn } from "@storybook/react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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";
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import "@mantine/core/styles.css";
|
||||
import "@mantine/dates/styles.css";
|
||||
|
||||
import "metabase-enterprise/data_apps/sandbox/iframe-baseline.css";
|
||||
|
||||
import "metabase/utils/csp-setup";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from "react";
|
||||
import * as ReactJsxRuntime from "react/jsx-runtime";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import * as ReactDOMClient from "react-dom/client";
|
||||
import * as ReactDOMServer from "react-dom/server";
|
||||
import * as ReactJsxRuntime from "react/jsx-runtime";
|
||||
import { pick } from "underscore";
|
||||
|
||||
import * as sdkExports from "embedding-sdk-package";
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// chunk. If this module is ever declared side-effect free, the bundler would
|
||||
// drop this import and the graph would render unstyled.
|
||||
import "@xyflow/react/dist/style.css";
|
||||
|
||||
import {
|
||||
Background,
|
||||
Controls,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {
|
||||
INVALID_AUTH_METHOD,
|
||||
MetabaseError,
|
||||
} from "embedding-sdk-shared/errors";
|
||||
import {
|
||||
connectToInstanceAuthSso,
|
||||
jwtDefaultRefreshTokenFunction,
|
||||
openSamlLoginPopup,
|
||||
validateSession,
|
||||
} 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 { EmbedAuthManagerContext } from "metabase/embedding/embedding-iframe-sdk/types/auth-manager";
|
||||
|
||||
/**
|
||||
* Manages authentication for embedded Metabase components.
|
||||
|
||||
@@ -51,10 +51,11 @@ const BillingInfoError = () => {
|
||||
<br />
|
||||
<strong>{t`Need help?`}</strong> {t`You can ask for billing help at `}
|
||||
<strong>
|
||||
{/* eslint-disable-next-line i18next/no-literal-string */}
|
||||
{/* eslint-disable i18next/no-literal-string -- untranslated billing address */}
|
||||
<Anchor href="mailto:billing@metabase.com">
|
||||
billing@metabase.com
|
||||
</Anchor>
|
||||
{/* eslint-enable i18next/no-literal-string */}
|
||||
</strong>
|
||||
</Alert>
|
||||
</Box>
|
||||
@@ -90,10 +91,11 @@ const BillingInfoNotStoreManaged = () => {
|
||||
description={
|
||||
<>
|
||||
{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">
|
||||
billing@metabase.com
|
||||
</Anchor>
|
||||
{/* eslint-enable i18next/no-literal-string */}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -24,9 +24,9 @@ import {
|
||||
MCP_EVENT_SORT_COLUMNS,
|
||||
type McpEventSortColumn,
|
||||
type McpFilters,
|
||||
buildEventsQuery,
|
||||
mcpEventColumnKeys,
|
||||
} from "metabase-enterprise/monitor/ai-auditing/mcp-analytics/query-utils";
|
||||
import { buildEventsQuery } from "metabase-enterprise/monitor/ai-auditing/mcp-analytics/query-utils";
|
||||
import type {
|
||||
CardMetadata,
|
||||
MetadataProvider,
|
||||
|
||||
@@ -4,10 +4,8 @@ import { PLUGIN_IS_EE_BUILD } from "metabase/plugins";
|
||||
PLUGIN_IS_EE_BUILD.isEEBuild = () => true;
|
||||
|
||||
import "./shared";
|
||||
|
||||
// PLUGINS THAT DON'T USE hasPremiumFeature (imported immediately):
|
||||
import "./license";
|
||||
|
||||
// PLUGINS THAT USE hasPremiumFeature (import initialization functions):
|
||||
import { initializePlugin as initializeAdvancedPermissions } from "./advanced_permissions";
|
||||
import { initializePlugin as initializeAiControls } from "./ai-controls";
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// chunk. If this module is ever declared side-effect free, the bundler would
|
||||
// drop this import and the graph would render unstyled.
|
||||
import "@xyflow/react/dist/style.css";
|
||||
|
||||
import {
|
||||
Background,
|
||||
Panel,
|
||||
|
||||
@@ -1,23 +1,34 @@
|
||||
/* eslint-disable import/order */
|
||||
// oxfmt-ignore
|
||||
import { PLUGIN_IS_EE_BUILD } from "metabase/plugins";
|
||||
|
||||
// oxfmt-ignore
|
||||
import { initializeSdkCustomVizPlugin } from "../embedding-sdk-ee/custom-viz/initialize";
|
||||
// oxfmt-ignore
|
||||
import { initializeHandleLinkPlugin } from "../embedding-sdk-ee/handle-link/handle-link";
|
||||
|
||||
// SETTINGS OVERRIDES:
|
||||
PLUGIN_IS_EE_BUILD.isEEBuild = () => true;
|
||||
|
||||
// oxfmt-ignore
|
||||
import "./shared";
|
||||
|
||||
// CORE APP PLUGINS THAT USE hasPremiumFeature (import initialization functions):
|
||||
// oxfmt-ignore
|
||||
import { initializePlugin as initializeContentTranslation } from "./content_translation";
|
||||
// oxfmt-ignore
|
||||
import { initializePlugin as initializeEmbedding } from "./embedding";
|
||||
// oxfmt-ignore
|
||||
import { initializePlugin as initializeEmbeddingSdk } from "./embedding-sdk";
|
||||
// oxfmt-ignore
|
||||
import { initializePlugin as initializeSharing } from "./sharing";
|
||||
// oxfmt-ignore
|
||||
import { initializePlugin as initializeTenants } from "./tenants";
|
||||
// oxfmt-ignore
|
||||
import { initializePlugin as initializeWhitelabelPlugin } from "./whitelabel";
|
||||
// oxfmt-ignore
|
||||
import { initializePlugin as initializeWhitelabelOverridePlugin } from "./whitelabel/sdk-overrides";
|
||||
|
||||
// oxfmt-ignore
|
||||
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.
|
||||
// These only apply to the SDK, not to the core app
|
||||
// oxfmt-ignore
|
||||
import "../embedding-sdk-ee/auth";
|
||||
// oxfmt-ignore
|
||||
import "../embedding-sdk-ee/metabot";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMemo } from "react";
|
||||
import { msgid, ngettext, t } from "ttag";
|
||||
|
||||
import { Ellipsified } from "metabase/ui";
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
Ellipsified,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
|
||||
@@ -3,8 +3,8 @@ import { c, t } from "ttag";
|
||||
|
||||
import { getFormattedTime } from "metabase/common/components/DateTime";
|
||||
import { formatNumber } from "metabase/static-viz/lib/numbers";
|
||||
import { Ellipsified } from "metabase/ui";
|
||||
import {
|
||||
Ellipsified,
|
||||
EntityNameCell,
|
||||
Flex,
|
||||
Text,
|
||||
|
||||
1280
eslint.config.mjs
1280
eslint.config.mjs
File diff suppressed because it is too large
Load Diff
@@ -4,10 +4,11 @@
|
||||
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
import boundaries from "eslint-plugin-boundaries";
|
||||
import react from "eslint-plugin-react";
|
||||
import tseslint from "typescript-eslint";
|
||||
import { globalIgnores, defineConfig } from "eslint/config";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
@@ -15,6 +16,7 @@ import {
|
||||
elements as boundaryElements,
|
||||
rules as boundaryRules,
|
||||
} 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
|
||||
const alwaysPassingRule = {
|
||||
@@ -63,6 +65,12 @@ export default defineConfig([
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
...Object.fromEntries(
|
||||
Object.values(ruleAliases).map((rule) => [
|
||||
rule.split("/")[0],
|
||||
alwaysPassingPlugin,
|
||||
]),
|
||||
),
|
||||
ttag: alwaysPassingPlugin,
|
||||
metabase: alwaysPassingPlugin,
|
||||
import: alwaysPassingPlugin,
|
||||
|
||||
18
frontend/build/embedding-sdk/rspack/resolve-config.js
Normal file
18
frontend/build/embedding-sdk/rspack/resolve-config.js
Normal 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,
|
||||
};
|
||||
@@ -80,4 +80,4 @@ const RESOLVE_ALIASES = {
|
||||
: SRC_PATH + "/plugins/noop",
|
||||
};
|
||||
|
||||
module.exports = { RESOLVE_ALIASES };
|
||||
module.exports = { ENTERPRISE_SRC_PATH, RESOLVE_ALIASES };
|
||||
|
||||
15
frontend/build/shared/rspack/resolve-config.js
Normal file
15
frontend/build/shared/rspack/resolve-config.js
Normal 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
38
frontend/lint/OXLINT.md
Normal 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
1216
frontend/lint/config.mjs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,17 @@
|
||||
|
||||
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.
|
||||
const DEFAULT_BASE_APIS = [
|
||||
{ module: "metabase/api", name: "Api" },
|
||||
@@ -70,14 +81,12 @@ module.exports = {
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode || context.getSourceCode();
|
||||
const filename = context.filename || context.getFilename();
|
||||
const { sourceCode, filename } = context;
|
||||
const options = context.options[0] || {};
|
||||
const baseApis = options.baseApis || DEFAULT_BASE_APIS;
|
||||
|
||||
// `dot: true` so a checkout under a dotted directory still matches `**`
|
||||
const isAllowedIn = (globs = []) =>
|
||||
globs.length > 0 && micromatch.isMatch(filename, globs, { dot: true });
|
||||
globs.length > 0 && matcherFor(globs)(filename);
|
||||
const injectionAllowed = isAllowedIn(options.allowInjectionIn);
|
||||
const reachAllowed = isAllowedIn(options.allowReachIn);
|
||||
|
||||
|
||||
@@ -218,8 +218,13 @@ module.exports = {
|
||||
const sourceRoots = (options.sourceRoots || DEFAULT_SOURCE_ROOTS).map(
|
||||
(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.
|
||||
const moduleScope = sourceCode.scopeManager.acquire(sourceCode.ast, true);
|
||||
let moduleScope;
|
||||
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) {
|
||||
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.
|
||||
function importOf(name) {
|
||||
const def = moduleScope.set
|
||||
.get(name)
|
||||
const def = getModuleScope()
|
||||
.set.get(name)
|
||||
?.defs.find(
|
||||
(def) =>
|
||||
def.type === "ImportBinding" &&
|
||||
@@ -245,7 +250,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
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()!`).
|
||||
@@ -572,7 +577,7 @@ function resolveSourceFile(base) {
|
||||
return (
|
||||
candidates.find((candidate) => {
|
||||
try {
|
||||
return fs.statSync(candidate).isFile();
|
||||
return fs.statSync(candidate, { throwIfNoEntry: false })?.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode || context.getSourceCode();
|
||||
const { sourceCode } = context;
|
||||
|
||||
function checkCast(node) {
|
||||
if (isConstAssertion(node)) {
|
||||
|
||||
@@ -570,3 +570,14 @@ export {
|
||||
getFeatureModules,
|
||||
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}",
|
||||
};
|
||||
|
||||
196
frontend/lint/oxlint-boundaries.mjs
Normal file
196
frontend/lint/oxlint-boundaries.mjs
Normal 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);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
225
frontend/lint/oxlint-import-resolver.mjs
Normal file
225
frontend/lint/oxlint-import-resolver.mjs
Normal 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 };
|
||||
}
|
||||
230
frontend/lint/oxlint/config.mjs
Normal file
230
frontend/lint/oxlint/config.mjs
Normal 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`),
|
||||
})),
|
||||
};
|
||||
}
|
||||
45
frontend/lint/oxlint/jsx-text.mjs
Normal file
45
frontend/lint/oxlint/jsx-text.mjs
Normal 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 } }),
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
39
frontend/lint/oxlint/module-scope.mjs
Normal file
39
frontend/lint/oxlint/module-scope.mjs
Normal 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 } }),
|
||||
},
|
||||
});
|
||||
}
|
||||
55
frontend/lint/oxlint/plugin.mjs
Normal file
55
frontend/lint/oxlint/plugin.mjs
Normal 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);
|
||||
},
|
||||
},
|
||||
];
|
||||
}),
|
||||
),
|
||||
};
|
||||
}
|
||||
7
frontend/lint/oxlint/plugins/boundaries.mjs
Normal file
7
frontend/lint/oxlint/plugins/boundaries.mjs
Normal 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 }),
|
||||
);
|
||||
3
frontend/lint/oxlint/plugins/chai-friendly.mjs
Normal file
3
frontend/lint/oxlint/plugins/chai-friendly.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "eslint-plugin-chai-friendly";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("chai-friendly", plugin);
|
||||
3
frontend/lint/oxlint/plugins/cypress.mjs
Normal file
3
frontend/lint/oxlint/plugins/cypress.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "eslint-plugin-cypress";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("cypress", plugin);
|
||||
4
frontend/lint/oxlint/plugins/depend.mjs
Normal file
4
frontend/lint/oxlint/plugins/depend.mjs
Normal 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);
|
||||
20
frontend/lint/oxlint/plugins/eslint-js.mjs
Normal file
20
frontend/lint/oxlint/plugins/eslint-js.mjs
Normal 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,
|
||||
];
|
||||
}),
|
||||
),
|
||||
});
|
||||
4
frontend/lint/oxlint/plugins/i18next.mjs
Normal file
4
frontend/lint/oxlint/plugins/i18next.mjs
Normal 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));
|
||||
34
frontend/lint/oxlint/plugins/import-js.mjs
Normal file
34
frontend/lint/oxlint/plugins/import-js.mjs
Normal 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,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
3
frontend/lint/oxlint/plugins/jest-dom.mjs
Normal file
3
frontend/lint/oxlint/plugins/jest-dom.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "eslint-plugin-jest-dom";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("jest-dom", plugin);
|
||||
3
frontend/lint/oxlint/plugins/jest-js.mjs
Normal file
3
frontend/lint/oxlint/plugins/jest-js.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "eslint-plugin-jest";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("jest-js", plugin);
|
||||
3
frontend/lint/oxlint/plugins/metabase.mjs
Normal file
3
frontend/lint/oxlint/plugins/metabase.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "../../eslint-plugin-metabase/index.js";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("metabase", plugin);
|
||||
1
frontend/lint/oxlint/plugins/no-only-tests.mjs
Normal file
1
frontend/lint/oxlint/plugins/no-only-tests.mjs
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from "eslint-plugin-no-only-tests";
|
||||
12
frontend/lint/oxlint/plugins/postcss-modules.mjs
Normal file
12
frontend/lint/oxlint/plugins/postcss-modules.mjs
Normal 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" },
|
||||
}),
|
||||
);
|
||||
3
frontend/lint/oxlint/plugins/react-js.mjs
Normal file
3
frontend/lint/oxlint/plugins/react-js.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "eslint-plugin-react";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("react-js", plugin);
|
||||
3
frontend/lint/oxlint/plugins/storybook.mjs
Normal file
3
frontend/lint/oxlint/plugins/storybook.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "eslint-plugin-storybook";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("storybook", plugin);
|
||||
3
frontend/lint/oxlint/plugins/testing-library.mjs
Normal file
3
frontend/lint/oxlint/plugins/testing-library.mjs
Normal file
@@ -0,0 +1,3 @@
|
||||
import plugin from "eslint-plugin-testing-library";
|
||||
import { wrap } from "../plugin.mjs";
|
||||
export default wrap("testing-library", plugin);
|
||||
4
frontend/lint/oxlint/plugins/ttag.mjs
Normal file
4
frontend/lint/oxlint/plugins/ttag.mjs
Normal 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));
|
||||
3
frontend/lint/oxlint/plugins/typescript-js.mjs
Normal file
3
frontend/lint/oxlint/plugins/typescript-js.mjs
Normal 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 });
|
||||
5
frontend/lint/oxlint/resolver.mjs
Normal file
5
frontend/lint/oxlint/resolver.mjs
Normal file
@@ -0,0 +1,5 @@
|
||||
import { ResolverFactory } from "oxc-resolver";
|
||||
|
||||
import { createImportResolverService } from "../oxlint-import-resolver.mjs";
|
||||
|
||||
export const resolver = createImportResolverService({ ResolverFactory });
|
||||
16
frontend/lint/oxlint/rule-aliases.mjs
Normal file
16
frontend/lint/oxlint/rule-aliases.mjs
Normal 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,
|
||||
]),
|
||||
);
|
||||
}
|
||||
139
frontend/lint/oxlint/rule-defaults.json
Normal file
139
frontend/lint/oxlint/rule-defaults.json
Normal 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": []
|
||||
}
|
||||
]
|
||||
}
|
||||
217
frontend/lint/oxlint/rule-map.json
Normal file
217
frontend/lint/oxlint/rule-map.json
Normal 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"
|
||||
}
|
||||
280
frontend/lint/recommended-rules.json
Normal file
280
frontend/lint/recommended-rules.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -25,10 +25,19 @@ function loadRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
|
||||
};
|
||||
}
|
||||
|
||||
const patternMatchers = new WeakMap();
|
||||
function matchingPatterns(registry, file) {
|
||||
return registry.patterns.filter((pattern) =>
|
||||
micromatch.isMatch(file, pattern),
|
||||
);
|
||||
let matchers = patternMatchers.get(registry);
|
||||
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.
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/enforce-module-public-api";
|
||||
import { getPublicApiModules } from "../module-boundaries.mjs";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: { ecmaVersion: 2022, sourceType: "module" },
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const options = [{ modules: ["metabase/analytics"] }];
|
||||
|
||||
|
||||
62
frontend/lint/tests/fixtures/resolve-config-parity.js
vendored
Normal file
62
frontend/lint/tests/fixtures/resolve-config-parity.js
vendored
Normal 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`);
|
||||
}
|
||||
@@ -1,16 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/jtag-missing-key";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
ecmaVersion: 2015,
|
||||
sourceType: "module",
|
||||
parserOptions: {
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const VALID_CASES = [
|
||||
{
|
||||
|
||||
@@ -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";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
sourceType: "module",
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const errorMessage =
|
||||
/is only allowed in files named "analytics" or inside an "analytics\/" directory/;
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/no-base-api-access";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
parserOptions: { ecmaFeatures: { jsx: true } },
|
||||
sourceType: "module",
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const COMPONENT_FILE = "/repo/frontend/src/metabase/foo/components/Foo.tsx";
|
||||
const OWNER_FILE = "/repo/frontend/src/metabase/foo/api/bar.ts";
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/no-direct-memoize-import";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: { ecmaVersion: 2022, sourceType: "module" },
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const error = { messageId: "noDirectMemoizeImport" };
|
||||
const FILE = "/repo/frontend/src/metabase/thing/new-file.ts";
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/no-literal-metabase-strings";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
ecmaVersion: 2015,
|
||||
sourceType: "module",
|
||||
parserOptions: {
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const VALID_CASES = [
|
||||
{
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/no-locale-with-intl-functions";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
ecmaVersion: 2015,
|
||||
sourceType: "module",
|
||||
parserOptions: {
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const VALID_CASES = [
|
||||
{
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/no-module-level-memoize";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: { ecmaVersion: 2022, sourceType: "module" },
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const error = { messageId: "noModuleLevelMemoize" };
|
||||
const FILE = "/repo/frontend/src/metabase/thing/new-file.ts";
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import path from "path";
|
||||
|
||||
import { RuleTester } from "eslint";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/no-module-side-effects";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
parserOptions: { ecmaFeatures: { jsx: true } },
|
||||
sourceType: "module",
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const FILENAME = "/repo/frontend/src/metabase/widgets/Widget/Widget.tsx";
|
||||
const REGISTRATION_FILE =
|
||||
@@ -21,10 +14,8 @@ const REGISTRATION_DIR = "/repo/frontend/src/metabase/widgets/api/";
|
||||
|
||||
const options = [{ sideEffectPaths: [REGISTRATION_FILE, REGISTRATION_DIR] }];
|
||||
|
||||
// Real files, because the import check resolves each import on disk before looking it up.
|
||||
// registry.json classifies effects/{global,entry,self,registration}.ts, leaves unclassified.ts
|
||||
// unclassified, names facade/ a facade, and lists the packages leaflet-draw and @mantine/core/styles.css.
|
||||
// pure.ts is not listed.
|
||||
// The import checks resolve each specifier on disk before consulting the registry,
|
||||
// so these cases point at real fixture files.
|
||||
const FIXTURES = path.resolve(__dirname, "fixtures/side-effect-files");
|
||||
const IMPORTER = path.join(FIXTURES, "importer/Widget.tsx");
|
||||
const registryOptions = {
|
||||
|
||||
@@ -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";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
sourceType: "module",
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const MODULE_FILE = "/repo/frontend/src/metabase/search/slots.ts";
|
||||
const MODULE_INDEX = "/repo/frontend/src/metabase/search/index.ts";
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
import rule from "../eslint-plugin-metabase/rules/no-unconditional-metabase-links-render";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
ecmaVersion: 2015,
|
||||
sourceType: "module",
|
||||
parserOptions: {
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
import { createRuleTester } from "./rule-tester";
|
||||
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
// Only importing `getShowMetabaseLinks` is not enough to pass the rule.
|
||||
// This doesn't necessarily mean that the link would be definitely conditionally
|
||||
|
||||
@@ -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 { createRuleTester } from "./rule-tester";
|
||||
|
||||
const TS_FILENAME = "spec.ts"; // Angle-bracket casts only parse with JSX off
|
||||
const TSX_FILENAME = "spec.tsx";
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
sourceType: "module",
|
||||
},
|
||||
});
|
||||
const ruleTester = createRuleTester();
|
||||
|
||||
const message = /Type casts .* must be preceded by a comment/;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
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 = {
|
||||
message: "H.restore() must come before H.resetTestTable()",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
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 = {
|
||||
messageId: "unexpected",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RuleTester } from "eslint";
|
||||
|
||||
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 };
|
||||
|
||||
|
||||
236
frontend/lint/tests/oxlint-boundaries.test.mjs
Normal file
236
frontend/lint/tests/oxlint-boundaries.test.mjs
Normal 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
Reference in New Issue
Block a user