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.
132 lines
3.7 KiB
132 lines
3.7 KiB
#!/usr/bin/env node
|
|
/**
|
|
* Fail-loud check for stale ecosystem aliases and old `App.<Capitalized>`
|
|
* references in `src/`. The point is to keep documentation honest after
|
|
* the rename to full-word aliases (`$cache` / `$session` / etc.) and
|
|
* the move from capitalized service slots (`App.Cache`) to lowercase
|
|
* declarable services (`App.cache`).
|
|
*
|
|
* Allowed capitalised names on `App.*` are the ecosystem core:
|
|
* `Logger`, `Bus`, `Timers`, `Orca`. Everything else is lowercase.
|
|
*
|
|
* Run: `node scripts/check-aliases.mjs`
|
|
* Exit code: 0 when clean, 1 when any forbidden token is found.
|
|
*/
|
|
|
|
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
import { join, relative, sep } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const HERE = fileURLToPath(new URL('.', import.meta.url));
|
|
const ROOT = join(HERE, '..');
|
|
const SRC = join(ROOT, 'src');
|
|
|
|
const STALE_ALIAS_PATTERNS = [
|
|
{ rx: /\$cach[^e]/g, hint: '$cach* → $cache*' },
|
|
{ rx: /\$sess[^i]/g, hint: '$sess* → $session*' },
|
|
{ rx: /\$conn[^e]/g, hint: '$conn* → $connection*' },
|
|
{ rx: /\$timr\b/g, hint: '$timr → $timer' },
|
|
{ rx: /\$logr\b/g, hint: '$logr → $logger' },
|
|
{ rx: /\$fmts\b/g, hint: '$fmts → $format' },
|
|
{ rx: /\$stor[^a]/g, hint: '$stor* → $storage*' },
|
|
{ rx: /\$aapp\b/g, hint: '$aapp → $active-app' },
|
|
{ rx: /\$buss\b/g, hint: '$buss → $bus' },
|
|
{ rx: /\$libs\/buss\b/g, hint: '$libs/buss → $libs/bus' },
|
|
{ rx: /\$libs\/logr\b/g, hint: '$libs/logr → $libs/logger' },
|
|
{ rx: /\$libs\/timr\b/g, hint: '$libs/timr → $libs/timer' },
|
|
{ rx: /\$libs\/cach[^e]/g, hint: '$libs/cach* → $libs/cache*' }
|
|
];
|
|
|
|
const APP_FORBIDDEN_CAPITALS = [
|
|
'Cache',
|
|
'Sess',
|
|
'Sium',
|
|
'Storage',
|
|
'Format',
|
|
'Frontend',
|
|
'Lang',
|
|
'Auth',
|
|
'Perms',
|
|
'Http',
|
|
'Dom'
|
|
];
|
|
const APP_PATTERN = new RegExp(`\\bApp\\.(${APP_FORBIDDEN_CAPITALS.join('|')})\\b`, 'g');
|
|
|
|
const SKIP_DIRS = new Set(['node_modules', '.svelte-kit', '.git', 'build', 'dist']);
|
|
const SCAN_EXTENSIONS = new Set([
|
|
'.ts',
|
|
'.svelte',
|
|
'.svelte.ts',
|
|
'.js',
|
|
'.mjs',
|
|
'.md',
|
|
'.txt'
|
|
]);
|
|
|
|
/** Files where the references are deliberately historical. */
|
|
const ALLOWLIST = new Set([
|
|
join('arts', 'active-app', 'types.ts').replaceAll('/', sep)
|
|
]);
|
|
|
|
function* walk(dir) {
|
|
for (const entry of readdirSync(dir)) {
|
|
if (SKIP_DIRS.has(entry)) continue;
|
|
const full = join(dir, entry);
|
|
const st = statSync(full);
|
|
if (st.isDirectory()) {
|
|
yield* walk(full);
|
|
continue;
|
|
}
|
|
if (!st.isFile()) continue;
|
|
const lower = entry.toLowerCase();
|
|
if (!Array.from(SCAN_EXTENSIONS).some((ext) => lower.endsWith(ext))) continue;
|
|
yield full;
|
|
}
|
|
}
|
|
|
|
function scanFile(file) {
|
|
const text = readFileSync(file, 'utf8');
|
|
const findings = [];
|
|
for (const { rx, hint } of STALE_ALIAS_PATTERNS) {
|
|
rx.lastIndex = 0;
|
|
const matches = text.match(rx);
|
|
if (matches) findings.push({ kind: 'alias', hint, count: matches.length });
|
|
}
|
|
APP_PATTERN.lastIndex = 0;
|
|
const appMatches = text.match(APP_PATTERN);
|
|
if (appMatches) {
|
|
findings.push({
|
|
kind: 'app',
|
|
hint: `App.<lowercase> required for non-core services (${[...new Set(appMatches)].join(', ')})`,
|
|
count: appMatches.length
|
|
});
|
|
}
|
|
return findings;
|
|
}
|
|
|
|
let exit = 0;
|
|
const offenders = [];
|
|
for (const file of walk(SRC)) {
|
|
const rel = relative(SRC, file);
|
|
if (ALLOWLIST.has(rel)) continue;
|
|
const findings = scanFile(file);
|
|
if (findings.length === 0) continue;
|
|
offenders.push({ rel, findings });
|
|
exit = 1;
|
|
}
|
|
|
|
if (offenders.length === 0) {
|
|
console.log('aliases: clean');
|
|
} else {
|
|
console.log('aliases: found stale references');
|
|
for (const { rel, findings } of offenders) {
|
|
console.log(` ${rel}`);
|
|
for (const f of findings) console.log(` - ${f.hint} (x${f.count})`);
|
|
}
|
|
console.log(
|
|
'\nFix: run a search/replace using the canonical aliases in svelte.config.js'
|
|
);
|
|
}
|
|
|
|
process.exit(exit);
|