95 lines
3.9 KiB
JavaScript
95 lines
3.9 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import assert from "node:assert/strict";
|
|
import { describe, it } from "vitest";
|
|
|
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
const rootDir = path.resolve(scriptDir, "..");
|
|
const eslintConfig = JSON.parse(fs.readFileSync(path.join(rootDir, ".eslintrc"), "utf8"));
|
|
|
|
function findRestrictedImportRules(config) {
|
|
const rules = [];
|
|
|
|
if (config.rules?.["no-restricted-imports"]) {
|
|
rules.push({ files: ["<root>"], rule: config.rules["no-restricted-imports"] });
|
|
}
|
|
|
|
for (const override of config.overrides ?? []) {
|
|
if (override.rules?.["no-restricted-imports"]) {
|
|
rules.push({ files: override.files ?? [], rule: override.rules["no-restricted-imports"] });
|
|
}
|
|
}
|
|
|
|
return rules;
|
|
}
|
|
|
|
function collectRestrictedPatterns(rule) {
|
|
const options = Array.isArray(rule) ? rule.slice(1) : [];
|
|
const patterns = [];
|
|
|
|
for (const option of options) {
|
|
if (typeof option === "string") {
|
|
patterns.push(option);
|
|
continue;
|
|
}
|
|
|
|
if (!option || typeof option !== "object") {
|
|
continue;
|
|
}
|
|
|
|
for (const entry of option.patterns ?? []) {
|
|
if (typeof entry === "string") {
|
|
patterns.push(entry);
|
|
} else if (entry?.group) {
|
|
patterns.push(...entry.group);
|
|
}
|
|
}
|
|
}
|
|
|
|
return patterns;
|
|
}
|
|
|
|
describe("DB Boundary ESLint DB boundary guard", () => {
|
|
it("restricts generated Prisma client source imports without blocking the package browser boundary", () => {
|
|
const restrictedRules = findRestrictedImportRules(eslintConfig);
|
|
assert.ok(restrictedRules.length > 0, "expected a no-restricted-imports rule");
|
|
|
|
const patterns = restrictedRules.flatMap(({ rule }) => collectRestrictedPatterns(rule));
|
|
|
|
assert.ok(patterns.includes("~/generated/prisma/client/*"), "missing tilde generated Prisma client restriction");
|
|
assert.ok(patterns.includes("app/generated/prisma/client/*"), "missing app generated Prisma client restriction");
|
|
assert.ok(patterns.includes("@prisma/client"), "missing direct @prisma/client restriction");
|
|
assert.ok(patterns.includes("@prisma/client/*"), "missing direct @prisma/client subpath restriction");
|
|
assert.ok(!patterns.includes("@toolctrl/db/prisma-browser"), "package Prisma browser boundary must remain importable");
|
|
});
|
|
|
|
it("keeps package-owned generated Prisma entrypoints available to db boundary files", () => {
|
|
const restrictedRules = findRestrictedImportRules(eslintConfig);
|
|
const boundaryOverrides = restrictedRules.filter(({ files }) =>
|
|
files.includes("packages/db/src/client.server.ts") || files.includes("packages/db/src/prisma-browser.ts"),
|
|
);
|
|
|
|
assert.ok(boundaryOverrides.length > 0, "expected db boundary override for generated Prisma entrypoints");
|
|
|
|
for (const { rule } of boundaryOverrides) {
|
|
const patterns = collectRestrictedPatterns(rule);
|
|
assert.ok(!patterns.includes("../generated/prisma/client/*"));
|
|
assert.ok(!patterns.includes("../generated/prisma/client/client.js"));
|
|
assert.ok(!patterns.includes("../generated/prisma/client/browser.js"));
|
|
}
|
|
});
|
|
|
|
it("blocks React imports in apps/web/app/utils/db without blocking Prisma browser package imports", () => {
|
|
const restrictedRules = findRestrictedImportRules(eslintConfig);
|
|
const dbOverrides = restrictedRules.filter(({ files }) => files.includes("apps/web/app/utils/db/**/*.ts"));
|
|
|
|
assert.ok(dbOverrides.length > 0, "expected apps/web/app/utils/db/**/*.ts override");
|
|
|
|
const patterns = dbOverrides.flatMap(({ rule }) => collectRestrictedPatterns(rule));
|
|
assert.ok(patterns.includes("react"), "missing react import restriction for apps/web/app/utils/db");
|
|
assert.ok(patterns.includes("react/*"), "missing react subpath import restriction for apps/web/app/utils/db");
|
|
assert.ok(!patterns.includes("@toolctrl/db/prisma-browser"), "db legacy boundary must allow Prisma browser type imports");
|
|
});
|
|
});
|