ci / module boundaries / boundaries (push) Successful in 6s
ci / api / api (push) Successful in 47s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m2s
ci / db / db (push) Successful in 1m4s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m30s
ci / ts / ts (packages + web) (push) Successful in 2m54s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m14s
48 lines
1.9 KiB
JavaScript
48 lines
1.9 KiB
JavaScript
import { readdirSync, readFileSync } from 'node:fs';
|
|
import { resolve, relative } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const root = fileURLToPath(new URL('../', import.meta.url));
|
|
function sources(dir, extension) {
|
|
return readdirSync(resolve(root, dir), { withFileTypes: true }).flatMap((entry) => {
|
|
const path = `${dir}/${entry.name}`;
|
|
return entry.isDirectory() ? sources(path, extension) : path.endsWith(extension) ? [path] : [];
|
|
});
|
|
}
|
|
|
|
// Check the boundaries introduced by the refactor. Existing query projections and
|
|
// composition roots are deliberately outside these use-case-specific rules.
|
|
const rules = [
|
|
{
|
|
files: sources('packages/core/src', '.ts'),
|
|
forbidden: /(?:from\s*|import\s*)['"](?:[^'"]*apps\/|(?:@react-native[^'"]*|react(?:-native)?(?:[-\/]|['"]))|expo(?:[-\/]|['"])|\.\.[^'"]*(?:web|mobile|desktop)\/)/,
|
|
message: 'core must not import platform/UI implementations',
|
|
},
|
|
{
|
|
files: ['service.go', 'worker.go', 'placement.go', 'batch.go'].map((p) => `services/api/internal/uploads/${p}`),
|
|
forbidden: /github\.com\/jackc\/pgx|\.store\.pool\b|\b(?:tx|pool)\.(?:Exec|Query|QueryRow)\(/,
|
|
message: 'upload SQL and pgx belong in store/persistence adapters',
|
|
},
|
|
{
|
|
files: sources('apps/web/src/features/uploads', '.tsx').filter((p) => !p.endsWith('/common.tsx')),
|
|
forbidden: /\b(?:session|client)\.(?:GET|POST|PUT|PATCH|DELETE)\(/,
|
|
message: 'upload views must use feature API/queries',
|
|
},
|
|
];
|
|
|
|
const errors = [];
|
|
for (const rule of rules) {
|
|
for (const path of rule.files) {
|
|
const text = readFileSync(resolve(root, path), 'utf8');
|
|
text.split(/\r?\n/).forEach((line, i) => {
|
|
if (rule.forbidden.test(line)) errors.push(`${relative(root, resolve(root, path))}:${i + 1}: ${rule.message}`);
|
|
});
|
|
}
|
|
}
|
|
if (errors.length) {
|
|
console.error(errors.join('\n'));
|
|
process.exitCode = 1;
|
|
} else {
|
|
console.log('Module boundary checks passed.');
|
|
}
|