Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/thatstupidcomputer / scripts/check-architecture.mjs |
| Date | Not specified in source |
| Repository | Janady13/thatstupidcomputer |
| Revision | 57555cde46910102dd25d6c1c1fb2c359e9655bd |
| Branch | main |
| Path or archive member | scripts/check-architecture.mjs |
| Original SHA-256 | 875b37cd4f2053c8a16e9d4b7c65fe281944b3d308cb2a1baade18b5df448f6e |
| Git blob SHA | 1afdd5b6c25074d714272d58ecfe54237df10297 |
| Reading-copy SHA-256 | 875b37cd4f2053c8a16e9d4b7c65fe281944b3d308cb2a1baade18b5df448f6e |
Recovered source transcript
Download complete source text ↓91 lines · 5.4 KB
import { readFileSync, existsSync, readdirSync, statSync, realpathSync } from 'node:fs';
import { resolve, relative, dirname, extname } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { builtinModules } from 'node:module';
import { buildSync } from 'esbuild';
const defaultRoot = fileURLToPath(new URL('..', import.meta.url));
const serverModules = new Set([...builtinModules, ...builtinModules.map(name => `node:${name}`), 'fastify', 'nodemailer']);
const code = /\.(?:[cm]?[jt]s|[jt]sx)$/;
const declaration = /\.d\.[cm]?ts$/;
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs', '.cts', '.cjs'];
function files(directory) {
return readdirSync(directory, { withFileTypes: true }).flatMap(entry => entry.isDirectory() ? files(resolve(directory, entry.name)) : code.test(entry.name) && !declaration.test(entry.name) ? [resolve(directory, entry.name)] : []);
}
function localFile(root, from, name) {
name = name.split(/[?#]/, 1)[0];
const stem = name.startsWith('@/') ? resolve(root, 'apps/web/src', name.slice(2)) : name.startsWith('.') ? resolve(dirname(from), name) : null;
if (!stem) return null;
const candidates = [stem];
// Match Vite's explicit JS-output -> TypeScript-source substitutions before
// trying appended extensions, so those spellings cannot hide runtime edges.
const extension = extname(stem);
if (/^\.(?:js|jsx|mjs|cjs)$/.test(extension)) {
const base = stem.slice(0, -extension.length);
candidates.push(base + extension.replace('js', 'ts'));
if (extension === '.js') candidates.push(base + '.tsx');
}
candidates.push(...extensions.map(suffix => stem + suffix), ...extensions.map(suffix => `${stem}/index${suffix}`));
const target = candidates.find(candidate => existsSync(candidate) && statSync(candidate).isFile());
return target ? realpathSync(target) : null;
}
/** Check actual runtime import edges, including lazy imports, without following type-only edges. */
export function auditArchitecture(root = defaultRoot) {
// Import targets are resolved to physical paths; use that same identity for
// the root and graph keys (notably macOS /var -> /private/var aliases).
root = realpathSync(root);
const violations = [];
const visited = new Set();
// The installed transpiler removes type-only imports and reports real static and
// dynamic edges. Nothing is written or executed; this also works with native TS 7.
const result = buildSync({
absWorkingDir: root,
entryPoints: ['apps/web/src', 'apps/api/src', 'packages'].flatMap(directory => files(resolve(root, directory))),
bundle: false, write: false, metafile: true, outdir: '.build/architecture',
platform: 'neutral', format: 'esm', jsx: 'automatic', target: 'es2022', logLevel: 'silent',
});
const edges = new Map(Object.values(result.metafile.outputs).filter(info => info.entryPoint).map(info => [resolve(root, info.entryPoint), info.imports.map(item => item.path)]));
const imports = file => edges.get(file) ?? [];
const visit = file => {
if (visited.has(file)) return;
visited.add(file);
for (const name of imports(file)) {
const owner = relative(root, file);
if (serverModules.has(name) || name.startsWith('node:')) violations.push(`${owner}: server runtime import ${name}`);
const target = localFile(root, file, name);
if (!target) continue;
const path = relative(root, target);
if (/^(?:apps\/api|private|native|scripts|deploy)\//.test(path) || path.startsWith('..')) violations.push(`${owner}: browser imports protected source ${path}`);
else if (path.startsWith('packages/discovery/') && !(/^packages\/discovery\/(?:registry|contract)\.ts$/.test(path)||/^packages\/discovery\/providers\/[^/]+\/profile\.ts$/.test(path))) violations.push(`${owner}: browser imports private discovery integration ${path}`);
else if (code.test(target)) visit(target);
}
};
visit(resolve(root, 'apps/web/src/entry-client.tsx'));
for (const directory of ['apps/web/src/animation', 'apps/api/src', 'packages']) {
for (const file of files(resolve(root, directory))) {
for (const name of imports(file)) {
const target = localFile(root, file, name);
if (!target) continue;
const path = relative(root, target);
if (directory.endsWith('animation') && /^apps\/web\/src\/(?:components|measurement)\//.test(path)) violations.push(`${relative(root, file)}: animation depends on product UI ${path}`);
if (directory !== 'apps/web/src/animation' && path.startsWith('apps/web/src/')) violations.push(`${relative(root, file)}: shared/server source depends on web UI ${path}`);
}
}
}
const css = readFileSync(resolve(root, 'apps/web/src/styles/site.css'), 'utf8');
for (const [, name] of css.matchAll(/@import\s+"(.+)";/g)) {
if (!existsSync(resolve(root, 'apps/web/src/styles', name))) violations.push(`Missing CSS module ${name}`);
}
for (const entry of readdirSync(resolve(root, 'apps/web/public'))) {
if (['private', 'native', 'src', 'tests', 'node_modules', 'deploy'].includes(entry) || entry.startsWith('.')) violations.push(`Forbidden public directory ${entry}`);
}
return { checkedBrowserModules: visited.size, violations };
}
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
const result = auditArchitecture();
console.log(JSON.stringify(result, null, 2));
if (result.violations.length) process.exitCode = 1;
}