From b316481acdb02c4871ab2b37a90f5c5b3713cd25 Mon Sep 17 00:00:00 2001 From: murashit Date: Sat, 27 Jun 2026 22:31:54 +0900 Subject: [PATCH] Organize Biome Grit policy configuration --- biome.jsonc | 60 +++++++++---------- package.json | 2 +- scripts/{lint => }/check-css-usage.mjs | 2 +- ...pp-server-connection-boundary-imports.grit | 0 .../no-app-server-projection-rpcs.grit | 0 ...-app-server-protocol-boundary-imports.grit | 0 .../no-app-server-root-module-imports.grit | 0 .../no-app-server-subfolder-root-imports.grit | 0 ...o-chat-app-server-outer-layer-imports.grit | 0 ...-chat-application-outer-layer-imports.grit | 0 .../no-chat-host-rendering-layer-imports.grit | 0 ...o-chat-panel-runtime-boundary-imports.grit | 0 ...chat-presentation-outer-layer-imports.grit | 0 .../no-chat-ui-outer-layer-imports.grit | 0 .../no-chat-workspace-boundary-imports.grit | 0 .../no-domain-outer-layer-imports.grit | 0 ...no-feature-workspace-boundary-imports.grit | 0 ...generated-app-server-boundary-imports.grit | 0 .../no-lower-level-feature-imports.grit | 0 .../no-preact-signal-imports.grit | 0 ...-settings-app-server-boundary-imports.grit | 0 .../no-state-module-side-effects.grit | 0 .../no-workspace-chat-internal-imports.grit | 0 .../dom}/no-dom-events-imports.grit | 0 .../dom}/no-implicit-dom-bridges.grit | 0 .../dom}/no-ui-root-imports.grit | 0 .../no-restricted-css-policy.grit | 0 .../no-handwritten-reexports.grit | 0 .../source-shape}/no-misplaced-tsx.grit | 0 .../no-responsibility-root-module-files.grit | 0 ...self-referential-initializer-callback.grit | 0 .../no-uncontrolled-preact-form-state.grit | 0 .../no-unsafe-iterator-value.grit | 0 tests/scripts/development-scripts.test.ts | 2 +- tests/scripts/grit-policy.test.mjs | 45 ++++++++++++-- 35 files changed, 74 insertions(+), 37 deletions(-) rename scripts/{lint => }/check-css-usage.mjs (98%) rename scripts/{lint => grit/architecture}/no-app-server-connection-boundary-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-app-server-projection-rpcs.grit (100%) rename scripts/{lint => grit/architecture}/no-app-server-protocol-boundary-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-app-server-root-module-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-app-server-subfolder-root-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-chat-app-server-outer-layer-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-chat-application-outer-layer-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-chat-host-rendering-layer-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-chat-panel-runtime-boundary-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-chat-presentation-outer-layer-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-chat-ui-outer-layer-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-chat-workspace-boundary-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-domain-outer-layer-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-feature-workspace-boundary-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-generated-app-server-boundary-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-lower-level-feature-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-preact-signal-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-settings-app-server-boundary-imports.grit (100%) rename scripts/{lint => grit/architecture}/no-state-module-side-effects.grit (100%) rename scripts/{lint => grit/architecture}/no-workspace-chat-internal-imports.grit (100%) rename scripts/{lint => grit/dom}/no-dom-events-imports.grit (100%) rename scripts/{lint => grit/dom}/no-implicit-dom-bridges.grit (100%) rename scripts/{lint => grit/dom}/no-ui-root-imports.grit (100%) rename scripts/{lint => grit}/no-restricted-css-policy.grit (100%) rename scripts/{lint => grit/source-shape}/no-handwritten-reexports.grit (100%) rename scripts/{lint => grit/source-shape}/no-misplaced-tsx.grit (100%) rename scripts/{lint => grit/source-shape}/no-responsibility-root-module-files.grit (100%) rename scripts/{lint => grit/source-shape}/no-self-referential-initializer-callback.grit (100%) rename scripts/{lint => grit/source-shape}/no-uncontrolled-preact-form-state.grit (100%) rename scripts/{lint => grit/source-shape}/no-unsafe-iterator-value.grit (100%) diff --git a/biome.jsonc b/biome.jsonc index f7b1f7ad..d5e5d604 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -8,7 +8,7 @@ "plugins": [ // Shared source-shape boundaries. { - "path": "./scripts/lint/no-responsibility-root-module-files.grit", + "path": "./scripts/grit/source-shape/no-responsibility-root-module-files.grit", "includes": [ "**/src/app-server/*.ts", "**/src/app-server/*.tsx", @@ -24,93 +24,93 @@ }, // App-server protocol and generated binding boundaries. { - "path": "./scripts/lint/no-app-server-root-module-imports.grit", + "path": "./scripts/grit/architecture/no-app-server-root-module-imports.grit", "includes": ["**/src/**/*.ts", "**/src/**/*.tsx"] }, { - "path": "./scripts/lint/no-app-server-subfolder-root-imports.grit", + "path": "./scripts/grit/architecture/no-app-server-subfolder-root-imports.grit", "includes": ["**/src/app-server/**/*.ts"] }, { - "path": "./scripts/lint/no-app-server-projection-rpcs.grit", + "path": "./scripts/grit/architecture/no-app-server-projection-rpcs.grit", "includes": ["**/src/features/chat/application/**/*.ts"] }, { - "path": "./scripts/lint/no-app-server-protocol-boundary-imports.grit", + "path": "./scripts/grit/architecture/no-app-server-protocol-boundary-imports.grit", "includes": ["**/src/**/*.ts", "**/src/**/*.tsx", "!**/src/app-server/**"] }, { - "path": "./scripts/lint/no-generated-app-server-boundary-imports.grit", + "path": "./scripts/grit/architecture/no-generated-app-server-boundary-imports.grit", "includes": ["**/src/**/*.ts", "**/src/**/*.tsx", "!**/src/app-server/connection/**"] }, { - "path": "./scripts/lint/no-settings-app-server-boundary-imports.grit", + "path": "./scripts/grit/architecture/no-settings-app-server-boundary-imports.grit", "includes": ["**/src/settings/**/*.ts", "**/src/settings/**/*.tsx", "!**/src/settings/app-server/**"] }, // Shared source layering boundaries. { - "path": "./scripts/lint/no-domain-outer-layer-imports.grit", + "path": "./scripts/grit/architecture/no-domain-outer-layer-imports.grit", "includes": ["**/src/domain/**/*.ts", "**/src/features/chat/domain/**/*.ts"] }, { - "path": "./scripts/lint/no-lower-level-feature-imports.grit", + "path": "./scripts/grit/architecture/no-lower-level-feature-imports.grit", "includes": ["**/src/app-server/**/*.ts", "**/src/shared/**/*.ts", "**/src/shared/**/*.tsx"] }, { - "path": "./scripts/lint/no-app-server-connection-boundary-imports.grit", + "path": "./scripts/grit/architecture/no-app-server-connection-boundary-imports.grit", "includes": ["**/src/app-server/protocol/**/*.ts", "**/src/domain/**/*.ts", "**/src/shared/**/*.ts", "**/src/shared/**/*.tsx"] }, // Chat feature architecture. { - "path": "./scripts/lint/no-preact-signal-imports.grit", + "path": "./scripts/grit/architecture/no-preact-signal-imports.grit", "includes": ["**/src/**/*.ts", "**/src/**/*.tsx", "!**/src/features/chat/panel/shell-state.tsx"] }, { - "path": "./scripts/lint/no-state-module-side-effects.grit", + "path": "./scripts/grit/architecture/no-state-module-side-effects.grit", "includes": ["**/src/features/chat/application/state/**/*.ts"] }, { - "path": "./scripts/lint/no-chat-application-outer-layer-imports.grit", + "path": "./scripts/grit/architecture/no-chat-application-outer-layer-imports.grit", "includes": ["**/src/features/chat/application/**/*.ts"] }, { - "path": "./scripts/lint/no-chat-app-server-outer-layer-imports.grit", + "path": "./scripts/grit/architecture/no-chat-app-server-outer-layer-imports.grit", "includes": ["**/src/features/chat/app-server/**/*.ts"] }, { - "path": "./scripts/lint/no-chat-workspace-boundary-imports.grit", + "path": "./scripts/grit/architecture/no-chat-workspace-boundary-imports.grit", "includes": ["**/src/features/chat/**/*.ts", "**/src/features/chat/**/*.tsx"] }, { - "path": "./scripts/lint/no-feature-workspace-boundary-imports.grit", + "path": "./scripts/grit/architecture/no-feature-workspace-boundary-imports.grit", "includes": ["**/src/features/**/*.ts", "**/src/features/**/*.tsx", "!**/src/features/chat/**"] }, { - "path": "./scripts/lint/no-workspace-chat-internal-imports.grit", + "path": "./scripts/grit/architecture/no-workspace-chat-internal-imports.grit", "includes": ["**/src/workspace/**/*.ts"] }, { - "path": "./scripts/lint/no-chat-host-rendering-layer-imports.grit", + "path": "./scripts/grit/architecture/no-chat-host-rendering-layer-imports.grit", "includes": ["**/src/features/chat/host/**/*.ts"] }, { - "path": "./scripts/lint/no-chat-panel-runtime-boundary-imports.grit", + "path": "./scripts/grit/architecture/no-chat-panel-runtime-boundary-imports.grit", "includes": ["**/src/features/chat/panel/**/*.ts", "**/src/features/chat/panel/**/*.tsx"] }, { - "path": "./scripts/lint/no-chat-presentation-outer-layer-imports.grit", + "path": "./scripts/grit/architecture/no-chat-presentation-outer-layer-imports.grit", "includes": ["**/src/features/chat/presentation/**/*.ts"] }, { - "path": "./scripts/lint/no-chat-ui-outer-layer-imports.grit", + "path": "./scripts/grit/architecture/no-chat-ui-outer-layer-imports.grit", "includes": ["**/src/features/chat/ui/**/*.ts", "**/src/features/chat/ui/**/*.tsx"] }, // UI and DOM source boundaries. { - "path": "./scripts/lint/no-implicit-dom-bridges.grit", + "path": "./scripts/grit/dom/no-implicit-dom-bridges.grit", "includes": [ "**/src/**/*.ts", "**/src/**/*.tsx", @@ -123,7 +123,7 @@ ] }, { - "path": "./scripts/lint/no-dom-events-imports.grit", + "path": "./scripts/grit/dom/no-dom-events-imports.grit", "includes": [ "**/src/**/*.ts", "**/src/**/*.tsx", @@ -136,7 +136,7 @@ ] }, { - "path": "./scripts/lint/no-ui-root-imports.grit", + "path": "./scripts/grit/dom/no-ui-root-imports.grit", "includes": [ "**/src/**/*.ts", "**/src/**/*.tsx", @@ -147,13 +147,13 @@ ] }, { - "path": "./scripts/lint/no-uncontrolled-preact-form-state.grit", + "path": "./scripts/grit/source-shape/no-uncontrolled-preact-form-state.grit", "includes": ["**/src/**/*.tsx"] }, // Project-wide source shape. { - "path": "./scripts/lint/no-misplaced-tsx.grit", + "path": "./scripts/grit/source-shape/no-misplaced-tsx.grit", "includes": [ "**/src/**/*.tsx", "!**/src/features/chat/panel/**", @@ -166,21 +166,21 @@ ] }, { - "path": "./scripts/lint/no-handwritten-reexports.grit", + "path": "./scripts/grit/source-shape/no-handwritten-reexports.grit", "includes": ["**/*.ts", "**/*.tsx", "**/*.mjs"] }, { - "path": "./scripts/lint/no-self-referential-initializer-callback.grit", + "path": "./scripts/grit/source-shape/no-self-referential-initializer-callback.grit", "includes": ["**/*.ts", "**/*.tsx", "**/*.mjs"] }, { - "path": "./scripts/lint/no-unsafe-iterator-value.grit", + "path": "./scripts/grit/source-shape/no-unsafe-iterator-value.grit", "includes": ["**/*.ts", "**/*.tsx", "**/*.mjs"] }, // CSS source policy. { - "path": "./scripts/lint/no-restricted-css-policy.grit", + "path": "./scripts/grit/no-restricted-css-policy.grit", "includes": ["**/src/styles/**/*.css"] } ], diff --git a/package.json b/package.json index 768545de..4fc04cec 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build:styles": "node scripts/build-styles.mjs", "check": "concurrently --group --pad-prefix 'node:check:*' && node --run build", "check:biome": "biome check --diagnostic-level=warn --error-on-warnings", - "check:css-usage": "node scripts/lint/check-css-usage.mjs", + "check:css-usage": "node scripts/check-css-usage.mjs", "check:eslint": "eslint src manifest.json LICENSE --max-warnings=0", "check:test": "node --run test", "check:typecheck": "node --run typecheck", diff --git a/scripts/lint/check-css-usage.mjs b/scripts/check-css-usage.mjs similarity index 98% rename from scripts/lint/check-css-usage.mjs rename to scripts/check-css-usage.mjs index a453a895..125386ed 100644 --- a/scripts/lint/check-css-usage.mjs +++ b/scripts/check-css-usage.mjs @@ -4,7 +4,7 @@ import path from "node:path"; const root = process.cwd(); const stylesDir = path.join(root, "src", "styles"); if (process.argv.length > 2) { - console.error("Usage: node scripts/lint/check-css-usage.mjs"); + console.error("Usage: node scripts/check-css-usage.mjs"); process.exit(1); } diff --git a/scripts/lint/no-app-server-connection-boundary-imports.grit b/scripts/grit/architecture/no-app-server-connection-boundary-imports.grit similarity index 100% rename from scripts/lint/no-app-server-connection-boundary-imports.grit rename to scripts/grit/architecture/no-app-server-connection-boundary-imports.grit diff --git a/scripts/lint/no-app-server-projection-rpcs.grit b/scripts/grit/architecture/no-app-server-projection-rpcs.grit similarity index 100% rename from scripts/lint/no-app-server-projection-rpcs.grit rename to scripts/grit/architecture/no-app-server-projection-rpcs.grit diff --git a/scripts/lint/no-app-server-protocol-boundary-imports.grit b/scripts/grit/architecture/no-app-server-protocol-boundary-imports.grit similarity index 100% rename from scripts/lint/no-app-server-protocol-boundary-imports.grit rename to scripts/grit/architecture/no-app-server-protocol-boundary-imports.grit diff --git a/scripts/lint/no-app-server-root-module-imports.grit b/scripts/grit/architecture/no-app-server-root-module-imports.grit similarity index 100% rename from scripts/lint/no-app-server-root-module-imports.grit rename to scripts/grit/architecture/no-app-server-root-module-imports.grit diff --git a/scripts/lint/no-app-server-subfolder-root-imports.grit b/scripts/grit/architecture/no-app-server-subfolder-root-imports.grit similarity index 100% rename from scripts/lint/no-app-server-subfolder-root-imports.grit rename to scripts/grit/architecture/no-app-server-subfolder-root-imports.grit diff --git a/scripts/lint/no-chat-app-server-outer-layer-imports.grit b/scripts/grit/architecture/no-chat-app-server-outer-layer-imports.grit similarity index 100% rename from scripts/lint/no-chat-app-server-outer-layer-imports.grit rename to scripts/grit/architecture/no-chat-app-server-outer-layer-imports.grit diff --git a/scripts/lint/no-chat-application-outer-layer-imports.grit b/scripts/grit/architecture/no-chat-application-outer-layer-imports.grit similarity index 100% rename from scripts/lint/no-chat-application-outer-layer-imports.grit rename to scripts/grit/architecture/no-chat-application-outer-layer-imports.grit diff --git a/scripts/lint/no-chat-host-rendering-layer-imports.grit b/scripts/grit/architecture/no-chat-host-rendering-layer-imports.grit similarity index 100% rename from scripts/lint/no-chat-host-rendering-layer-imports.grit rename to scripts/grit/architecture/no-chat-host-rendering-layer-imports.grit diff --git a/scripts/lint/no-chat-panel-runtime-boundary-imports.grit b/scripts/grit/architecture/no-chat-panel-runtime-boundary-imports.grit similarity index 100% rename from scripts/lint/no-chat-panel-runtime-boundary-imports.grit rename to scripts/grit/architecture/no-chat-panel-runtime-boundary-imports.grit diff --git a/scripts/lint/no-chat-presentation-outer-layer-imports.grit b/scripts/grit/architecture/no-chat-presentation-outer-layer-imports.grit similarity index 100% rename from scripts/lint/no-chat-presentation-outer-layer-imports.grit rename to scripts/grit/architecture/no-chat-presentation-outer-layer-imports.grit diff --git a/scripts/lint/no-chat-ui-outer-layer-imports.grit b/scripts/grit/architecture/no-chat-ui-outer-layer-imports.grit similarity index 100% rename from scripts/lint/no-chat-ui-outer-layer-imports.grit rename to scripts/grit/architecture/no-chat-ui-outer-layer-imports.grit diff --git a/scripts/lint/no-chat-workspace-boundary-imports.grit b/scripts/grit/architecture/no-chat-workspace-boundary-imports.grit similarity index 100% rename from scripts/lint/no-chat-workspace-boundary-imports.grit rename to scripts/grit/architecture/no-chat-workspace-boundary-imports.grit diff --git a/scripts/lint/no-domain-outer-layer-imports.grit b/scripts/grit/architecture/no-domain-outer-layer-imports.grit similarity index 100% rename from scripts/lint/no-domain-outer-layer-imports.grit rename to scripts/grit/architecture/no-domain-outer-layer-imports.grit diff --git a/scripts/lint/no-feature-workspace-boundary-imports.grit b/scripts/grit/architecture/no-feature-workspace-boundary-imports.grit similarity index 100% rename from scripts/lint/no-feature-workspace-boundary-imports.grit rename to scripts/grit/architecture/no-feature-workspace-boundary-imports.grit diff --git a/scripts/lint/no-generated-app-server-boundary-imports.grit b/scripts/grit/architecture/no-generated-app-server-boundary-imports.grit similarity index 100% rename from scripts/lint/no-generated-app-server-boundary-imports.grit rename to scripts/grit/architecture/no-generated-app-server-boundary-imports.grit diff --git a/scripts/lint/no-lower-level-feature-imports.grit b/scripts/grit/architecture/no-lower-level-feature-imports.grit similarity index 100% rename from scripts/lint/no-lower-level-feature-imports.grit rename to scripts/grit/architecture/no-lower-level-feature-imports.grit diff --git a/scripts/lint/no-preact-signal-imports.grit b/scripts/grit/architecture/no-preact-signal-imports.grit similarity index 100% rename from scripts/lint/no-preact-signal-imports.grit rename to scripts/grit/architecture/no-preact-signal-imports.grit diff --git a/scripts/lint/no-settings-app-server-boundary-imports.grit b/scripts/grit/architecture/no-settings-app-server-boundary-imports.grit similarity index 100% rename from scripts/lint/no-settings-app-server-boundary-imports.grit rename to scripts/grit/architecture/no-settings-app-server-boundary-imports.grit diff --git a/scripts/lint/no-state-module-side-effects.grit b/scripts/grit/architecture/no-state-module-side-effects.grit similarity index 100% rename from scripts/lint/no-state-module-side-effects.grit rename to scripts/grit/architecture/no-state-module-side-effects.grit diff --git a/scripts/lint/no-workspace-chat-internal-imports.grit b/scripts/grit/architecture/no-workspace-chat-internal-imports.grit similarity index 100% rename from scripts/lint/no-workspace-chat-internal-imports.grit rename to scripts/grit/architecture/no-workspace-chat-internal-imports.grit diff --git a/scripts/lint/no-dom-events-imports.grit b/scripts/grit/dom/no-dom-events-imports.grit similarity index 100% rename from scripts/lint/no-dom-events-imports.grit rename to scripts/grit/dom/no-dom-events-imports.grit diff --git a/scripts/lint/no-implicit-dom-bridges.grit b/scripts/grit/dom/no-implicit-dom-bridges.grit similarity index 100% rename from scripts/lint/no-implicit-dom-bridges.grit rename to scripts/grit/dom/no-implicit-dom-bridges.grit diff --git a/scripts/lint/no-ui-root-imports.grit b/scripts/grit/dom/no-ui-root-imports.grit similarity index 100% rename from scripts/lint/no-ui-root-imports.grit rename to scripts/grit/dom/no-ui-root-imports.grit diff --git a/scripts/lint/no-restricted-css-policy.grit b/scripts/grit/no-restricted-css-policy.grit similarity index 100% rename from scripts/lint/no-restricted-css-policy.grit rename to scripts/grit/no-restricted-css-policy.grit diff --git a/scripts/lint/no-handwritten-reexports.grit b/scripts/grit/source-shape/no-handwritten-reexports.grit similarity index 100% rename from scripts/lint/no-handwritten-reexports.grit rename to scripts/grit/source-shape/no-handwritten-reexports.grit diff --git a/scripts/lint/no-misplaced-tsx.grit b/scripts/grit/source-shape/no-misplaced-tsx.grit similarity index 100% rename from scripts/lint/no-misplaced-tsx.grit rename to scripts/grit/source-shape/no-misplaced-tsx.grit diff --git a/scripts/lint/no-responsibility-root-module-files.grit b/scripts/grit/source-shape/no-responsibility-root-module-files.grit similarity index 100% rename from scripts/lint/no-responsibility-root-module-files.grit rename to scripts/grit/source-shape/no-responsibility-root-module-files.grit diff --git a/scripts/lint/no-self-referential-initializer-callback.grit b/scripts/grit/source-shape/no-self-referential-initializer-callback.grit similarity index 100% rename from scripts/lint/no-self-referential-initializer-callback.grit rename to scripts/grit/source-shape/no-self-referential-initializer-callback.grit diff --git a/scripts/lint/no-uncontrolled-preact-form-state.grit b/scripts/grit/source-shape/no-uncontrolled-preact-form-state.grit similarity index 100% rename from scripts/lint/no-uncontrolled-preact-form-state.grit rename to scripts/grit/source-shape/no-uncontrolled-preact-form-state.grit diff --git a/scripts/lint/no-unsafe-iterator-value.grit b/scripts/grit/source-shape/no-unsafe-iterator-value.grit similarity index 100% rename from scripts/lint/no-unsafe-iterator-value.grit rename to scripts/grit/source-shape/no-unsafe-iterator-value.grit diff --git a/tests/scripts/development-scripts.test.ts b/tests/scripts/development-scripts.test.ts index 1d639f2d..9dbe9aa2 100644 --- a/tests/scripts/development-scripts.test.ts +++ b/tests/scripts/development-scripts.test.ts @@ -123,7 +123,7 @@ describe("development scripts", () => { "tests/component.test.ts": 'expect("codex-panel__test-only").toBeTruthy();\n', }); - const result = runNodeScript("scripts/lint/check-css-usage.mjs", [], cwd); + const result = runNodeScript("scripts/check-css-usage.mjs", [], cwd); expect(result.status).toBe(1); expect(result.stdout).toBe(""); diff --git a/tests/scripts/grit-policy.test.mjs b/tests/scripts/grit-policy.test.mjs index 8c893254..cff62d4f 100644 --- a/tests/scripts/grit-policy.test.mjs +++ b/tests/scripts/grit-policy.test.mjs @@ -1,15 +1,17 @@ import { spawnSync } from "node:child_process"; import { readFileSync } from "node:fs"; -import { mkdir, mkdtemp, writeFile } from "node:fs/promises"; +import { mkdir, mkdtemp, readdir, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; const repoRoot = process.cwd(); const biomeBin = path.join(repoRoot, "node_modules", ".bin", "biome"); +const projectBiomeConfig = parseJsonc(readFileSync(path.join(repoRoot, "biome.jsonc"), "utf8")); +const projectPluginEntries = projectBiomeConfig.plugins; const projectPluginByName = new Map( - parseJsonc(readFileSync(path.join(repoRoot, "biome.jsonc"), "utf8")).plugins.map((plugin) => { - const pluginPath = typeof plugin === "string" ? plugin : plugin.path; + projectPluginEntries.map((plugin) => { + const pluginPath = projectPluginPath(plugin); return [path.basename(pluginPath), plugin]; }), ); @@ -45,6 +47,20 @@ let appServerBoundaryPolicyReportPromise; let renderingAndCssPolicyReportPromise; describe.concurrent("GritQL source policy", () => { + it("keeps Biome wired to every checked-in Grit policy", async () => { + const gritPolicyPaths = await listRelativeGritPolicyPaths(path.join(repoRoot, "scripts/grit")); + const configuredGritPluginPaths = projectPluginEntries + .map((plugin) => projectPluginPath(plugin)) + .filter((pluginPath) => pluginPath.endsWith(".grit")) + .map(normalizeProjectRelativePath) + .sort(); + const configuredGritPluginNames = configuredGritPluginPaths.map((pluginPath) => path.basename(pluginPath)); + + expect(new Set(configuredGritPluginPaths).size).toBe(configuredGritPluginPaths.length); + expect(new Set(configuredGritPluginNames).size).toBe(configuredGritPluginNames.length); + expect(configuredGritPluginPaths).toEqual(gritPolicyPaths); + }); + it("keeps project-wide source-shape policies enforceable as Biome plugin diagnostics", async () => { const cwd = await tempBiomeWorkspace([ "no-handwritten-reexports.grit", @@ -1458,13 +1474,17 @@ function projectPluginConfig(plugin) { if (!projectPlugin) { throw new Error(`Missing ${plugin} in biome.jsonc plugins`); } - const pluginPath = path.join(repoRoot, "scripts", "lint", plugin); + const pluginPath = path.resolve(repoRoot, projectPluginPath(projectPlugin)); if (typeof projectPlugin === "string") { return pluginPath; } return { ...projectPlugin, path: pluginPath }; } +function projectPluginPath(plugin) { + return typeof plugin === "string" ? plugin : plugin.path; +} + function pluginDiagnostics(report, filePath) { return report.diagnostics .filter((diagnostic) => diagnostic.category === "plugin" && diagnosticMatchesFile(report, diagnostic, filePath)) @@ -1497,6 +1517,23 @@ function normalizeRelativePath(filePath) { return filePath.split(path.sep).join("/"); } +function normalizeProjectRelativePath(filePath) { + return normalizeRelativePath(filePath).replace(/^\.\//, ""); +} + +async function listRelativeGritPolicyPaths(directory) { + const entries = await readdir(directory, { withFileTypes: true }); + const paths = await Promise.all( + entries.map(async (entry) => { + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) return listRelativeGritPolicyPaths(entryPath); + if (entry.isFile() && entry.name.endsWith(".grit")) return [normalizeRelativePath(path.relative(repoRoot, entryPath))]; + return []; + }), + ); + return paths.flat().sort(); +} + function parseBiomeJsonReport(stdout, stderr) { const jsonStart = stdout.indexOf("{"); if (jsonStart === -1) {