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.
63 lines
2.2 KiB
63 lines
2.2 KiB
|
2 months ago
|
/**
|
||
|
|
* rtl-check — the mechanical guard of the build contract's RTL row
|
||
|
|
* (docs/guides/component-guide.md). Until now that row's guard was
|
||
|
|
* "rule (LIVE)", i.e. human review, and it is how the Slider defect of
|
||
|
|
* `013ceac57` reached production: three vertical rules paired a logical
|
||
|
|
* `inset-inline-start` with a physical `translateX`, and nothing in CI looked
|
||
|
|
* at CSS declarations — `eidos-lint` classifies selectors.
|
||
|
|
*
|
||
|
|
* RTL-1 a physical inline-axis displacement (`transform: translateX/
|
||
|
|
* translate/translate3d`, or the independent `translate` property) in
|
||
|
|
* a block that also anchors on `inset-inline*` / `margin-inline*`.
|
||
|
|
* The anchor flips with the writing direction, the displacement does
|
||
|
|
* not: correct in LTR, a full element-width off-axis in RTL.
|
||
|
|
*
|
||
|
|
* The rule, its deliberate exclusions (block axis, zero X, `padding-inline`)
|
||
|
|
* and the `rtl-physical:` escape hatch live in `src/uix/eidos/rtl-lint.ts`.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
||
|
|
import { join, relative } from 'node:path';
|
||
|
|
|
||
|
|
import { lintRtlGeometry } from '../src/uix/eidos/rtl-lint';
|
||
|
|
|
||
|
|
const REPO = process.cwd();
|
||
|
|
const EIDOS_DIR = join(REPO, 'src', 'uix', 'eidos');
|
||
|
|
|
||
|
|
function walk(dir: string, out: string[] = []): string[] {
|
||
|
|
for (const entry of readdirSync(dir)) {
|
||
|
|
const path = join(dir, entry);
|
||
|
|
if (statSync(path).isDirectory()) walk(path, out);
|
||
|
|
else if (entry.endsWith('.css')) out.push(path);
|
||
|
|
}
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
function main(): void {
|
||
|
|
const files = walk(EIDOS_DIR);
|
||
|
|
let errors = 0;
|
||
|
|
|
||
|
|
for (const file of files) {
|
||
|
|
const rel = relative(REPO, file).replace(/\\/g, '/');
|
||
|
|
for (const f of lintRtlGeometry(readFileSync(file, 'utf8'))) {
|
||
|
|
errors++;
|
||
|
|
console.error(
|
||
|
|
`ERROR [RTL-1] ${rel}:${f.line} — physical "${f.translate}" against logical ` +
|
||
|
|
`${f.anchors.map((a) => `"${a}"`).join(' + ')} in ${f.selector}`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (errors > 0) {
|
||
|
|
console.error(
|
||
|
|
`\nrtl-check: ${errors} error(s) across ${files.length} files\n` +
|
||
|
|
'Express the offset logically (margin-inline-start: calc(…)), go fully physical\n' +
|
||
|
|
'(left/right), or mark the line /* rtl-physical: <reason> */ if the pairing is meant.'
|
||
|
|
);
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
console.log(`rtl-check: 0 error(s) across ${files.length} files`);
|
||
|
|
}
|
||
|
|
|
||
|
|
main();
|