You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/scripts/eidos-lint.ts

79 lines
2.8 KiB

/**
* Lint an eidos component CSS against its morfo contract.
*
* Usage: npx tsx scripts/eidos-lint.ts <component-kebab>
* e.g. npx tsx scripts/eidos-lint.ts toggle
*
* Reads `src/uix/morfo/components/{name}.ts` +
* `src/uix/eidos/components/{name}/{name}.css` (or legacy flat
* `components/{name}.css`), compiles the morfo, and reports which
* selectors are morfo-backed, eidos-only DOM signals/wrapper attrs, or
* invalid (value not in declared enum).
*
* Also validates the `data-event*` VALUES against the morfo catalogue and
* the sema canon — see `scripts/eidos-event-vocabulary.ts`.
*/
import { readFileSync, existsSync } from 'node:fs';
import { resolve } from 'node:path';
import { compileMorfo } from '../src/uix/morfo/compile';
import { formatLintReport, lintEidosCss } from '../src/uix/eidos/lint';
import type { Morfo } from '../src/uix/morfo/types';
import {
formatEventFindings,
lintEventValues,
loadEventVocabulary
} from './eidos-event-vocabulary';
async function main() {
const name = process.argv[2];
if (!name) {
console.error('Usage: tsx scripts/eidos-lint.ts <component-kebab>');
process.exit(2);
}
const morfoPath = resolve(`src/uix/morfo/components/${name}.ts`);
const subfolderCssPath = resolve(`src/uix/eidos/components/${name}/${name}.css`);
const flatCssPath = resolve(`src/uix/eidos/components/${name}.css`);
const cssPath = existsSync(subfolderCssPath) ? subfolderCssPath : flatCssPath;
if (!existsSync(morfoPath)) {
console.error(`No morfo file at ${morfoPath}`);
process.exit(2);
}
if (!existsSync(cssPath)) {
console.error(`No eidos CSS at ${subfolderCssPath} or ${flatCssPath}`);
process.exit(2);
}
const mod = (await import(`../src/uix/morfo/components/${name}`)) as Record<string, unknown>;
const morfoExportName = `${name.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase())}Morfo`;
const morfo = mod[morfoExportName] as Morfo | undefined;
if (!morfo) {
console.error(`Module exports ${Object.keys(mod).join(', ')}; expected ${morfoExportName}.`);
process.exit(2);
}
const compiled = compileMorfo(morfo);
const css = readFileSync(cssPath, 'utf-8');
const report = lintEidosCss(css, compiled);
console.log(formatLintReport(report));
// The structural report allowlists `data-event*` as eidos-only and never
// reads its value — the vocabulary is checked separately.
const eventFindings = lintEventValues(css, await loadEventVocabulary(), name);
if (eventFindings.length) {
console.log('');
console.log(' data-event* vocabulary (value must exist in a morfo / the canon):');
console.log(formatEventFindings(eventFindings, ' '));
}
const deadEvents = eventFindings.filter((f) => f.level === 'error').length;
if (report.counts.invalid > 0 || deadEvents > 0) process.exit(1);
}
main().catch((err) => {
console.error(err);
process.exit(2);
});

Powered by TurnKey Linux.