64 lines
2.9 KiB
TypeScript
64 lines
2.9 KiB
TypeScript
import { dirname, join, resolve } from 'node:path';
|
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
import { beforeAll, describe, expect, it } from 'vitest';
|
|
|
|
// The Core guard's area table (AGENTS.md, "Core Engine and engines"): engine paths come before the
|
|
// Core areas, an unregistered source path stays Core, and a bare folder name belongs to the prefix
|
|
// it names, so renaming a whole engine folder is not mistaken for a Core change.
|
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
|
|
interface AreaTable {
|
|
classifyPath(relative: string | null): string | null;
|
|
relativeToProject(filePath: string, projectDir: string): string | null;
|
|
resolveAreaName(raw: string): string | null;
|
|
isReleased(area: string, releasedAreas: string[]): boolean;
|
|
}
|
|
let areas: AreaTable;
|
|
beforeAll(async () => {
|
|
areas = await import(/* @vite-ignore */ pathToFileURL(join(root, '.claude', 'hooks', 'core-areas.mjs')).href) as AreaTable;
|
|
});
|
|
|
|
describe('Core guard area table', () => {
|
|
it.each([
|
|
'src/compliance', 'src/compliance/', 'src/compliance/ui/regulatorymappingpanel.tsx',
|
|
'server/compliance', 'tests/compliance', 'src/assessment-context', 'src/reporting', 'server/reporting'
|
|
])('treats engine path %s as engine code', path => {
|
|
expect(areas.classifyPath(path)).toBeNull();
|
|
});
|
|
|
|
it.each([
|
|
['src/compliance-x', 'Unclassified Source'],
|
|
['src/compliance-x/file.ts', 'Unclassified Source'],
|
|
['src/newthing', 'Unclassified Source'],
|
|
['src/persistence', 'Store'],
|
|
['src/persistence/local-assessor-repository.ts', 'Store'],
|
|
['server/postgres', 'Store'],
|
|
['src/app', 'Presentation'],
|
|
['src/features/finding-reader/findingreader.tsx', 'Presentation'],
|
|
['server/index.ts', 'Platform'],
|
|
['tests/architecture/core-areas.test.ts', 'Core Tests'],
|
|
['agents.md', 'Governance'],
|
|
['.claude/hooks', 'Governance'],
|
|
['src/domain/review.ts', 'Client Records']
|
|
])('keeps %s in Core area %s', (path, area) => {
|
|
expect(areas.classifyPath(path)).toBe(area);
|
|
});
|
|
|
|
it('leaves paths outside the project and documentation unguarded', () => {
|
|
expect(areas.classifyPath(null)).toBeNull();
|
|
expect(areas.relativeToProject(join(root, '..', 'elsewhere.ts'), root)).toBeNull();
|
|
expect(areas.classifyPath('docs/implementation_plan.md')).toBeNull();
|
|
expect(areas.relativeToProject(join(root, 'src', 'Compliance', 'X.ts'), root)).toBe('src/compliance/x.ts');
|
|
});
|
|
|
|
it('resolves release names and never lets "alle" cover Governance', () => {
|
|
expect(areas.resolveAreaName(' Core Tests ')).toBe('Core Tests');
|
|
expect(areas.resolveAreaName('unclassified source')).toBe('Unclassified Source');
|
|
expect(areas.resolveAreaName('compliance')).toBeNull();
|
|
expect(areas.isReleased('Store', ['alle'])).toBe(true);
|
|
expect(areas.isReleased('Governance', ['alle'])).toBe(false);
|
|
expect(areas.isReleased('Governance', ['Governance'])).toBe(true);
|
|
expect(areas.isReleased('Store', ['Platform'])).toBe(false);
|
|
});
|
|
});
|