2026-08-04 23:28:10 +08:00
|
|
|
import path from "node:path";
|
|
|
|
|
import {
|
|
|
|
|
readTextFileIfSmall,
|
|
|
|
|
relative,
|
|
|
|
|
repositoryRoot,
|
|
|
|
|
walkFiles,
|
|
|
|
|
} from "./repository-files.mjs";
|
|
|
|
|
|
2026-08-07 18:00:38 +08:00
|
|
|
const domainRoot = path.join(
|
|
|
|
|
repositoryRoot,
|
|
|
|
|
"app",
|
|
|
|
|
"src",
|
|
|
|
|
"main",
|
|
|
|
|
"java",
|
|
|
|
|
"net",
|
|
|
|
|
"opcapp",
|
|
|
|
|
"flash",
|
|
|
|
|
"domain",
|
|
|
|
|
);
|
2026-08-04 23:28:10 +08:00
|
|
|
const forbiddenImports = [
|
|
|
|
|
/^android\./u,
|
|
|
|
|
/^androidx\./u,
|
|
|
|
|
/^com\.google\.dagger\./u,
|
|
|
|
|
/^dagger\./u,
|
|
|
|
|
/^okhttp3\./u,
|
|
|
|
|
/^retrofit2\./u,
|
|
|
|
|
/^io\.ktor\./u,
|
|
|
|
|
/^androidx\.room\./u,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const failures = [];
|
|
|
|
|
let kotlinFiles = [];
|
|
|
|
|
try {
|
|
|
|
|
kotlinFiles = (await walkFiles(domainRoot)).filter((file) => file.endsWith(".kt"));
|
|
|
|
|
} catch {
|
|
|
|
|
failures.push(`domain source directory is missing: ${relative(domainRoot)}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const file of kotlinFiles) {
|
|
|
|
|
const content = await readTextFileIfSmall(file);
|
|
|
|
|
if (content === null) continue;
|
|
|
|
|
for (const [index, line] of content.split(/\r?\n/u).entries()) {
|
|
|
|
|
const match = /^\s*import\s+([^\s]+)/u.exec(line);
|
|
|
|
|
if (!match) continue;
|
|
|
|
|
if (forbiddenImports.some((pattern) => pattern.test(match[1]))) {
|
|
|
|
|
failures.push(`${relative(file)}:${index + 1} forbidden import ${match[1]}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (failures.length > 0) {
|
|
|
|
|
console.error("Domain boundary verification failed:");
|
|
|
|
|
for (const failure of failures) console.error(`- ${failure}`);
|
|
|
|
|
process.exitCode = 1;
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`Domain boundary verification passed (${kotlinFiles.length} Kotlin files).`);
|
|
|
|
|
}
|