import { readdirSync, readFileSync } from 'node:fs' import { relative, resolve } from 'node:path' import { describe, expect, it } from 'vitest' const sourceRoot = resolve(process.cwd(), 'src') function sourceFiles(directory: string): string[] { return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { const path = resolve(directory, entry.name) if (entry.isDirectory()) return sourceFiles(path) return /\.(ts|vue)$/.test(entry.name) ? [path] : [] }) } function aliasImports(path: string): string[] { const source = readFileSync(path, 'utf8') return [...source.matchAll(/['"](@\/[^'"]+)['"]/g)].map((match) => match[1]) } describe('source dependency boundaries', () => { it('keeps app, core, modules and shared dependencies pointing inward', () => { const violations: string[] = [] for (const path of sourceFiles(sourceRoot)) { const sourcePath = relative(sourceRoot, path).replaceAll('\\', '/') const sourceModule = sourcePath.match(/^modules\/([^/]+)\//)?.[1] for (const dependency of aliasImports(path)) { if (sourcePath.startsWith('shared/') && /^@\/(app|core|modules|prototype)\//.test(dependency)) { violations.push(`${sourcePath} -> ${dependency}`) } if (sourcePath.startsWith('core/') && /^@\/(app|modules|prototype)\//.test(dependency)) { violations.push(`${sourcePath} -> ${dependency}`) } if (sourceModule && /^@\/(app|prototype)\//.test(dependency)) { violations.push(`${sourcePath} -> ${dependency}`) } const targetModule = dependency.match(/^@\/modules\/([^/]+)(\/.*)?$/) if (sourceModule && targetModule && targetModule[1] !== sourceModule && targetModule[2]) { violations.push(`${sourcePath} -> ${dependency}`) } } } expect(violations).toEqual([]) }) })