mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Organize Biome Grit policy configuration
This commit is contained in:
parent
f068607509
commit
b316481acd
35 changed files with 74 additions and 37 deletions
60
biome.jsonc
60
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"]
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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("");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue