fix(client): lint:layers holds src/types.ts to the rules of types

A file's layer was the first path segment under src/, so src/types.ts,
the shared types module every layer imports as '../types', got the
layer "types.ts" and no rule at all, while the imports into it already
resolved to "types". It could import a component or a page unnoticed.
A file directly in src/ is now the layer of its name without the
extension, for the importer and the import alike. No file changes its
count: types.ts imports only @trek/shared today.
This commit is contained in:
Maurice
2026-10-08 12:50:33 +02:00
parent 6a6f3f6cf6
commit 3e37dcfb45
4 changed files with 38 additions and 8 deletions
+20 -1
View File
@@ -1,7 +1,7 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { importsOf, layerOf } from '../../../scripts/lib/imports.mjs';
import { importsOf, layerOf, layerOfPath } from '../../../scripts/lib/imports.mjs';
import { check, RULES, violations } from '../../../scripts/lib/layers.mjs';
import { RatchetError } from '../../../scripts/lib/ratchet.mjs';
import { ratchetTree, type RatchetTree } from '../../helpers/ratchetFixture';
@@ -57,6 +57,16 @@ describe('scripts/lib/imports', () => {
expect(layerOf(src, from, 'react')).toBeNull();
expect(layerOf(src, from, '../../../../shared/src')).toBeNull();
});
it('IMPORTS-003: a file directly in src/ is the layer of its name without the extension', () => {
expect(layerOfPath('types.ts')).toBe('types');
expect(layerOfPath('App.tsx')).toBe('App');
expect(layerOfPath('vite-env.d.ts')).toBe('vite-env');
expect(layerOfPath('types/tz-lookup.d.ts')).toBe('types');
expect(layerOfPath('components/Map/MapView.tsx')).toBe('components');
const src = join('/r', 'src');
expect(layerOf(src, join(src, 'App.tsx'), './types.ts')).toBe('types');
});
});
describe('lint:layers', () => {
@@ -125,6 +135,15 @@ describe('lint:layers', () => {
expect(tree.error.join('\n')).toMatch(/src\/vacay\/yearWindow\.ts: 1 import\(s\) against the layering/);
});
it('LAYERS-008: src/types.ts is held to the rules of types and imports no view', () => {
const files = {
'src/types.ts': "import type { Props } from './components/Map/MapView'\nimport type { T } from '@trek/shared'\n",
};
expect(run({}, files)).toBe(1);
expect(tree.error.join('\n')).toMatch(/src\/types\.ts: 1 import\(s\) against the layering/);
expect(tree.error.join('\n')).toMatch(/\(types into components\)/);
});
it('LAYERS-006: a missing baseline stops the check', () => {
tree = ratchetTree({ 'src/a.ts': '' });
expect(() => check({ root: tree.root, baselinePath: tree.path(BASELINE), ...tree.out })).toThrow(RatchetError);