/** * Framework-rules check — runs the forbidden-import rules of the plan's * locked framework against the target project during implement-stage * verification. Mirrors arch-rules-check.ts: a checker config is emitted * (dependency-cruiser JSON for TypeScript maps, import-linter INI for * Python maps) and the matching tool runs it when installed. The tool is * never installed by this module: when absent, the check reports * toolAvailable=false so the caller can warn-and-continue honestly. * * The framework map comes from the chirpi framework-library; the framework * id comes from the plan's `## Framework` field (manifest.ts). When the * field is missing or `none`, the check skips cleanly. * * Executable rules come from the map's machine-readable `## Rules` section * when present (preferred — strict, hand-written globs). Maps without one * fall back to conservative prose compilation of `## Forbidden patterns`: * only unambiguous "X importing Y" items compile (layout folder before * "import", folder/backticked-module targets after it, em-dash explanation * ignored). Every rule cites its source; items too vague to compile stay * visible in the report, never silently dropped. */ import { type FrameworkMap } from "@adi-mudi/pi-chirpi"; export type FrameworkRulesTool = "dependency-cruiser" | "import-linter"; export interface FrameworkRule { /** The reason / source sentence this rule enforces. */ source: string; /** Importer side: a project path glob (e.g. "routes/**", * "*.controller.ts"). */ from: string; /** Imported side: a path glob (e.g. "models/**") or a `pkg:` * external package (e.g. "pkg:express"). */ to: string; } export interface FrameworkRulesResult { /** Framework id locked in the plan manifest; null when the plan carries * no `## Framework` field. */ frameworkId: string | null; /** True when the check did not run (no field, `none`, invalid map, no * derivable rules, or unsupported language). skipReason says why. */ skipped: boolean; skipReason: string | null; /** Executable rules derived from the map's forbidden patterns. */ rules: FrameworkRule[]; /** Emitted checker config, relative to the project root. */ configPath: string | null; tool: FrameworkRulesTool | null; toolAvailable: boolean; /** The tool actually ran (rules derived + config emitted + tool available). */ ran: boolean; violations: string[]; } export type FrameworkRulesExecFn = (cmd: string, args: string[], cwd: string) => Promise<{ code: number; output: string; }>; /** Folder aliases declared in the map's `## Layout map` fenced block * (basenames of entries ending with `/`, e.g. "routes", "services"). */ export declare function parseLayoutFolders(map: FrameworkMap): string[]; /** Compile the map's `## Forbidden patterns` prose into executable rules. * Fallback for maps without a `## Rules` section. Conservative by design: * an item only compiles when a layout folder is named before the word * "import" (the importer) and at least one target (layout folder or * backticked module) is named after it, before any em-dash explanation. * Everything else stays prose-only. Output uses the same glob / `pkg:` * shape as parsed `## Rules` lines so one emission pipeline serves both. */ export declare function deriveForbiddenRules(map: FrameworkMap): FrameworkRule[]; /** The map's executable rules: parsed `## Rules` lines when present * (preferred — strict, hand-written), prose compilation as fallback. */ export declare function frameworkRulesFromMap(map: FrameworkMap): FrameworkRule[]; /** Emit a dependency-cruiser JSON config with one forbidden rule per * framework rule (same shape chirpi's arch-rules emits). */ export declare function emitFrameworkDependencyCruiserConfig(id: string, rules: FrameworkRule[]): string; /** Emit an import-linter INI config with one forbidden contract per * framework rule. `rootPackage` defaults to "src". */ export declare function emitFrameworkImportLinterConfig(id: string, rules: FrameworkRule[], options?: { rootPackage?: string; }): string; /** Run the locked framework's forbidden-import rules at the implement gate. * The exec function is injectable so tests can mock the runner instead of * installing dependency-cruiser / import-linter. */ export declare function checkFrameworkRules(cwd: string, runId: string, execFn?: FrameworkRulesExecFn): Promise;