feat: enforce the adapter barrel boundary in the architecture gate

그룹 바깥에서 어댑터 내부 파일을 직접 import하면 check:architecture가
거부한다. 회귀 fixture 2개가 거부와 허용을 각각 고정한다 — 규칙 이름을
바꿔 보면 fixture 검사가 먼저 깨지는 것을 확인했다.

도착점 정규식은 중첩 수량자 대신 교대를 쓴다. dependency-cruiser의 안전
정규식 검사가 (?:[^/]+/)? 안의 + 를 unsafe로 거부하기 때문이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-09-16 18:54:17 +09:00
co-authored by Claude Opus 5
parent 1606d9b0c1
commit 27ab17d6d6
6 changed files with 40 additions and 1 deletions
+17 -1
View File
@@ -824,12 +824,13 @@ async function runGraphFixtureChecks(): Promise<GraphFixtureResult> {
"tests/fixtures/architecture/dependency-graph",
);
const allowedRoot = resolve(fixtureRoot, "allowed");
const [allowedGraph, unresolvedGraph, layerGraph, cycleGraph] =
const [allowedGraph, unresolvedGraph, layerGraph, cycleGraph, barrelGraph] =
await Promise.all([
analyzeSourceGraph(allowedRoot, "src"),
analyzeSourceGraph(resolve(fixtureRoot, "unresolved"), "src"),
analyzeSourceGraph(resolve(fixtureRoot, "layer"), "src"),
analyzeSourceGraph(resolve(fixtureRoot, "cycle"), "src"),
analyzeSourceGraph(resolve(fixtureRoot, "barrel"), "src"),
]);
const allowedFiles = new Set(await listFiles(allowedRoot));
const allowedSourceFile = resolve(
@@ -850,6 +851,21 @@ async function runGraphFixtureChecks(): Promise<GraphFixtureResult> {
),
);
const assertions = [
{
name: "deep adapter import from outside the group is rejected",
passed: blockingViolations(barrelGraph).some(
({ rule, source, target }) =>
rule === "adapter-groups-are-reached-through-their-barrel" &&
source === "src/bootstrap/compose-deep.ts" &&
target === "src/adapters/http/client.ts",
),
},
{
name: "barrel import from outside the group is accepted",
passed: !blockingViolations(barrelGraph).some(
({ source }) => source === "src/bootstrap/compose-barrel.ts",
),
},
{
name: "explicit TS specifier resolves to a TS module",
passed: allowedGraph.dependencies.some(