From b13d6c2878e009a33cf505e16cf288e87839745e Mon Sep 17 00:00:00 2001 From: Anthony Lio Date: Fri, 2 Oct 2026 14:13:59 +0300 Subject: [PATCH] feat(chore): add a lint ratchet for shadcn rules (#51014) ## Problem shadcn lint rules has been soft landed in #50676 and are now on as warnings in every app, but nothing stops a PR from adding new violations linear: FE-4473 ## Solution - moved the ratchet script and its tests from `apps/studio/scripts` to `packages/eslint-config-supabase` so every app runs one copy - added a shared rule list, `packages/eslint-config-supabase/ratchet-rules.json` with the shadcn rules - www, docs, design-system, ui-library and learn get `lint-ratchet.yml` with one job per changed app (triggered by the app, `packages/**` or the lockfile) + a weekly `lint-ratchet-decrease.yml` (as for studio ratchet) - package tests run in `eslint-config-supabase-tests.yml` ## Review instructions 1. run `pnpm --filter ./apps/www run lint:ratchet` 2. add `p-[13px]` to a `className` in any www component and run it again. it fails with `shadcn/no-arbitrary-values` and the file name with `(+1)` 3. revert change 4. run `pnpm --filter eslint-config-supabase test` and see 6 tests pass 5. in ci, check `Ratchet studio lint checks` and the `ratchet ()` jobs for the apps this pr touches ## Checklist Check all before review: - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) - [x] If I wrote a new docs topic or edited an existing topic, I used the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs [style guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide) ## Summary by CodeRabbit * **Developer Improvements** * Expanded automated lint checks to cover additional apps and shared package changes. * Added checks for arbitrary Tailwind values, unknown classes, and raw colors across supported apps. * Added automated baseline updates that can open or update a pull request when lint counts change. * Added tests for the lint configuration and support for combining multiple rule files. * Updated Studio lint notifications to exclude Shadcn rules with zero-baseline counts. --- .../eslint-config-supabase-tests.yml | 43 +++ .github/workflows/lint-ratchet-decrease.yml | 109 +++++++ .github/workflows/lint-ratchet.yml | 85 ++++++ .../studio-lint-ratchet-decrease.yml | 2 +- .github/workflows/studio-lint-ratchet.yml | 2 + AGENTS.md | 2 +- .../.github/eslint-rule-baselines.json | 56 ++++ apps/design-system/package.json | 1 + apps/docs/.github/eslint-rule-baselines.json | 39 +++ apps/docs/package.json | 1 + apps/learn/.github/eslint-rule-baselines.json | 25 ++ apps/learn/package.json | 1 + .../studio/.github/eslint-rule-baselines.json | 261 ++++++++++++++++- apps/studio/package.json | 2 +- .../.github/eslint-rule-baselines.json | 37 +++ apps/ui-library/package.json | 1 + apps/www/.github/eslint-rule-baselines.json | 277 ++++++++++++++++++ apps/www/package.json | 1 + .../__tests__/ratchet-eslint-rules.test.ts | 54 +++- packages/eslint-config-supabase/package.json | 7 +- .../ratchet-eslint-rules.ts | 28 +- .../eslint-config-supabase/ratchet-rules.json | 1 + pnpm-lock.yaml | 6 + 23 files changed, 1021 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/eslint-config-supabase-tests.yml create mode 100644 .github/workflows/lint-ratchet-decrease.yml create mode 100644 .github/workflows/lint-ratchet.yml create mode 100644 apps/design-system/.github/eslint-rule-baselines.json create mode 100644 apps/docs/.github/eslint-rule-baselines.json create mode 100644 apps/learn/.github/eslint-rule-baselines.json create mode 100644 apps/ui-library/.github/eslint-rule-baselines.json create mode 100644 apps/www/.github/eslint-rule-baselines.json rename {apps/studio/scripts => packages/eslint-config-supabase}/__tests__/ratchet-eslint-rules.test.ts (73%) rename {apps/studio/scripts => packages/eslint-config-supabase}/ratchet-eslint-rules.ts (95%) create mode 100644 packages/eslint-config-supabase/ratchet-rules.json diff --git a/.github/workflows/eslint-config-supabase-tests.yml b/.github/workflows/eslint-config-supabase-tests.yml new file mode 100644 index 00000000000..0531b69bda1 --- /dev/null +++ b/.github/workflows/eslint-config-supabase-tests.yml @@ -0,0 +1,43 @@ +name: ESLint Config Tests + +on: + pull_request: + branches: ['master'] + paths: + - 'packages/eslint-config-supabase/**/*' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + sparse-checkout: | + packages/eslint-config-supabase + patches + + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + name: Install pnpm + with: + run_install: false + + - name: Use Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install deps + run: pnpm install --frozen-lockfile + + - name: Run tests + run: pnpm --filter eslint-config-supabase run test diff --git a/.github/workflows/lint-ratchet-decrease.yml b/.github/workflows/lint-ratchet-decrease.yml new file mode 100644 index 00000000000..c71af5a14bd --- /dev/null +++ b/.github/workflows/lint-ratchet-decrease.yml @@ -0,0 +1,109 @@ +name: Decrease lint ratchet baselines + +on: + schedule: + - cron: '0 0 * * SUN' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + decrease-baselines: + runs-on: blacksmith-4vcpu-ubuntu-2404 + + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + sparse-checkout: | + apps/www + apps/docs + apps/design-system + apps/ui-library + apps/learn + packages + patches + + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + name: Install pnpm + with: + run_install: false + + - name: Use Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install deps + run: pnpm install --frozen-lockfile + + - name: Generate token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + client-id: ${{ vars.GH_AUTOFIX_APP_CLIENT_ID }} + private-key: ${{ secrets.GH_AUTOFIX_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + + - name: Decrease ESLint ratchet baselines and open PR + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + run: | + set -eo pipefail + DEFAULT_BRANCH=${DEFAULT_BRANCH:-master} + + BRANCH="bot/decrease-lint-ratchet-baselines" + + git fetch origin "$DEFAULT_BRANCH" --depth=1 + if git ls-remote --exit-code --heads origin "$BRANCH" > /dev/null 2>&1; then + git fetch origin "$BRANCH":"$BRANCH" --depth=1 + git switch "$BRANCH" + git reset --hard "origin/$DEFAULT_BRANCH" + else + git switch --create "$BRANCH" "origin/$DEFAULT_BRANCH" + fi + + # Keep going past an app that regressed so the others still get decreased; + # the job fails at the end if any app did. + failed="" + APPS="www docs design-system ui-library learn" + for app in $APPS; do + pnpm --filter "./apps/$app" run lint:ratchet --decrease-baselines || failed="$failed $app" + done + + if git diff --quiet; then + echo "No baseline updates detected." + if [ -n "$failed" ]; then + echo "::error title=Ratchet regressions::New violations on $DEFAULT_BRANCH in:$failed" + exit 1 + fi + exit 0 + fi + + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + + for app in $APPS; do git add "apps/$app/.github/eslint-rule-baselines.json"; done + git commit --message "chore: decrease lint ratchet baselines" + git -c credential.helper= push --force "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "HEAD:${BRANCH}" + + pr_url=$(gh pr list --state open --head "$BRANCH" --json url --jq '.[0].url // ""' 2>/dev/null || echo "") + if [ -z "$pr_url" ]; then + gh pr create \ + --title "[bot] Decrease lint ratchet baselines" \ + --body "Automated weekly decrease of lint ratchet baselines." \ + --base "$DEFAULT_BRANCH" \ + --head "$BRANCH" + else + gh pr comment "$pr_url" --body "Updated lint ratchet baselines with the latest weekly decreases." + fi + + if [ -n "$failed" ]; then + echo "::error title=Ratchet regressions::New violations on $DEFAULT_BRANCH in:$failed" + exit 1 + fi diff --git a/.github/workflows/lint-ratchet.yml b/.github/workflows/lint-ratchet.yml new file mode 100644 index 00000000000..d2204ecbfd1 --- /dev/null +++ b/.github/workflows/lint-ratchet.yml @@ -0,0 +1,85 @@ +name: Ratchet lint checks + +on: + pull_request: + branches: + - master + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: read + +jobs: + changes: + runs-on: ubuntu-latest + outputs: + apps: ${{ steps.filter.outputs.changes }} + steps: + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: filter + with: + filters: | + shared: &shared + - 'packages/**' + - 'pnpm-lock.yaml' + www: + - *shared + - 'apps/www/**' + docs: + - *shared + - 'apps/docs/**' + design-system: + - *shared + - 'apps/design-system/**' + ui-library: + - *shared + - 'apps/ui-library/**' + learn: + - *shared + - 'apps/learn/**' + + ratchet: + needs: changes + if: ${{ needs.changes.outputs.apps != '[]' }} + # Uses larger hosted runner as it significantly decreases build times + runs-on: blacksmith-4vcpu-ubuntu-2404 + strategy: + fail-fast: false + matrix: + app: ${{ fromJSON(needs.changes.outputs.apps) }} + exclude: + - app: shared + + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + sparse-checkout: | + apps/${{ matrix.app }} + packages + patches + + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + name: Install pnpm + with: + run_install: false + + - name: Use Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install deps + run: pnpm install --frozen-lockfile + + # pnpm runs the script from the app directory, which is where the + # baselines were generated, so per-file keys line up. + - name: Run ratchet script + env: + APP: ${{ matrix.app }} + run: pnpm --filter "./apps/$APP" run lint:ratchet diff --git a/.github/workflows/studio-lint-ratchet-decrease.yml b/.github/workflows/studio-lint-ratchet-decrease.yml index 71ac4bcbec6..5d0f46812d6 100644 --- a/.github/workflows/studio-lint-ratchet-decrease.yml +++ b/.github/workflows/studio-lint-ratchet-decrease.yml @@ -103,7 +103,7 @@ jobs: run: | set -euo pipefail - zero_rules=$(jq -r '.rules | to_entries | map(select(.value == 0) | .key) | join(", ")' apps/studio/.github/eslint-rule-baselines.json) + zero_rules=$(jq -r '.rules | to_entries | map(select(.value == 0 and (.key | startswith("shadcn/") | not)) | .key) | join(", ")' apps/studio/.github/eslint-rule-baselines.json) if [ -z "$zero_rules" ]; then echo "No rules dropped to a baseline of 0; nothing to notify." diff --git a/.github/workflows/studio-lint-ratchet.yml b/.github/workflows/studio-lint-ratchet.yml index 2e4e91df520..5a6b50b06a5 100644 --- a/.github/workflows/studio-lint-ratchet.yml +++ b/.github/workflows/studio-lint-ratchet.yml @@ -6,6 +6,8 @@ on: - master paths: - 'apps/studio/**' + - 'packages/**' + - 'pnpm-lock.yaml' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} diff --git a/AGENTS.md b/AGENTS.md index d49e92295d4..6b56a9e1e05 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,7 @@ pnpm api:codegen # platform Management API types → packages/api-ty ## CI -Every PR must pass typecheck + lint (one workflow), Prettier, and a typos check. Other checks are path-filtered: Studio unit tests/build and the lint ratchet (ESLint warning count must not increase) run on `apps/studio/**` changes; app-specific test suites run on their own paths. +Every PR must pass typecheck + lint (one workflow), Prettier, and a typos check. Other checks are path-filtered: Studio unit tests/build and the lint ratchet (ESLint warning count must not increase) run on `apps/studio/**` changes and the Tailwind class rules (`shadcn/*`) for `www`, `docs`, `design-system`, `ui-library`, and `learn`; app-specific test suites run on their own paths. Never hand-edit generated files: `packages/api-types/types/**`, `**/routeTree.gen.ts`, `**/__generated__/**`, `apps/docs/features/docs/generated/**`, `apps/www/.generated/**`, `supabase/functions/common/database-types.ts`, `apps/docs/content/_partials/access-control/scoped_pat_*.mdx` (run `make -C apps/docs/spec generate.partials.access-control`). diff --git a/apps/design-system/.github/eslint-rule-baselines.json b/apps/design-system/.github/eslint-rule-baselines.json new file mode 100644 index 00000000000..b072aa793c1 --- /dev/null +++ b/apps/design-system/.github/eslint-rule-baselines.json @@ -0,0 +1,56 @@ +{ + "rules": { + "shadcn/no-arbitrary-values": 42, + "shadcn/no-unknown-classes": 8, + "shadcn/no-raw-colors": 22 + }, + "ruleFiles": { + "shadcn/no-arbitrary-values": { + "components/code-block-wrapper.tsx": 1, + "components/code-fragment.tsx": 7, + "components/color-palette.tsx": 2, + "components/command-menu.tsx": 1, + "components/component-preview.tsx": 12, + "components/mdx-components.tsx": 2, + "registry/default/example/admonition-button-split.tsx": 2, + "registry/default/example/assistant-chat-commands.tsx": 2, + "registry/default/example/button-split-dropdown.tsx": 2, + "registry/default/example/chart-tooltip-demo.tsx": 2, + "registry/default/example/command-dialog.tsx": 1, + "registry/default/example/connect-interstitial-shared.tsx": 2, + "registry/default/example/drawer-demo.tsx": 1, + "registry/default/example/page-layout-edge-function.tsx": 1, + "registry/default/example/toc-demo.tsx": 1, + "registry/default/example/toc-single-demo.tsx": 1, + "registry/default/example/typography-inline-code.tsx": 2 + }, + "shadcn/no-unknown-classes": { + "components/code-block-wrapper.tsx": 1, + "components/code-fragment.tsx": 1, + "components/component-preview.tsx": 1, + "components/mdx-components.tsx": 2, + "registry/default/example/data-grid-demo.tsx": 1, + "registry/default/example/data-grid-empty-state.tsx": 1, + "registry/default/example/form-patterns-sidepanel.tsx": 1 + }, + "shadcn/no-raw-colors": { + "components/code-block-wrapper.tsx": 2, + "components/copy-button.tsx": 3, + "registry/default/example/calendar-form.tsx": 1, + "registry/default/example/calendar-react-hook-form.tsx": 1, + "registry/default/example/checkbox-form-multiple.tsx": 1, + "registry/default/example/checkbox-form-single.tsx": 1, + "registry/default/example/combobox-form.tsx": 1, + "registry/default/example/connect-interstitial-shared.tsx": 3, + "registry/default/example/date-picker-form.tsx": 1, + "registry/default/example/input-form.tsx": 1, + "registry/default/example/input-otp-form.tsx": 1, + "registry/default/example/radio-group-card-form.tsx": 1, + "registry/default/example/radio-group-form.tsx": 1, + "registry/default/example/radio-group-stacked-form.tsx": 1, + "registry/default/example/select-form.tsx": 1, + "registry/default/example/switch-form.tsx": 1, + "registry/default/example/textarea-form.tsx": 1 + } + } +} diff --git a/apps/design-system/package.json b/apps/design-system/package.json index 9b268cd20e5..438b1c3ce3a 100644 --- a/apps/design-system/package.json +++ b/apps/design-system/package.json @@ -14,6 +14,7 @@ "build": "run-p build:registry build:content && pnpm build:next", "start": "next start", "lint": "eslint .", + "lint:ratchet": "tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts --rules-file node_modules/eslint-config-supabase/ratchet-rules.json", "clean": "rimraf .next .turbo tsconfig.tsbuildinfo .contentlayer .velite __registry__", "typecheck": "run-p build:registry build:content && tsc --noEmit -p tsconfig.json" }, diff --git a/apps/docs/.github/eslint-rule-baselines.json b/apps/docs/.github/eslint-rule-baselines.json new file mode 100644 index 00000000000..60d38d360f9 --- /dev/null +++ b/apps/docs/.github/eslint-rule-baselines.json @@ -0,0 +1,39 @@ +{ + "rules": { + "shadcn/no-arbitrary-values": 38, + "shadcn/no-unknown-classes": 19, + "shadcn/no-raw-colors": 3 + }, + "ruleFiles": { + "shadcn/no-arbitrary-values": { + "app/contributing/ContributingToC.tsx": 1, + "components/Feedback/Feedback.tsx": 15, + "components/GuidesSidebar.tsx": 1, + "components/StepHike/index.tsx": 1, + "features/docs/Reference.sections.tsx": 4, + "features/docs/Reference.ui.tsx": 4, + "features/ui/AgentWatchSchedule.tsx": 2, + "features/ui/CodeBlock/CodeBlock.client.tsx": 7, + "features/ui/PromptPanel.tsx": 3 + }, + "shadcn/no-unknown-classes": { + "app/guides/getting-started/ai-skills/AiSkillsIndex.tsx": 1, + "app/guides/local-development/cli/config/page.tsx": 1, + "components/GithubCard.tsx": 1, + "components/Navigation/NavigationMenu/GlobalMobileMenu.tsx": 1, + "components/Navigation/NavigationMenu/NavigationMenuCliList.tsx": 2, + "components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx": 2, + "components/Navigation/SideBar.tsx": 1, + "components/Params.tsx": 1, + "components/ProjectConfigVariables/ProjectConfigVariables.tsx": 2, + "features/docs/Reference.sections.tsx": 2, + "layouts/MainSkeleton.tsx": 1, + "layouts/ref/RefSubLayout.tsx": 2, + "layouts/ref/RefSubLayoutNonFunc.tsx": 2 + }, + "shadcn/no-raw-colors": { + "features/ui/CodeBlock/CodeBlock.tsx": 1, + "features/ui/PromptPanel.tsx": 2 + } + } +} diff --git a/apps/docs/package.json b/apps/docs/package.json index 862ba3687e3..c0c615f6dff 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -33,6 +33,7 @@ "last-changed": "tsx scripts/last-changed.ts", "last-changed:reset": "pnpm run last-changed -- --reset", "lint": "eslint .", + "lint:ratchet": "tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts --rules-file node_modules/eslint-config-supabase/ratchet-rules.json", "postbuild": "pnpm run build:sitemap && ./../../scripts/upload-static-assets.sh", "prebuild": "pnpm run codegen:graphql && pnpm run codegen:references && pnpm run codegen:examples && pnpm build:federated-content && pnpm run build:markdown && pnpm run build:gz-archive", "predev": "pnpm run codegen:graphql && pnpm run codegen:references && pnpm run codegen:examples", diff --git a/apps/learn/.github/eslint-rule-baselines.json b/apps/learn/.github/eslint-rule-baselines.json new file mode 100644 index 00000000000..8efbe43625c --- /dev/null +++ b/apps/learn/.github/eslint-rule-baselines.json @@ -0,0 +1,25 @@ +{ + "rules": { + "shadcn/no-arbitrary-values": 7, + "shadcn/no-unknown-classes": 6, + "shadcn/no-raw-colors": 7 + }, + "ruleFiles": { + "shadcn/no-arbitrary-values": { + "components/command-menu.tsx": 2, + "components/command.tsx": 2, + "components/course-hero.tsx": 1, + "components/mdx-components.tsx": 2 + }, + "shadcn/no-unknown-classes": { + "components/mdx-components.tsx": 5, + "components/side-navigation-item.tsx": 1 + }, + "shadcn/no-raw-colors": { + "components/chapter-completion.tsx": 1, + "components/course-hero.tsx": 1, + "components/mdx-components.tsx": 2, + "components/side-navigation.tsx": 3 + } + } +} diff --git a/apps/learn/package.json b/apps/learn/package.json index d6a963d70be..4ad5ea1b9ce 100644 --- a/apps/learn/package.json +++ b/apps/learn/package.json @@ -13,6 +13,7 @@ "internal:sync": "tsx ./scripts/sync-internal-content.mts", "start": "next start", "lint": "eslint .", + "lint:ratchet": "tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts --rules-file node_modules/eslint-config-supabase/ratchet-rules.json", "clean": "rimraf .next .turbo tsconfig.tsbuildinfo .contentlayer .velite tsconfig.tsbuildinfo", "typecheck": "pnpm build:content && tsc --noEmit" }, diff --git a/apps/studio/.github/eslint-rule-baselines.json b/apps/studio/.github/eslint-rule-baselines.json index 6d063265ab4..0cdb7fb6500 100644 --- a/apps/studio/.github/eslint-rule-baselines.json +++ b/apps/studio/.github/eslint-rule-baselines.json @@ -11,7 +11,10 @@ "jsx-a11y/no-redundant-roles": 2, "jsx-a11y/anchor-is-valid": 6, "jsx-a11y/heading-has-content": 2, - "valtio/state-snapshot-rule": 1 + "valtio/state-snapshot-rule": 1, + "shadcn/no-arbitrary-values": 212, + "shadcn/no-unknown-classes": 151, + "shadcn/no-raw-colors": 64 }, "ruleFiles": { "react-hooks/exhaustive-deps": { @@ -1000,6 +1003,262 @@ }, "valtio/state-snapshot-rule": { "state/storage-explorer.tsx": 1 + }, + "shadcn/no-arbitrary-values": { + "components/grid/components/editor/DateTimeEditor.tsx": 2, + "components/grid/components/editor/JsonEditor.tsx": 4, + "components/grid/components/editor/TextEditor.tsx": 4, + "components/grid/components/editor/TruncatedWarningOverlay.tsx": 1, + "components/grid/components/header/ExportDialog.tsx": 2, + "components/interfaces/Account/AccessTokens/Classic/ExperimentalTokenDropdown.tsx": 2, + "components/interfaces/Account/AccessTokens/Scoped/Form/RiskMarker.tsx": 2, + "components/interfaces/Account/AuditLogs/AuditLogOverview.tsx": 2, + "components/interfaces/Account/Preferences/HotkeyToggle.tsx": 1, + "components/interfaces/Auth/EmailTemplates/CustomEmailTemplateRestrictionAdmonition.tsx": 2, + "components/interfaces/Compute/RuntimeBadge.tsx": 1, + "components/interfaces/ConfigDrift/ConfigurationDriftPage.tsx": 1, + "components/interfaces/Database/Policies/PolicyEditorPanel/LockedQuerySection.tsx": 10, + "components/interfaces/Database/Policies/PolicyEditorPanel/index.tsx": 6, + "components/interfaces/Database/Privileges/PrivilegesHead.tsx": 1, + "components/interfaces/Database/Replication/ReplicationPipelineStatus/ReplicationPipelineStatus.tsx": 2, + "components/interfaces/Database/Roles/RoleRow.tsx": 1, + "components/interfaces/Database/Schemas/DefaultEdge.tsx": 2, + "components/interfaces/Database/Schemas/SchemaGraph.tsx": 2, + "components/interfaces/Database/Schemas/SchemaTableNode.tsx": 10, + "components/interfaces/Database/Tables/ConstraintToken.tsx": 4, + "components/interfaces/DiskManagement/DiskManagementReviewAndSubmitDialog/DiskManagementReviewAndSubmitDialog.tsx": 2, + "components/interfaces/DiskManagement/fields/StorageTypeField.tsx": 1, + "components/interfaces/DiskManagement/ui/DiskSpaceBar.tsx": 1, + "components/interfaces/Explorer/ExplorerOnboardingWireframes.tsx": 5, + "components/interfaces/Explorer/QueryEditor/QueryRunButton.tsx": 2, + "components/interfaces/Functions/EdgeFunctionOverview/EdgeFunctionInvocationsChart.tsx": 1, + "components/interfaces/Home/ProjectList/ProjectCard.tsx": 2, + "components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet/InstallationOverview.tsx": 1, + "components/interfaces/Integrations/Marketplace/MarketplaceFeaturedHeroGrid.tsx": 1, + "components/interfaces/Integrations/Marketplace/MarketplaceSidebar.tsx": 1, + "components/interfaces/Integrations/Queues/QueueTab.tsx": 1, + "components/interfaces/Integrations/VercelGithub/ProjectLinker.tsx": 2, + "components/interfaces/Integrations/Warehouse/WarehouseTableStatusList.tsx": 1, + "components/interfaces/Integrations/Wrappers/WrapperRow.tsx": 2, + "components/interfaces/LogDrains/OrgAuditLogDrains.tsx": 2, + "components/interfaces/Organization/BillingSettings/Subscription/PaymentMethodSelection.tsx": 1, + "components/interfaces/Organization/BillingSettings/Subscription/PlanCard.tsx": 11, + "components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.components.tsx": 2, + "components/interfaces/Organization/Documents/ISO27001.tsx": 1, + "components/interfaces/Organization/Documents/SOC2.tsx": 1, + "components/interfaces/Organization/HeaderBanner.tsx": 2, + "components/interfaces/Organization/OAuthApps/AuthorizeRequesterDetails.tsx": 1, + "components/interfaces/ProjectCreation/RegionSelector.tsx": 1, + "components/interfaces/ProjectHome/HighAvailabilityBadge.tsx": 5, + "components/interfaces/ProjectHome/PlanUsageCard.tsx": 1, + "components/interfaces/ProjectHome/ServerLightGrid.tsx": 1, + "components/interfaces/QueryInsights/QueryInsightsChart/QueryInsightsChart.tsx": 2, + "components/interfaces/QueryInsights/hooks/useQueryInsightsTableColumns.tsx": 2, + "components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx": 1, + "components/interfaces/Reports/ReportBlock/ChartBlock.tsx": 2, + "components/interfaces/Reports/ReportFilterBar.tsx": 3, + "components/interfaces/SQLEditor/DownloadSnippetModal.tsx": 1, + "components/interfaces/Settings/General/Infrastructure/RestartServerButton.tsx": 2, + "components/interfaces/Settings/General/TransferProjectPanel/TransferProjectButton.tsx": 1, + "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/MapView.tsx": 2, + "components/interfaces/Settings/Integrations/VercelIntegration/VercelSection.tsx": 1, + "components/interfaces/Settings/Logs/PreviewFilterPanel.tsx": 1, + "components/interfaces/Sidebar.tsx": 1, + "components/interfaces/SignIn/SignInMfaForm.tsx": 1, + "components/interfaces/Storage/AnalyticsBuckets/AnalyticsBucketDetails/CreateTable/CreateTableInstructionsDialog.tsx": 2, + "components/interfaces/Storage/AnalyticsBuckets/AnalyticsBucketDetails/NamespaceWithTables/TableRowComponent.tsx": 2, + "components/interfaces/Storage/BucketFilePickerDialog/BucketFilePickerHeader.tsx": 2, + "components/interfaces/Storage/StorageExplorer/FileExplorerRow.tsx": 2, + "components/interfaces/Storage/StorageExplorer/MoveItemsFolderPickerRow.tsx": 2, + "components/interfaces/Storage/StoragePolicies/StoragePoliciesEditor.tsx": 1, + "components/interfaces/Support/AttachmentUpload.tsx": 1, + "components/interfaces/TableGridEditor/GridHeaderActions.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx": 4, + "components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/index.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/TextEditor.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ForeignKeysManagement/ForeignKeyRow.tsx": 1, + "components/interfaces/UnifiedLogs/ServiceFlow/components/shared/DetailRow.tsx": 1, + "components/interfaces/UnifiedLogs/UnifiedLogs.fields.tsx": 5, + "components/interfaces/UnifiedLogs/components/Columns.tsx": 3, + "components/interfaces/UnifiedLogs/components/LogsList.tsx": 1, + "components/interfaces/UnifiedLogs/components/UserLogFilterControl.tsx": 2, + "components/layouts/Navigation/FloatingMobileToolbar/FloatingMobileToolbar.tsx": 2, + "components/layouts/Navigation/NavigationBar/MobileNavigationBar.tsx": 1, + "components/layouts/Navigation/NavigationBar/ProjectBranchSelectorSheetTabTrigger.tsx": 2, + "components/layouts/ProjectLayout/LogicalBackupCliInstructions.tsx": 1, + "components/layouts/SignInLayout/SignInLayout.tsx": 1, + "components/ui/AIEditor/AskAIWidget.tsx": 1, + "components/ui/AiAssistantDropdown.tsx": 2, + "components/ui/BannerStack/Banners/BannerExplorer.tsx": 3, + "components/ui/BannerStack/Banners/BannerSelect2026.tsx": 13, + "components/ui/Charts/BarChart.tsx": 1, + "components/ui/Charts/ComposedChart.utils.tsx": 2, + "components/ui/DataTable/DataTableFilters/DataTableFilterCheckbox.tsx": 2, + "components/ui/DataTable/DataTableFilters/DataTableFilterCheckboxAsync.tsx": 1, + "components/ui/DataTable/DataTableFilters/DataTableFilterResetButton.tsx": 1, + "components/ui/DataTable/primitives/InputWithAddons.tsx": 1, + "components/ui/DataTable/primitives/Kbd.tsx": 1, + "components/ui/EntityTypeIcon.tsx": 1, + "components/ui/ErrorCodeTooltip/ErrorCodeTooltip.tsx": 1, + "components/ui/GlobalShortcuts/ShortcutsReferenceSheet.tsx": 1, + "components/ui/ShortcutBadge.tsx": 1, + "components/ui/ShortcutTooltip.tsx": 1, + "pages/project/[ref]/settings/infrastructure/replica/[replicaId].tsx": 1, + "pages/project/[ref]/settings/log-drains.tsx": 2, + "state/shortcuts/useDynamicShortcut.tsx": 1, + "state/shortcuts/useShortcut.tsx": 1 + }, + "shadcn/no-unknown-classes": { + "components/grid/SupabaseGrid.tsx": 1, + "components/grid/components/editor/JsonEditor.tsx": 1, + "components/grid/components/editor/TextEditor.tsx": 1, + "components/grid/components/grid/ColumnHeader.tsx": 6, + "components/grid/components/grid/ColumnOverlayItem.tsx": 5, + "components/grid/components/grid/Grid.tsx": 1, + "components/grid/components/grid/SelectColumn.tsx": 5, + "components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx": 1, + "components/interfaces/Auth/AuthProvidersForm/FormField.tsx": 1, + "components/interfaces/Auth/AuthProvidersForm/index.tsx": 1, + "components/interfaces/Auth/CustomAuthProviders/CreateOrUpdateCustomProviderSheet.tsx": 1, + "components/interfaces/Auth/CustomAuthProviders/CustomAuthProvidersList.tsx": 1, + "components/interfaces/Auth/OAuthApps/CreateOrUpdateOAuthAppSheet.tsx": 1, + "components/interfaces/Auth/OAuthApps/OAuthAppsList.tsx": 1, + "components/interfaces/Auth/Overview/OverviewLearnMore.tsx": 1, + "components/interfaces/Auth/Users/UserPanel.tsx": 1, + "components/interfaces/Auth/Users/UsersGridComponents.tsx": 3, + "components/interfaces/Billing/Payment/AddNewPaymentMethodModal.tsx": 1, + "components/interfaces/BranchManagement/ConnectToGitHub.tsx": 1, + "components/interfaces/ConnectSheet/content/steps/direct-connection/IPv4StatusPanel.tsx": 1, + "components/interfaces/Database/EnumeratedTypes/CreateEnumeratedTypeSidePanel.tsx": 1, + "components/interfaces/Database/EnumeratedTypes/EditEnumeratedTypeSidePanel.tsx": 1, + "components/interfaces/Database/Functions/FunctionsList/FunctionList.tsx": 1, + "components/interfaces/Database/Hooks/EditHookPanel.tsx": 1, + "components/interfaces/Database/Policies/PolicyEditorPanel/PolicyEditorPanelHeader.tsx": 1, + "components/interfaces/Database/Policies/PolicyEditorPanel/PolicyTemplates.tsx": 1, + "components/interfaces/Database/Replication/ReplicationDiagram/Edges.tsx": 2, + "components/interfaces/Database/Replication/ReplicationDiagram/index.tsx": 1, + "components/interfaces/Database/Schemas/SchemaGraph.tsx": 1, + "components/interfaces/Database/Schemas/SchemaTableNode.tsx": 2, + "components/interfaces/Database/Triggers/ChooseFunctionForm.tsx": 1, + "components/interfaces/Database/Triggers/EventTriggersList/EventTriggerList.tsx": 1, + "components/interfaces/Database/Triggers/TriggersList/TriggerList.tsx": 1, + "components/interfaces/Docs/DocSection.tsx": 1, + "components/interfaces/Home/ProjectList/ShimmeringCard.tsx": 2, + "components/interfaces/Integrations/CronJobs/CronJobPage.tsx": 1, + "components/interfaces/Integrations/CronJobs/CronJobTableCell.tsx": 1, + "components/interfaces/Integrations/CronJobs/CronJobsTab.DataGrid.tsx": 1, + "components/interfaces/Integrations/CronJobs/PreviousRunsTab.tsx": 2, + "components/interfaces/Integrations/Queues/QueuesTab.tsx": 1, + "components/interfaces/Integrations/Queues/SingleQueue/QueueDataGrid.tsx": 1, + "components/interfaces/Integrations/Vault/Secrets/SecretsManagement.tsx": 1, + "components/interfaces/JwtSecrets/jwt-secret-keys-table/action-panel.tsx": 1, + "components/interfaces/Organization/BillingSettings/Subscription/UpgradeModal.tsx": 1, + "components/interfaces/Organization/ProjectClaim/confirm.tsx": 1, + "components/interfaces/Platform/Webhooks/PlatformWebhooksEndpointDetails.tsx": 1, + "components/interfaces/ProjectAPIDocs/ContentSnippet.tsx": 4, + "components/interfaces/ProjectAPIDocs/ResourceContent.tsx": 4, + "components/interfaces/QueryPerformance/IndexAdvisor/IndexSuggestionIcon.tsx": 1, + "components/interfaces/QueryPerformance/QueryIndexes.tsx": 2, + "components/interfaces/Realtime/Inspector/MessagesTable.tsx": 2, + "components/interfaces/Realtime/Inspector/SelectedRealtimeMessagePanel.tsx": 1, + "components/interfaces/Reports/ReportBlock/ChartBlock.tsx": 1, + "components/interfaces/Reports/ReportBlock/ReportBlockContainer.tsx": 1, + "components/interfaces/Reports/ReportPadding.tsx": 1, + "components/interfaces/Reports/renderers/ApiRenderers.tsx": 1, + "components/interfaces/Settings/API/HardenAPIModal.tsx": 4, + "components/interfaces/Settings/Addons/Addons.tsx": 2, + "components/interfaces/Settings/Database/DatabaseReadOnlyAlert.tsx": 1, + "components/interfaces/Settings/General/CustomDomainConfig/CustomDomainsShimmerLoader.tsx": 2, + "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DiagramFlow.tsx": 1, + "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/Edge.tsx": 2, + "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/HaInstanceConfiguration.tsx": 1, + "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx": 1, + "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/MapView.tsx": 1, + "components/interfaces/Settings/Integrations/VercelIntegration/VercelSection.tsx": 1, + "components/interfaces/Settings/Logs/LogTable.tsx": 3, + "components/interfaces/Settings/Logs/LogsFormatters.tsx": 4, + "components/interfaces/Storage/BucketFilePickerDialog/BucketFilePickerExplorer.tsx": 1, + "components/interfaces/Storage/BucketFilePickerDialog/BucketFilePickerRow.tsx": 1, + "components/interfaces/Storage/StorageBucketsError.tsx": 1, + "components/interfaces/Storage/StorageExplorer/FileExplorer.tsx": 1, + "components/interfaces/Storage/StorageExplorer/FileExplorerRow.tsx": 2, + "components/interfaces/Storage/StorageExplorer/FileExplorerRowEditing.tsx": 2, + "components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/ForeignRowSelector/SelectorGrid.tsx": 2, + "components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/TextEditor.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ForeignKeysManagement/ForeignKeyRow.tsx": 1, + "components/interfaces/UnifiedLogs/components/LogsListPanel.tsx": 2, + "components/layouts/Navigation/FloatingMobileToolbar/FloatingMobileToolbar.tsx": 1, + "components/layouts/Navigation/NavigationBar/MobileNavigationBar.tsx": 1, + "components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx": 1, + "components/layouts/WizardLayout.tsx": 2, + "components/ui/AIAssistantPanel/CollapsibleCodeBlock.tsx": 1, + "components/ui/AIAssistantPanel/MessageMarkdown.tsx": 1, + "components/ui/AIAssistantPanel/SupportAssistantSuccessCardContent.tsx": 1, + "components/ui/AIAssistantPanel/elements/Tool.tsx": 1, + "components/ui/AutoEnableRLSNotice.tsx": 1, + "components/ui/CodeEditor/CodeEditor.tsx": 2, + "components/ui/DataGridResults/CellDetailPanel.tsx": 1, + "components/ui/DataTable/DataTableInfinite.tsx": 1, + "components/ui/EdgeFunctionBlock/EdgeFunctionBlock.tsx": 1, + "components/ui/EditorPanel/EditorPanel.tsx": 1, + "components/ui/FileExplorerAndEditor/index.tsx": 2, + "components/ui/Forms/FormSection.tsx": 2, + "components/ui/QueryBlock/QueryBlock.tsx": 3, + "components/ui/ShimmerLine.tsx": 1, + "components/ui/Shimmers.tsx": 3, + "pages/project/[ref]/functions/[functionSlug]/code.tsx": 1, + "pages/project/[ref]/storage/vectors/buckets/[bucketId].tsx": 1 + }, + "shadcn/no-raw-colors": { + "components/interfaces/Advisors/AdvisorRuleItem.tsx": 1, + "components/interfaces/Auth/EmailTemplates/TemplateEditor.tsx": 1, + "components/interfaces/BranchManagement/BranchPanels.tsx": 1, + "components/interfaces/BranchManagement/CreateBranchModal.tsx": 6, + "components/interfaces/BranchManagement/DeleteBranchModal.tsx": 1, + "components/interfaces/ConnectSheet/content/steps/direct-connection/IPv4StatusPanel.tsx": 1, + "components/interfaces/Database/Functions/FunctionsList/FunctionsList.tsx": 2, + "components/interfaces/Database/Hooks/DeleteHookModal.tsx": 2, + "components/interfaces/Database/Migrations/Migrations.tsx": 1, + "components/interfaces/Database/Triggers/DeleteEventTrigger.tsx": 1, + "components/interfaces/Database/Triggers/TriggersList/TriggersList.tsx": 2, + "components/interfaces/DiskManagement/ui/DiskSpaceBar.tsx": 1, + "components/interfaces/Functions/FunctionsEmptyState.tsx": 1, + "components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx": 1, + "components/interfaces/Integrations/Marketplace/MarketplaceFeaturedHeroGrid.tsx": 2, + "components/interfaces/Integrations/Queues/SingleQueue/DeleteQueue.tsx": 1, + "components/interfaces/Integrations/Queues/SingleQueue/PurgeQueue.tsx": 1, + "components/interfaces/Integrations/VercelGithub/IntegrationPanels.tsx": 1, + "components/interfaces/JwtSecrets/jwt-secret-keys-table/signing-key-row.tsx": 1, + "components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingMetric.tsx": 2, + "components/interfaces/Organization/BillingSettings/Subscription/ExitSurveyModal.tsx": 1, + "components/interfaces/Organization/BillingSettings/Subscription/UpgradeModal.tsx": 1, + "components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx": 1, + "components/interfaces/Organization/TeamSettings/MembersView.tsx": 1, + "components/interfaces/ProjectCreation/ProjectCreationForm.tsx": 1, + "components/interfaces/Reports/renderers/ApiRenderers.tsx": 1, + "components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx": 4, + "components/interfaces/Settings/Integrations/IntegrationsSettings.tsx": 1, + "components/interfaces/Settings/Logs/Logs.DatePickers.tsx": 1, + "components/interfaces/SignIn/ForgotPasswordWizard.tsx": 2, + "components/interfaces/Storage/StoragePolicies/PolicyTemplates/TemplatesList.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/OperationQueueSidePanel/DeleteRowOperationItem.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/InputField.tsx": 1, + "components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/DrilldownViewer/DrilldownPane.tsx": 2, + "components/interfaces/TableGridEditor/SidePanelEditor/SpreadsheetImport/SpreadSheetFileUpload.tsx": 2, + "components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts": 1, + "components/layouts/AppLayout/EnableBranchingButton/BranchingPITRNotice.tsx": 1, + "components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx": 2, + "components/ui/AIAssistantPanel/Confirm.tsx": 1, + "components/ui/AIAssistantPanel/Message.Actions.tsx": 1, + "components/ui/AIAssistantPanel/MessagePartQueryLogs.tsx": 1, + "components/ui/DatePicker/TimeSplitInput.tsx": 1, + "components/ui/EdgeFunctionBlock/EdgeFunctionBlock.tsx": 2, + "components/ui/FileExplorerAndEditor/index.tsx": 1, + "components/ui/ProjectSettings/ToggleLegacyApiKeys.tsx": 1, + "components/ui/SqlWarningAdmonition.tsx": 1 } } } diff --git a/apps/studio/package.json b/apps/studio/package.json index 3549e6e0ea0..0ef65f11522 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -16,7 +16,7 @@ "build:tanstack": "vite build --mode ${MODE:-production}", "start:tanstack": "node --env-file-if-exists=.env --env-file-if-exists=.env.local --env-file-if-exists=.env.${MODE:-production} --env-file-if-exists=.env.${MODE:-production}.local .output/server/index.mjs", "lint": "eslint .", - "lint:ratchet": "tsx scripts/ratchet-eslint-rules.ts --rules-file scripts/ratchet-rules.json", + "lint:ratchet": "tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts --rules-file scripts/ratchet-rules.json --rules-file node_modules/eslint-config-supabase/ratchet-rules.json", "clean": "rimraf .next .turbo tsconfig.tsbuildinfo", "test": "vitest --run --coverage", "test:watch": "vitest watch", diff --git a/apps/ui-library/.github/eslint-rule-baselines.json b/apps/ui-library/.github/eslint-rule-baselines.json new file mode 100644 index 00000000000..c5a9dea417e --- /dev/null +++ b/apps/ui-library/.github/eslint-rule-baselines.json @@ -0,0 +1,37 @@ +{ + "rules": { + "shadcn/no-arbitrary-values": 36, + "shadcn/no-unknown-classes": 11, + "shadcn/no-raw-colors": 2 + }, + "ruleFiles": { + "shadcn/no-arbitrary-values": { + "app/example/headless-app/layout.tsx": 3, + "app/example/oauth-consent/layout.tsx": 3, + "app/example/password-based-auth/layout.tsx": 3, + "app/example/social-auth/layout.tsx": 3, + "components/catalog-preview.tsx": 5, + "components/command-menu.tsx": 2, + "components/command.tsx": 2, + "components/component-preview.tsx": 7, + "components/library-overview.tsx": 3, + "components/mdx-components.tsx": 2, + "components/tanstack-db-generator/index.tsx": 1, + "registry/default/blocks/realtime-flow/components/realtime-flow-overlay.tsx": 1, + "registry/default/platform/platform-kit-nextjs/components/supabase-manager/index.tsx": 1 + }, + "shadcn/no-unknown-classes": { + "app/(app)/docs/[[...slug]]/page.tsx": 2, + "components/block-overview-tabs.tsx": 2, + "components/block-preview.tsx": 1, + "components/component-preview.tsx": 2, + "components/mdx-components.tsx": 1, + "registry/default/components/ui/popover.tsx": 1, + "registry/default/components/ui/select.tsx": 1, + "registry/default/components/ui/tooltip.tsx": 1 + }, + "shadcn/no-raw-colors": { + "components/mdx-components.tsx": 2 + } + } +} diff --git a/apps/ui-library/package.json b/apps/ui-library/package.json index 9d84fb2bd9e..f05a14c6d89 100644 --- a/apps/ui-library/package.json +++ b/apps/ui-library/package.json @@ -18,6 +18,7 @@ "test:headless-tools": "tsx scripts/test-headless-tools.mts", "start": "next start", "lint": "eslint .", + "lint:ratchet": "tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts --rules-file node_modules/eslint-config-supabase/ratchet-rules.json", "clean": "rimraf .next .turbo tsconfig.tsbuildinfo .contentlayer .velite", "typecheck": "run-p build:content build:markdown && next typegen && tsc --noEmit -p tsconfig.json" }, diff --git a/apps/www/.github/eslint-rule-baselines.json b/apps/www/.github/eslint-rule-baselines.json new file mode 100644 index 00000000000..c4f1fffbb31 --- /dev/null +++ b/apps/www/.github/eslint-rule-baselines.json @@ -0,0 +1,277 @@ +{ + "rules": { + "shadcn/no-arbitrary-values": 527, + "shadcn/no-unknown-classes": 112, + "shadcn/no-raw-colors": 212 + }, + "ruleFiles": { + "shadcn/no-arbitrary-values": { + "app/(home)/_components/BuiltWithSupabaseSection.tsx": 2, + "app/(products)/auth/_components/FeaturesSection.tsx": 40, + "app/(products)/database/_components/FeaturesSection.tsx": 15, + "app/(products)/database/_components/Illustrations/SpreadsheetIllustration.tsx": 9, + "app/(products)/database/_components/VisualDemo.tsx": 5, + "app/(products)/edge-functions/_components/Highlights.tsx": 1, + "app/(products)/realtime/_components/FeaturesSection.tsx": 5, + "app/(products)/storage/_components/FeaturesSection.tsx": 16, + "app/contribute/about/page.tsx": 1, + "app/partners/PartnersContent.tsx": 2, + "app/state-of-startups/components/StateOfStartupsAuroraHeader.tsx": 2, + "app/state-of-startups/components/StateOfStartupsHeader.tsx": 2, + "app/state-of-startups/register/RegisterContent.tsx": 12, + "components/Blog/BlogGridItem.tsx": 1, + "components/BuiltWithSupabaseSection.tsx": 2, + "components/Changelog/ChangelogInlineMarkdown.tsx": 1, + "components/Changelog/ChangelogLlmMarkdownButton.tsx": 2, + "components/Changelog/ChangelogTimelineList.tsx": 2, + "components/Contribute/Hero.tsx": 1, + "components/Contribute/Icons.tsx": 2, + "components/Contribute/UnansweredThreadsTable.tsx": 2, + "components/Contribute/UserProfile.tsx": 2, + "components/CustomerStories/CutomsersSliderDesktop.tsx": 1, + "components/Error404.tsx": 3, + "components/Events/new/EventTimeline.tsx": 1, + "components/FeaturesMatrix.tsx": 1, + "components/Footer/index.tsx": 1, + "components/Go/TweetsSection.tsx": 2, + "components/LaunchWeek/11/HackathonCallout.tsx": 1, + "components/LaunchWeek/11/LW11Day1.tsx": 1, + "components/LaunchWeek/11/LW11Meetups.tsx": 1, + "components/LaunchWeek/11/LW11Summary.tsx": 1, + "components/LaunchWeek/11/LaunchWeekLogoHeader.tsx": 4, + "components/LaunchWeek/11/LaunchWeekPrizeSection.tsx": 1, + "components/LaunchWeek/11/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/11/Releases/components/AdventCard.tsx": 2, + "components/LaunchWeek/11/Releases/components/DaySection.tsx": 6, + "components/LaunchWeek/12/HackathonCallout.tsx": 1, + "components/LaunchWeek/12/LWMeetups.tsx": 1, + "components/LaunchWeek/12/LaunchWeekLogoHeader.tsx": 4, + "components/LaunchWeek/12/LaunchWeekPrizeSection.tsx": 1, + "components/LaunchWeek/12/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/12/Releases/Day1.tsx": 1, + "components/LaunchWeek/12/Releases/LWHeader.tsx": 1, + "components/LaunchWeek/12/Releases/components/BuildCard.tsx": 2, + "components/LaunchWeek/12/Releases/components/DaySection.tsx": 2, + "components/LaunchWeek/13/Releases/Day1.tsx": 1, + "components/LaunchWeek/13/Releases/components/BuildCard.tsx": 2, + "components/LaunchWeek/13/Releases/components/DaySection.tsx": 2, + "components/LaunchWeek/14/ActionButton.tsx": 6, + "components/LaunchWeek/14/Header.tsx": 4, + "components/LaunchWeek/14/Releases/components/BuildCard.tsx": 2, + "components/LaunchWeek/14/Releases/components/DaySection.tsx": 2, + "components/LaunchWeek/15/ActionButton.tsx": 6, + "components/LaunchWeek/15/LW15MainStage.tsx": 3, + "components/LaunchWeek/7/BlogLinks.tsx": 2, + "components/LaunchWeek/7/LabelBadge.tsx": 3, + "components/LaunchWeek/7/LaunchSection/LaunchWeekLogoHeader.tsx": 3, + "components/LaunchWeek/7/LaunchWeekPrizeCard.tsx": 1, + "components/LaunchWeek/7/LaunchWeekPrizeSection.tsx": 3, + "components/LaunchWeek/7/Releases/components/index.tsx": 22, + "components/LaunchWeek/7/Releases/index.tsx": 6, + "components/LaunchWeek/8/LWArchive.tsx": 3, + "components/LaunchWeek/8/LaunchWeekLogoHeader.tsx": 4, + "components/LaunchWeek/8/LaunchWeekPrizeCard.tsx": 1, + "components/LaunchWeek/8/Releases/LWAnnouncement.tsx": 1, + "components/LaunchWeek/8/Releases/components/index.tsx": 20, + "components/LaunchWeek/8/Releases/index.tsx": 17, + "components/LaunchWeek/X/Album/Player.tsx": 2, + "components/LaunchWeek/X/LWXMeetups.tsx": 7, + "components/LaunchWeek/X/LWXSummary.tsx": 1, + "components/LaunchWeek/X/LaunchWeekLogoHeader.tsx": 4, + "components/LaunchWeek/X/LaunchWeekPrizeCard.tsx": 2, + "components/LaunchWeek/X/LaunchWeekPrizeSection.tsx": 5, + "components/LaunchWeek/X/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/X/Releases/LWXStickyNav.tsx": 3, + "components/LaunchWeek/X/Releases/MainStage.tsx": 4, + "components/LaunchWeek/X/Releases/components/AdventCard.tsx": 7, + "components/LaunchWeek/X/Releases/components/DaySection.tsx": 9, + "components/Nav/ProductDropdown.tsx": 1, + "components/Nav/index.tsx": 3, + "components/OpenSource/OSSHero.tsx": 1, + "components/OpenSource/Sponsorships.tsx": 2, + "components/Panel/Panel.tsx": 1, + "components/Partners/BackgroundPattern.tsx": 1, + "components/Pricing/ComputePricingCalculator.tsx": 1, + "components/Pricing/PricingAddons.tsx": 4, + "components/Pricing/PricingComparisonTable.tsx": 1, + "components/Pricing/PricingComputeAnimation.tsx": 3, + "components/Pricing/PricingComputeSection.tsx": 4, + "components/Pricing/PricingPlans.tsx": 15, + "components/Products/DataAPIsVisual.tsx": 1, + "components/Products/Functions/CI.tsx": 1, + "components/Products/Functions/RealtimeLogs.tsx": 2, + "components/Products/RealtimeVisual.tsx": 10, + "components/Products/index.tsx": 1, + "components/Regions/RegionTooltip.tsx": 2, + "components/Sections/FeaturesSection.tsx": 1, + "components/Sections/ParagraphSection.tsx": 1, + "components/Sections/ProductHeader2.tsx": 1, + "components/Sections/ProductModulesHeader.tsx": 1, + "components/Sections/TimedTabsSection.tsx": 2, + "components/Sections/TwitterSocialProof.tsx": 2, + "components/Solutions/PostGrid.tsx": 1, + "components/SurveyResults/StateOfStartupsHeader.tsx": 2, + "components/UsersGrowthChart.tsx": 2, + "components/Wrapped/Pages/CustomerStories.tsx": 1, + "components/Wrapped/Pages/Devs.tsx": 1, + "components/Wrapped/Pages/Home.tsx": 1, + "components/Wrapped/Pages/ProductAnnouncements.tsx": 1, + "components/Wrapped/Pages/SupabaseSelect.tsx": 1, + "components/Wrapped/Pages/YearOfAI.tsx": 1, + "components/logos.tsx": 2, + "data/aws-reinvent-2025.tsx": 5, + "data/home/content.tsx": 4, + "data/products/functions/page.tsx": 1, + "data/solutions/agencies.tsx": 9, + "data/solutions/beginners.tsx": 6, + "data/solutions/developers.tsx": 9, + "data/solutions/firebase.tsx": 9, + "data/solutions/hackathon.tsx": 9, + "data/solutions/innovation-teams.tsx": 6, + "data/solutions/neon.tsx": 9, + "data/solutions/no-code.tsx": 5, + "data/solutions/postgres-developers.tsx": 9, + "data/solutions/startups.tsx": 9, + "data/solutions/vibe-coders.tsx": 5, + "pages/careers.tsx": 12, + "pages/changelog.tsx": 1, + "pages/contact-us.tsx": 3, + "pages/features.tsx": 5, + "pages/ga.tsx": 4, + "pages/launch-week/7/index.tsx": 2, + "pages/launch-week/8/index.tsx": 1, + "pages/support.tsx": 2 + }, + "shadcn/no-unknown-classes": { + "app/partners/PartnersContent.tsx": 1, + "app/state-of-startups/components/ParticipantsCarousel.tsx": 1, + "components/AIDemo/DotGrid.tsx": 1, + "components/AIDemo/Panel.tsx": 1, + "components/Announcement/Badge.tsx": 6, + "components/Avatar.tsx": 1, + "components/Blog/BlogCollapsible.tsx": 2, + "components/Card.tsx": 1, + "components/Changelog/ChangelogTimelineList.tsx": 1, + "components/CodeBlock/CodeBlock.tsx": 1, + "components/CustomerStories/CutomsersSliderDesktop.tsx": 1, + "components/Enterprise/CTAForm.tsx": 1, + "components/Go/TweetsSection.tsx": 2, + "components/LaunchWeek/11/LW11Day1.tsx": 2, + "components/LaunchWeek/11/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/11/Releases/LW11StickyNav.tsx": 1, + "components/LaunchWeek/11/Releases/components/AdventCard.tsx": 1, + "components/LaunchWeek/11/Releases/components/DaySection.tsx": 2, + "components/LaunchWeek/12/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/12/Releases/Day1.tsx": 2, + "components/LaunchWeek/12/Releases/LWStickyNav.tsx": 1, + "components/LaunchWeek/12/Releases/components/BuildCard.tsx": 1, + "components/LaunchWeek/12/Releases/components/DaySection.tsx": 2, + "components/LaunchWeek/13/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/13/Releases/Day1.tsx": 2, + "components/LaunchWeek/13/Releases/LWStickyNav.tsx": 2, + "components/LaunchWeek/13/Releases/components/BuildCard.tsx": 1, + "components/LaunchWeek/13/Releases/components/DaySection.tsx": 2, + "components/LaunchWeek/14/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/14/Releases/LWStickyNav.tsx": 2, + "components/LaunchWeek/14/Releases/components/BuildCard.tsx": 1, + "components/LaunchWeek/14/Releases/components/DaySection.tsx": 2, + "components/LaunchWeek/15/LW15BuildStage.tsx": 1, + "components/LaunchWeek/15/LW15Hackathon.tsx": 1, + "components/LaunchWeek/15/LW15Heading.tsx": 6, + "components/LaunchWeek/7/LaunchSection/LaunchWeekLogoHeader.tsx": 1, + "components/LaunchWeek/7/Releases/Day5.tsx": 2, + "components/LaunchWeek/7/Releases/index.tsx": 1, + "components/LaunchWeek/X/Album/Player.tsx": 1, + "components/LaunchWeek/X/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/X/Releases/LWXStickyNav.tsx": 1, + "components/LaunchWeek/X/Releases/components/DaySection.tsx": 2, + "components/Nav/MobileMenu.tsx": 1, + "components/OpenSource/RepoCard.tsx": 1, + "components/OpenSource/Repos.tsx": 2, + "components/OpenSource/Sponsorships.tsx": 1, + "components/Pricing/CostControlAnimation.tsx": 2, + "components/Pricing/PricingComparisonTable.tsx": 1, + "components/Pricing/PricingTableRow.tsx": 4, + "components/Products/Functions/RealtimeLogs.tsx": 2, + "components/Products/RealtimeVisual.tsx": 1, + "components/Products/StorageVisual.tsx": 1, + "components/Sections/APISection.tsx": 1, + "components/Sections/FunctionsUsecases.tsx": 1, + "components/Sections/HighlightCards.tsx": 1, + "components/Sections/ImageParagraphSection.tsx": 2, + "components/Sections/ProductHeader2.tsx": 2, + "components/Sections/TwitterSocialProof.tsx": 1, + "components/Solutions/CTAForm.tsx": 1, + "components/Solutions/FeaturesGrid.tsx": 2, + "components/Solutions/TwoColumnsSection.tsx": 2, + "components/Tabs/Tabs.tsx": 2, + "components/TabsWithHighlights.tsx": 2, + "components/VideoWithHighlights.tsx": 2, + "components/logos.tsx": 2, + "pages/beta.tsx": 2, + "pages/careers.tsx": 1, + "pages/changelog/[slug].tsx": 1, + "pages/contact/sales.tsx": 1, + "pages/customers/[slug].tsx": 3, + "pages/support.tsx": 2 + }, + "shadcn/no-raw-colors": { + "app/(home)/_components/logos/FrameworkLogos.tsx": 2, + "app/(home)/_components/logos/PublicityLogos.tsx": 12, + "app/(products)/auth/_components/FeaturesSection.tsx": 9, + "app/(products)/database/_components/FeaturesSection.tsx": 4, + "app/(products)/realtime/_components/FeaturesSection.tsx": 4, + "app/state-of-startups/StateOfStartups2026Content.tsx": 2, + "components/AIDemo/Panel.tsx": 1, + "components/CaseStudies/benchmark.tsx": 1, + "components/Charts/DeveloperGrowthChart.tsx": 2, + "components/ExampleCard.tsx": 3, + "components/LaunchWeek/14/ActionButton.tsx": 12, + "components/LaunchWeek/14/Header.tsx": 6, + "components/LaunchWeek/15/ActionButton.tsx": 12, + "components/LaunchWeek/7/LaunchWeekPrizeSection.tsx": 2, + "components/LaunchWeek/7/Releases/components/index.tsx": 8, + "components/LaunchWeek/7/Releases/index.tsx": 3, + "components/LaunchWeek/8/LWArchive.tsx": 1, + "components/LaunchWeek/8/Releases/components/index.tsx": 11, + "components/LaunchWeek/X/Album/Player.tsx": 1, + "components/LaunchWeek/X/Releases/BuildStage.tsx": 1, + "components/LaunchWeek/X/Releases/data/lwx_advent_days.tsx": 20, + "components/Nav/ProductDropdown.tsx": 1, + "components/OpenSource/RepoCard.tsx": 2, + "components/Panel/Panel.tsx": 1, + "components/Partners/BackgroundPattern.tsx": 1, + "components/Pricing/PricingIcons.tsx": 1, + "components/Pricing/PricingTableRow.tsx": 1, + "components/Products/DatabaseVisual.tsx": 3, + "components/Products/Functions/Metrics.tsx": 2, + "components/Products/VectorAI/OpenAIImage.tsx": 4, + "components/Products/VectorVisual.tsx": 2, + "components/Realtime/sandpack.tsx": 1, + "components/Sections/CustomerQuotesSection.tsx": 1, + "components/SurveyResults/SurveyChart.tsx": 1, + "components/code-display.tsx": 5, + "data/BetaPage.js": 6, + "data/Solutions.tsx": 9, + "data/products/database/pipelines-visual.tsx": 19, + "data/solutions/agencies.tsx": 1, + "data/solutions/ai-builders.tsx": 14, + "data/solutions/beginners.tsx": 1, + "data/solutions/developers.tsx": 1, + "data/solutions/firebase.tsx": 1, + "data/solutions/hackathon.tsx": 1, + "data/solutions/neon.tsx": 1, + "data/solutions/no-code.tsx": 1, + "data/solutions/postgres-developers.tsx": 1, + "data/solutions/startups.tsx": 1, + "data/solutions/vibe-coders.tsx": 1, + "pages/assistant.tsx": 2, + "pages/beta.tsx": 2, + "pages/brand-assets.tsx": 2, + "pages/modules/cron.tsx": 1, + "pages/modules/queues.tsx": 1, + "pages/modules/vector.tsx": 1, + "pages/state-of-startups-2025.tsx": 2 + } + } +} diff --git a/apps/www/package.json b/apps/www/package.json index 699d9cfeedd..3c2dd50222f 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -12,6 +12,7 @@ "export": "next export", "start": "next start", "lint": "eslint .", + "lint:ratchet": "tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts --rules-file node_modules/eslint-config-supabase/ratchet-rules.json", "clean": "rimraf .next .turbo tsconfig.tsbuildinfo", "pretypecheck": "next typegen", "typecheck": "pnpm run content:build:core && tsc --noEmit", diff --git a/apps/studio/scripts/__tests__/ratchet-eslint-rules.test.ts b/packages/eslint-config-supabase/__tests__/ratchet-eslint-rules.test.ts similarity index 73% rename from apps/studio/scripts/__tests__/ratchet-eslint-rules.test.ts rename to packages/eslint-config-supabase/__tests__/ratchet-eslint-rules.test.ts index 18da11ee685..010387a01d1 100644 --- a/apps/studio/scripts/__tests__/ratchet-eslint-rules.test.ts +++ b/packages/eslint-config-supabase/__tests__/ratchet-eslint-rules.test.ts @@ -1,13 +1,15 @@ -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { spawnSync } from 'node:child_process' +import { mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs' +import { createRequire } from 'node:module' import os from 'node:os' import path from 'node:path' import { afterEach, describe, expect, it, vi } from 'vitest' import { runRatchet } from '../ratchet-eslint-rules' -const studioRoot = path.resolve(__dirname, '../..') -const repoRoot = path.resolve(studioRoot, '..', '..') -const scriptArgvPlaceholder = path.resolve(studioRoot, 'scripts', 'ratchet-eslint-rules.ts') +const packageRoot = path.resolve(__dirname, '..') +const repoRoot = path.resolve(packageRoot, '..', '..') +const scriptArgvPlaceholder = path.resolve(packageRoot, 'ratchet-eslint-rules.ts') const tempDirs: string[] = [] @@ -83,6 +85,36 @@ describe('ratchet-eslint-rules integration', () => { expect(combinedErrors).toContain(`${relativeToCwd('apps/studio/src/b.ts')} (+1)`) }) + it('combines rule ids from repeated --rules-file flags', () => { + const tmp = createTempDir() + const metadataPath = path.join(tmp, 'baseline.json') + const appRulesPath = path.join(tmp, 'app-rules.json') + const sharedRulesPath = path.join(tmp, 'shared-rules.json') + writeFileSync(appRulesPath, JSON.stringify(['no-console'])) + writeFileSync(sharedRulesPath, JSON.stringify(['no-debugger'])) + + const eslintResults = buildEslintResults([ + { filePath: repoPath('apps/studio/src/a.ts'), rules: { 'no-console': 1, 'no-debugger': 2 } }, + ]) + + const result = invokeRatchet( + [ + '--metadata', + metadataPath, + '--rules-file', + appRulesPath, + '--rules-file', + sharedRulesPath, + '--init', + ], + eslintResults + ) + + expect(result).toBe(0) + const baseline = JSON.parse(readFileSync(metadataPath, 'utf8')) + expect(baseline.rules).toEqual({ 'no-console': 1, 'no-debugger': 2 }) + }) + it('reads rule ids from --rules-file', () => { const tmp = createTempDir() const metadataPath = path.join(tmp, 'baseline.json') @@ -137,6 +169,20 @@ describe('ratchet-eslint-rules integration', () => { }) }) +describe('ratchet-eslint-rules CLI', () => { + it('runs when invoked through a symlink', () => { + const tmp = createTempDir() + const link = path.join(tmp, 'ratchet-eslint-rules.ts') + symlinkSync(scriptArgvPlaceholder, link) + + const tsxCli = createRequire(import.meta.url).resolve('tsx/cli') + const proc = spawnSync(process.execPath, [tsxCli, link], { encoding: 'utf8' }) + + expect(proc.status).toBe(2) + expect(proc.stderr).toContain('You must provide at least one --rule') + }) +}) + function buildEslintResults( files: Array<{ filePath: string; rules: Record }> ): unknown[] { diff --git a/packages/eslint-config-supabase/package.json b/packages/eslint-config-supabase/package.json index 0ccb3ec86f0..580d6457822 100644 --- a/packages/eslint-config-supabase/package.json +++ b/packages/eslint-config-supabase/package.json @@ -5,7 +5,8 @@ "license": "MIT", "scripts": { "preinstall": "npx only-allow pnpm", - "clean": "rimraf .turbo tsconfig.tsbuildinfo" + "clean": "rimraf .turbo tsconfig.tsbuildinfo", + "test": "vitest run" }, "devDependencies": { "@shadcn/lint": "0.1.5", @@ -15,6 +16,8 @@ "eslint-config-next": "^16.0.0", "eslint-config-prettier": "^10.0.0", "eslint-config-turbo": "^2.5.0", - "typescript": "catalog:" + "tsx": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" } } diff --git a/apps/studio/scripts/ratchet-eslint-rules.ts b/packages/eslint-config-supabase/ratchet-eslint-rules.ts similarity index 95% rename from apps/studio/scripts/ratchet-eslint-rules.ts rename to packages/eslint-config-supabase/ratchet-eslint-rules.ts index eed8c1b3498..093aa99bc96 100644 --- a/apps/studio/scripts/ratchet-eslint-rules.ts +++ b/packages/eslint-config-supabase/ratchet-eslint-rules.ts @@ -4,15 +4,15 @@ * * Examples: * # Initialize baselines for two rules - * tsx scripts/ratchet-eslint-rules.ts --init \ + * tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts --init \ * --rule react-hooks/exhaustive-deps --rule no-console * * # Compare current counts vs baselines - * tsx scripts/ratchet-eslint-rules.ts \ + * tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts \ * --rule react-hooks/exhaustive-deps --rule no-console * # Decrease baselines when improvements occur - * tsx scripts/ratchet-eslint-rules.ts \ + * tsx node_modules/eslint-config-supabase/ratchet-eslint-rules.ts \ * --rule react-hooks/exhaustive-deps --rule no-console \ * --decrease-baselines * @@ -32,7 +32,14 @@ */ import { spawnSync } from 'node:child_process' -import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' +import { + appendFileSync, + existsSync, + mkdirSync, + readFileSync, + realpathSync, + writeFileSync, +} from 'node:fs' import path from 'node:path' import { pathToFileURL } from 'node:url' @@ -43,7 +50,7 @@ interface Args { eslintArgs: string decreaseBaselines: boolean rules: string[] - rulesFile?: string + rulesFiles: string[] } interface ESLintMessage { @@ -103,6 +110,7 @@ function parseArgs(argv: string[]): Args { eslintArgs: '', decreaseBaselines: false, rules: [], + rulesFiles: [], } for (let i = 2; i < argv.length; i += 1) { @@ -126,7 +134,7 @@ function parseArgs(argv: string[]): Args { ) } } else if (a === '--rules-file') { - args.rulesFile = argv[++i] + args.rulesFiles.push(argv[++i]) } else if (a === '--decrease-baselines') { args.decreaseBaselines = true } else { @@ -134,14 +142,14 @@ function parseArgs(argv: string[]): Args { } } - if (args.rulesFile) { - args.rules.push(...readRulesFile(args.rulesFile)) + for (const rulesFile of args.rulesFiles) { + args.rules.push(...readRulesFile(rulesFile)) } if (args.rules.length === 0) { console.error('Error: You must provide at least one --rule or a --rules-file.') console.error('Example: --rule exhaustive-deps --rule no-console') - console.error('Example: --rules-file scripts/ratchet-rules.json') + console.error('Example: --rules-file node_modules/eslint-config-supabase/ratchet-rules.json') process.exit(2) } @@ -412,7 +420,7 @@ function main(): void { } if (process.argv[1]) { - const invokedPath = pathToFileURL(path.resolve(process.argv[1])).href + const invokedPath = pathToFileURL(realpathSync(path.resolve(process.argv[1]))).href if (import.meta.url === invokedPath) { main() } diff --git a/packages/eslint-config-supabase/ratchet-rules.json b/packages/eslint-config-supabase/ratchet-rules.json new file mode 100644 index 00000000000..648b2f201e1 --- /dev/null +++ b/packages/eslint-config-supabase/ratchet-rules.json @@ -0,0 +1 @@ +["shadcn/no-arbitrary-values", "shadcn/no-unknown-classes", "shadcn/no-raw-colors"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6abd4903100..b75a49659bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2550,9 +2550,15 @@ importers: eslint-config-turbo: specifier: ^2.5.0 version: 2.5.8(eslint@9.37.0(jiti@2.7.0)(supports-color@8.1.1))(turbo@2.9.14) + tsx: + specifier: 'catalog:' + version: 4.22.4 typescript: specifier: 'catalog:' version: 6.0.2 + vitest: + specifier: 'catalog:' + version: 5.0.0(@opentelemetry/api@1.9.1)(@types/node@22.13.14)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.14.5)(jsdom@28.1.0(@noble/hashes@1.8.0)(supports-color@8.1.1))(msw@2.11.3(@types/node@22.13.14)(typescript@6.0.2))(vite@8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) packages/generator: devDependencies: