@anatomytool/validate 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +127 -0
- package/dist/canonical.d.ts +21 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +76 -0
- package/dist/canonical.js.map +1 -0
- package/dist/checks/commands-no-test-warn.d.ts +6 -0
- package/dist/checks/commands-no-test-warn.d.ts.map +1 -0
- package/dist/checks/commands-no-test-warn.js +35 -0
- package/dist/checks/commands-no-test-warn.js.map +1 -0
- package/dist/checks/description-warn.d.ts +6 -0
- package/dist/checks/description-warn.d.ts.map +1 -0
- package/dist/checks/description-warn.js +23 -0
- package/dist/checks/description-warn.js.map +1 -0
- package/dist/checks/entry-point-alias-warn.d.ts +6 -0
- package/dist/checks/entry-point-alias-warn.d.ts.map +1 -0
- package/dist/checks/entry-point-alias-warn.js +25 -0
- package/dist/checks/entry-point-alias-warn.js.map +1 -0
- package/dist/checks/fingerprint-check.d.ts +6 -0
- package/dist/checks/fingerprint-check.d.ts.map +1 -0
- package/dist/checks/fingerprint-check.js +59 -0
- package/dist/checks/fingerprint-check.js.map +1 -0
- package/dist/checks/hash-check.d.ts +6 -0
- package/dist/checks/hash-check.d.ts.map +1 -0
- package/dist/checks/hash-check.js +36 -0
- package/dist/checks/hash-check.js.map +1 -0
- package/dist/checks/interface-form-check.d.ts +6 -0
- package/dist/checks/interface-form-check.d.ts.map +1 -0
- package/dist/checks/interface-form-check.js +66 -0
- package/dist/checks/interface-form-check.js.map +1 -0
- package/dist/checks/memory-dangling-ref-check.d.ts +6 -0
- package/dist/checks/memory-dangling-ref-check.d.ts.map +1 -0
- package/dist/checks/memory-dangling-ref-check.js +34 -0
- package/dist/checks/memory-dangling-ref-check.js.map +1 -0
- package/dist/checks/memory-fingerprint-check.d.ts +6 -0
- package/dist/checks/memory-fingerprint-check.d.ts.map +1 -0
- package/dist/checks/memory-fingerprint-check.js +20 -0
- package/dist/checks/memory-fingerprint-check.js.map +1 -0
- package/dist/checks/memory-supersession-check.d.ts +6 -0
- package/dist/checks/memory-supersession-check.d.ts.map +1 -0
- package/dist/checks/memory-supersession-check.js +61 -0
- package/dist/checks/memory-supersession-check.js.map +1 -0
- package/dist/checks/memory-verification-check.d.ts +6 -0
- package/dist/checks/memory-verification-check.d.ts.map +1 -0
- package/dist/checks/memory-verification-check.js +61 -0
- package/dist/checks/memory-verification-check.js.map +1 -0
- package/dist/checks/nested-path-escape.d.ts +6 -0
- package/dist/checks/nested-path-escape.d.ts.map +1 -0
- package/dist/checks/nested-path-escape.js +76 -0
- package/dist/checks/nested-path-escape.js.map +1 -0
- package/dist/checks/schema-check.d.ts +6 -0
- package/dist/checks/schema-check.d.ts.map +1 -0
- package/dist/checks/schema-check.js +32 -0
- package/dist/checks/schema-check.js.map +1 -0
- package/dist/checks/source-cross-check.d.ts +52 -0
- package/dist/checks/source-cross-check.d.ts.map +1 -0
- package/dist/checks/source-cross-check.js +473 -0
- package/dist/checks/source-cross-check.js.map +1 -0
- package/dist/checks/source-path-check.d.ts +6 -0
- package/dist/checks/source-path-check.d.ts.map +1 -0
- package/dist/checks/source-path-check.js +62 -0
- package/dist/checks/source-path-check.js.map +1 -0
- package/dist/checks/structure-path-check.d.ts +6 -0
- package/dist/checks/structure-path-check.d.ts.map +1 -0
- package/dist/checks/structure-path-check.js +31 -0
- package/dist/checks/structure-path-check.js.map +1 -0
- package/dist/checks/verify/ast-grep-verifier.d.ts +4 -0
- package/dist/checks/verify/ast-grep-verifier.d.ts.map +1 -0
- package/dist/checks/verify/ast-grep-verifier.js +153 -0
- package/dist/checks/verify/ast-grep-verifier.js.map +1 -0
- package/dist/checks/verify/detect-ast-grep.d.ts +9 -0
- package/dist/checks/verify/detect-ast-grep.d.ts.map +1 -0
- package/dist/checks/verify/detect-ast-grep.js +26 -0
- package/dist/checks/verify/detect-ast-grep.js.map +1 -0
- package/dist/checks/verify/detect-semgrep.d.ts +8 -0
- package/dist/checks/verify/detect-semgrep.d.ts.map +1 -0
- package/dist/checks/verify/detect-semgrep.js +36 -0
- package/dist/checks/verify/detect-semgrep.js.map +1 -0
- package/dist/checks/verify/glob-verifier.d.ts +5 -0
- package/dist/checks/verify/glob-verifier.d.ts.map +1 -0
- package/dist/checks/verify/glob-verifier.js +58 -0
- package/dist/checks/verify/glob-verifier.js.map +1 -0
- package/dist/checks/verify/semgrep-pattern-verifier.d.ts +4 -0
- package/dist/checks/verify/semgrep-pattern-verifier.d.ts.map +1 -0
- package/dist/checks/verify/semgrep-pattern-verifier.js +121 -0
- package/dist/checks/verify/semgrep-pattern-verifier.js.map +1 -0
- package/dist/checks/verify/semgrep-rule-file-verifier.d.ts +9 -0
- package/dist/checks/verify/semgrep-rule-file-verifier.d.ts.map +1 -0
- package/dist/checks/verify/semgrep-rule-file-verifier.js +151 -0
- package/dist/checks/verify/semgrep-rule-file-verifier.js.map +1 -0
- package/dist/checks/verify/types.d.ts +44 -0
- package/dist/checks/verify/types.d.ts.map +1 -0
- package/dist/checks/verify/types.js +6 -0
- package/dist/checks/verify/types.js.map +1 -0
- package/dist/checks/verify-check.d.ts +9 -0
- package/dist/checks/verify-check.d.ts.map +1 -0
- package/dist/checks/verify-check.js +67 -0
- package/dist/checks/verify-check.js.map +1 -0
- package/dist/discovery.d.ts +13 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +82 -0
- package/dist/discovery.js.map +1 -0
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +5 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/memory.d.ts +19 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +80 -0
- package/dist/memory.js.map +1 -0
- package/dist/parse.d.ts +17 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +47 -0
- package/dist/parse.js.map +1 -0
- package/dist/schema-0.10.json +194 -0
- package/dist/schema-0.11.json +203 -0
- package/dist/schema-0.12.json +243 -0
- package/dist/schema-0.13.json +267 -0
- package/dist/schema-0.14.json +288 -0
- package/dist/schema-0.15.json +347 -0
- package/dist/schema-0.2.json +283 -0
- package/dist/schema-0.4.json +280 -0
- package/dist/schema-0.5.json +300 -0
- package/dist/schema-0.6.json +328 -0
- package/dist/schema-0.7.json +311 -0
- package/dist/schema-0.8.json +245 -0
- package/dist/schema-0.9.json +172 -0
- package/dist/schema-1.0.json +347 -0
- package/dist/schema-memory-0.1.json +43 -0
- package/dist/schema-memory-0.2.json +49 -0
- package/dist/schema-memory.d.ts +5 -0
- package/dist/schema-memory.d.ts.map +1 -0
- package/dist/schema-memory.js +16 -0
- package/dist/schema-memory.js.map +1 -0
- package/dist/schema.d.ts +6 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +62 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.json +129 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.generated.d.ts +1103 -0
- package/dist/types.generated.d.ts.map +1 -0
- package/dist/types.generated.js +7 -0
- package/dist/types.generated.js.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/validate-tree.d.ts +20 -0
- package/dist/validate-tree.d.ts.map +1 -0
- package/dist/validate-tree.js +64 -0
- package/dist/validate-tree.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
// src/checks/source-cross-check.ts
|
|
2
|
+
// Post-Pass-2 drift check. Flags two classes of authoring drift:
|
|
3
|
+
// 1. [[substance.key_dependencies]].name with no quoted reference in
|
|
4
|
+
// scanned source ("unused-dependency-claim").
|
|
5
|
+
// 2. Stale host-port / scoped-package / source-path literals embedded in
|
|
6
|
+
// [[rules]].rule|why, [[flows]].summary, [[decisions]].topic|reason
|
|
7
|
+
// ("literal-not-in-source").
|
|
8
|
+
// Skipped when repoRoot is undefined (matches structure-path-check pattern).
|
|
9
|
+
// See docs/superpowers/specs/2026-05-09-pass2-source-cross-check-design.md.
|
|
10
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
11
|
+
import { resolve, join } from "node:path";
|
|
12
|
+
const HOST_PORT_RE = /\b(?:localhost|127\.0\.0\.1|0\.0\.0\.0):\d{2,5}\b/g;
|
|
13
|
+
const SCOPED_PACKAGE_RE = /(?<![\w/])@[a-z0-9][\w-]*\/[a-z0-9][\w.-]*(?![\w/])/g;
|
|
14
|
+
const SOURCE_PATH_RE = /(?<![\w/])(?:src|lib|app|bin|cmd|pkg|internal|test|tests|spec|specs|docs)\/[\w/.-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|c|cpp|h|hpp|rb|php|md|json|toml|yaml|yml|sql|sh|bash)\b/g;
|
|
15
|
+
export function extractLiterals(text) {
|
|
16
|
+
if (typeof text !== "string" || text.length === 0)
|
|
17
|
+
return [];
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
const out = [];
|
|
20
|
+
const push = (literal, kind) => {
|
|
21
|
+
const key = `${kind}\x00${literal}`;
|
|
22
|
+
if (seen.has(key))
|
|
23
|
+
return;
|
|
24
|
+
seen.add(key);
|
|
25
|
+
out.push({ literal, kind });
|
|
26
|
+
};
|
|
27
|
+
for (const m of text.matchAll(HOST_PORT_RE))
|
|
28
|
+
push(m[0], "host-port");
|
|
29
|
+
for (const m of text.matchAll(SCOPED_PACKAGE_RE)) {
|
|
30
|
+
if (m[0].startsWith("@types/"))
|
|
31
|
+
continue;
|
|
32
|
+
push(m[0], "scoped-package");
|
|
33
|
+
}
|
|
34
|
+
for (const m of text.matchAll(SOURCE_PATH_RE))
|
|
35
|
+
push(m[0], "source-path");
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/** Returns true if `name` appears in `haystack` inside a quoted string,
|
|
39
|
+
* bounded on the right by either a closing quote or `/` (subpath imports
|
|
40
|
+
* like `'@fontsource/inter/400.css'` or `'react-dom/client'`). The right-
|
|
41
|
+
* side `/` is the only addition over a strict closing-quote match — `-` and
|
|
42
|
+
* `.` are still rejected so `react` does not match `react-dom`/`react.foo`. */
|
|
43
|
+
export function findQuotedReference(name, haystack) {
|
|
44
|
+
if (!name || !haystack)
|
|
45
|
+
return false;
|
|
46
|
+
return (haystack.includes(`'${name}'`) || haystack.includes(`"${name}"`) ||
|
|
47
|
+
haystack.includes(`'${name}/`) || haystack.includes(`"${name}/`));
|
|
48
|
+
}
|
|
49
|
+
const EXCLUDE_DIRS = new Set([
|
|
50
|
+
"node_modules", ".git", "dist", "build", "target", "out",
|
|
51
|
+
".next", ".turbo", "__pycache__", ".pytest_cache",
|
|
52
|
+
".venv", "venv", "coverage", ".cache",
|
|
53
|
+
// Documentation build outputs — generated HTML / static site artifacts that
|
|
54
|
+
// bloat the byte budget but never carry a meaningful dep / rule literal.
|
|
55
|
+
// Names match site generators' default output dirs (mkdocs `site/`, jekyll
|
|
56
|
+
// `_site/`, sphinx `_build/`). The 50-repo stress test hit budget exhaustion
|
|
57
|
+
// on fastapi/docs/pt translations and Alamofire/docs jazzy output via paths
|
|
58
|
+
// not in the original exclude list.
|
|
59
|
+
"site", "_site", "_build",
|
|
60
|
+
]);
|
|
61
|
+
// Files that almost never carry a primary source reference but eat the byte
|
|
62
|
+
// budget on large repos. Cheap extension test before stat() avoids reading
|
|
63
|
+
// pre-rendered HTML, minified bundles, lockfiles, jupyter notebooks, and
|
|
64
|
+
// translation/data files from the haystack. If a project genuinely needs
|
|
65
|
+
// these scanned (rare), they can raise ANATOMY_SOURCE_SCAN_BYTES — but then
|
|
66
|
+
// they should also know that adding `.html` to a real source-of-truth list
|
|
67
|
+
// is unusual.
|
|
68
|
+
const SKIP_EXT_RE = /\.(?:html|htm|svg|min\.js|min\.css|map|lock|sum|snap|ipynb|csv|tsv|po|pot|jsonl|ndjson)$/i;
|
|
69
|
+
const TOP_LEVEL_CONFIG_RE = /^\.?(vite|webpack|esbuild|rollup|jest|vitest|eslint|prettier|tsconfig|babel|tailwind|postcss|biome|swc|turbo|nx|lerna|pnpm-workspace)[\w.-]*\.(?:js|ts|cjs|mjs|json|yaml|yml)?$/;
|
|
70
|
+
const TOP_LEVEL_CONFIG_LITERALS = new Set([
|
|
71
|
+
"Makefile", "Dockerfile", "docker-compose.yml", "docker-compose.yaml",
|
|
72
|
+
]);
|
|
73
|
+
// 32 MB default — the prior 8 MB cap was tight enough that 7 of 50 mainstream
|
|
74
|
+
// repos in the v0.12 stress test (curl, fastapi, prettier, pandoc, Alamofire,
|
|
75
|
+
// Kong, plus one) hit `source-cross-check-truncated` despite mostly being
|
|
76
|
+
// bloated by docs/translations rather than source. With the doc-output
|
|
77
|
+
// EXCLUDE_DIRS additions and SKIP_EXT_RE blocklist below, 32 MB clears nearly
|
|
78
|
+
// all of them while still bounding pathological repos. Reading 32 MB of text
|
|
79
|
+
// into a haystack takes well under a second on any modern machine.
|
|
80
|
+
const DEFAULT_MAX_TOTAL_BYTES = 32 * 1024 * 1024;
|
|
81
|
+
const MAX_FILE_BYTES = 256 * 1024; // 256 KB
|
|
82
|
+
const MAX_DEPTH = 10;
|
|
83
|
+
const NUL_SCAN_BYTES = 4096;
|
|
84
|
+
/** Reads ANATOMY_SOURCE_SCAN_BYTES (e.g. "16M", "32768K", "16777216").
|
|
85
|
+
* Defaults to DEFAULT_MAX_TOTAL_BYTES (8 MB) when unset/malformed.
|
|
86
|
+
* Surfaced via the source-cross-check-truncated warning when the budget
|
|
87
|
+
* is exhausted, so monorepo users with >8MB of source can raise the cap
|
|
88
|
+
* without splitting into cascading sub-.anatomy files (per the
|
|
89
|
+
* 2026-05-09 stress test on openclaw-fresh). */
|
|
90
|
+
export function getMaxTotalBytes() {
|
|
91
|
+
const raw = process.env.ANATOMY_SOURCE_SCAN_BYTES;
|
|
92
|
+
if (!raw)
|
|
93
|
+
return DEFAULT_MAX_TOTAL_BYTES;
|
|
94
|
+
const m = /^(\d+)([KkMmGg]?)$/.exec(raw.trim());
|
|
95
|
+
if (!m)
|
|
96
|
+
return DEFAULT_MAX_TOTAL_BYTES;
|
|
97
|
+
const n = Number(m[1]);
|
|
98
|
+
if (!isFinite(n) || n <= 0)
|
|
99
|
+
return DEFAULT_MAX_TOTAL_BYTES;
|
|
100
|
+
const suffix = m[2].toLowerCase();
|
|
101
|
+
const mul = suffix === "k" ? 1024 : suffix === "m" ? 1024 * 1024 : suffix === "g" ? 1024 * 1024 * 1024 : 1;
|
|
102
|
+
return n * mul;
|
|
103
|
+
}
|
|
104
|
+
const TYPES_DEP_PREFIX = "@types/";
|
|
105
|
+
const TOOLING_DEP_ALLOWLIST = new Set(["husky", "lint-staged"]);
|
|
106
|
+
/** Sections of package.json that are *declarations* of deps, not uses. They
|
|
107
|
+
* must be excluded from the haystack — otherwise every declared dep would
|
|
108
|
+
* match as a quoted reference and Class 1 could never fire. */
|
|
109
|
+
const PACKAGE_JSON_DECLARATION_SECTIONS = [
|
|
110
|
+
"dependencies", "devDependencies", "peerDependencies",
|
|
111
|
+
"optionalDependencies", "bundleDependencies", "bundledDependencies",
|
|
112
|
+
];
|
|
113
|
+
/** Tokens that delimit commands within a package.json script string. */
|
|
114
|
+
const SCRIPT_TOKEN_DELIMITERS = /[\s&|;><]+/;
|
|
115
|
+
/** Returns true if `name` appears as a whitespace/operator-bounded token in
|
|
116
|
+
* any value of the parsed package.json scripts. Handles bare invocation
|
|
117
|
+
* (`"prettier --write ."`), `npx <name>`, and chained commands
|
|
118
|
+
* (`"npm run lint && vitest run"`). For `@scope/name` deps, also matches
|
|
119
|
+
* the conventional bin form `<scope>-<name>` (e.g. `@electron/rebuild`
|
|
120
|
+
* publishes a bin called `electron-rebuild`). */
|
|
121
|
+
export function isUsedInScripts(name, scripts) {
|
|
122
|
+
if (!name || !scripts)
|
|
123
|
+
return false;
|
|
124
|
+
const candidates = [name];
|
|
125
|
+
const scopedMatch = /^@([a-z0-9][\w-]*)\/([a-z0-9][\w.-]*)$/.exec(name);
|
|
126
|
+
if (scopedMatch)
|
|
127
|
+
candidates.push(`${scopedMatch[1]}-${scopedMatch[2]}`);
|
|
128
|
+
for (const value of Object.values(scripts)) {
|
|
129
|
+
if (typeof value !== "string")
|
|
130
|
+
continue;
|
|
131
|
+
const tokens = value.split(SCRIPT_TOKEN_DELIMITERS).filter(Boolean);
|
|
132
|
+
for (const c of candidates)
|
|
133
|
+
if (tokens.includes(c))
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
/** Source-file extensions for the top-level source-file scan (matches the
|
|
139
|
+
* source-path regex's extension list). Repos that put code at the root
|
|
140
|
+
* rather than under src/ rely on this so dep imports there land in the
|
|
141
|
+
* haystack. */
|
|
142
|
+
const TOP_LEVEL_SOURCE_EXT_RE = /\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|c|cpp|h|hpp|rb|php)$/;
|
|
143
|
+
function isProbablyBinary(buf) {
|
|
144
|
+
const limit = Math.min(buf.length, NUL_SCAN_BYTES);
|
|
145
|
+
for (let i = 0; i < limit; i++) {
|
|
146
|
+
if (buf[i] === 0)
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
function recordSkip(builder, scanRoot, absPath) {
|
|
152
|
+
builder.truncated = true;
|
|
153
|
+
if (builder.firstSkippedRel === null) {
|
|
154
|
+
let rel = absPath.slice(scanRoot.length);
|
|
155
|
+
if (rel.startsWith("/") || rel.startsWith("\\"))
|
|
156
|
+
rel = rel.slice(1);
|
|
157
|
+
builder.firstSkippedRel = rel || absPath;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Loads package.json into the haystack but strips dep-declaration sections
|
|
161
|
+
* (`dependencies`, `devDependencies`, etc.). Without this, every quoted dep
|
|
162
|
+
* name in the manifest matches as a "use" and Class 1 cannot fire on any
|
|
163
|
+
* declared dep — which is the very case it exists to catch. Also captures
|
|
164
|
+
* the parsed scripts so checkDependencyUsage can detect bare-command usage.
|
|
165
|
+
* Falls back to plain text load if the file is not parseable JSON. */
|
|
166
|
+
function loadPackageJson(builder, scanRoot) {
|
|
167
|
+
const absPath = join(scanRoot, "package.json");
|
|
168
|
+
if (!existsSync(absPath))
|
|
169
|
+
return undefined;
|
|
170
|
+
if (builder.seenAbs.has(absPath))
|
|
171
|
+
return undefined;
|
|
172
|
+
let raw;
|
|
173
|
+
try {
|
|
174
|
+
raw = readFileSync(absPath, "utf8");
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
let parsed;
|
|
180
|
+
try {
|
|
181
|
+
parsed = JSON.parse(raw);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
tryLoadFile(builder, scanRoot, absPath);
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
const filtered = { ...parsed };
|
|
188
|
+
for (const k of PACKAGE_JSON_DECLARATION_SECTIONS)
|
|
189
|
+
delete filtered[k];
|
|
190
|
+
const filteredText = JSON.stringify(filtered, null, 2);
|
|
191
|
+
const size = Buffer.byteLength(filteredText, "utf8");
|
|
192
|
+
if (builder.totalBytes + size > builder.maxTotalBytes) {
|
|
193
|
+
recordSkip(builder, scanRoot, absPath);
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
builder.files.push({ relPath: "package.json", content: filteredText });
|
|
197
|
+
builder.totalBytes += size;
|
|
198
|
+
builder.seenAbs.add(absPath);
|
|
199
|
+
const scripts = {};
|
|
200
|
+
const rawScripts = parsed.scripts;
|
|
201
|
+
if (rawScripts && typeof rawScripts === "object") {
|
|
202
|
+
for (const [k, v] of Object.entries(rawScripts)) {
|
|
203
|
+
if (typeof v === "string")
|
|
204
|
+
scripts[k] = v;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return scripts;
|
|
208
|
+
}
|
|
209
|
+
function tryLoadFile(builder, scanRoot, absPath) {
|
|
210
|
+
if (builder.truncated)
|
|
211
|
+
return;
|
|
212
|
+
if (builder.seenAbs.has(absPath))
|
|
213
|
+
return;
|
|
214
|
+
// Cheap extension test before stat() — skip rendered HTML, minified bundles,
|
|
215
|
+
// lockfiles, jupyter notebooks, translation/data files. None of these
|
|
216
|
+
// typically carry the dep / rule literals the cross-check is looking for,
|
|
217
|
+
// and on large repos they collectively dominate the byte budget.
|
|
218
|
+
if (SKIP_EXT_RE.test(absPath))
|
|
219
|
+
return;
|
|
220
|
+
let st;
|
|
221
|
+
try {
|
|
222
|
+
st = statSync(absPath);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (!st.isFile())
|
|
228
|
+
return;
|
|
229
|
+
if (st.size > MAX_FILE_BYTES)
|
|
230
|
+
return;
|
|
231
|
+
if (builder.totalBytes + st.size > builder.maxTotalBytes) {
|
|
232
|
+
recordSkip(builder, scanRoot, absPath);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
let buf;
|
|
236
|
+
try {
|
|
237
|
+
buf = readFileSync(absPath);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (isProbablyBinary(buf))
|
|
243
|
+
return;
|
|
244
|
+
let relPath = absPath.slice(scanRoot.length);
|
|
245
|
+
if (relPath.startsWith("/") || relPath.startsWith("\\"))
|
|
246
|
+
relPath = relPath.slice(1);
|
|
247
|
+
builder.files.push({ relPath, content: buf.toString("utf8") });
|
|
248
|
+
builder.totalBytes += st.size;
|
|
249
|
+
builder.seenAbs.add(absPath);
|
|
250
|
+
}
|
|
251
|
+
function walkDir(builder, scanRoot, dirAbs, depth) {
|
|
252
|
+
if (builder.truncated)
|
|
253
|
+
return;
|
|
254
|
+
if (depth > MAX_DEPTH)
|
|
255
|
+
return;
|
|
256
|
+
let entries;
|
|
257
|
+
try {
|
|
258
|
+
entries = readdirSync(dirAbs, { withFileTypes: true });
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
for (const e of entries) {
|
|
264
|
+
if (builder.truncated)
|
|
265
|
+
return;
|
|
266
|
+
if (e.isDirectory()) {
|
|
267
|
+
if (EXCLUDE_DIRS.has(e.name))
|
|
268
|
+
continue;
|
|
269
|
+
walkDir(builder, scanRoot, join(dirAbs, e.name), depth + 1);
|
|
270
|
+
}
|
|
271
|
+
else if (e.isFile()) {
|
|
272
|
+
tryLoadFile(builder, scanRoot, join(dirAbs, e.name));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
export function buildSourceIndex(scanRoot, structureEntries) {
|
|
277
|
+
const maxTotalBytes = getMaxTotalBytes();
|
|
278
|
+
const builder = {
|
|
279
|
+
files: [],
|
|
280
|
+
totalBytes: 0,
|
|
281
|
+
truncated: false,
|
|
282
|
+
firstSkippedRel: null,
|
|
283
|
+
maxTotalBytes,
|
|
284
|
+
seenAbs: new Set(),
|
|
285
|
+
};
|
|
286
|
+
if (!existsSync(scanRoot)) {
|
|
287
|
+
return { files: [], combinedHaystack: "", truncated: false, maxTotalBytes };
|
|
288
|
+
}
|
|
289
|
+
// 1. package.json — load FIRST so the filtered version (dep-declaration
|
|
290
|
+
// sections stripped) is what lands in the haystack. The structure walker
|
|
291
|
+
// below skips already-seen absolute paths, so a structure entry like
|
|
292
|
+
// path = "." won't re-load the unfiltered file.
|
|
293
|
+
const packageJsonScripts = loadPackageJson(builder, scanRoot);
|
|
294
|
+
// 2. Structure dirs (every entry, regardless of kind).
|
|
295
|
+
for (const entry of structureEntries) {
|
|
296
|
+
if (typeof entry?.path !== "string")
|
|
297
|
+
continue;
|
|
298
|
+
const dirAbs = resolve(scanRoot, entry.path);
|
|
299
|
+
if (!existsSync(dirAbs))
|
|
300
|
+
continue;
|
|
301
|
+
let st;
|
|
302
|
+
try {
|
|
303
|
+
st = statSync(dirAbs);
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (st.isFile()) {
|
|
309
|
+
tryLoadFile(builder, scanRoot, dirAbs);
|
|
310
|
+
}
|
|
311
|
+
else if (st.isDirectory()) {
|
|
312
|
+
walkDir(builder, scanRoot, dirAbs, 0);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// 3. Top-level config files + top-level source files. Source-file inclusion
|
|
316
|
+
// handles small repos that put server.js / database.js / main.py at the
|
|
317
|
+
// root rather than under src/ — without this, deps imported there look
|
|
318
|
+
// "unused" because the structure entries don't cover them.
|
|
319
|
+
let topEntries;
|
|
320
|
+
try {
|
|
321
|
+
topEntries = readdirSync(scanRoot, { withFileTypes: true });
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
topEntries = [];
|
|
325
|
+
}
|
|
326
|
+
for (const e of topEntries) {
|
|
327
|
+
if (!e.isFile())
|
|
328
|
+
continue;
|
|
329
|
+
if (TOP_LEVEL_CONFIG_LITERALS.has(e.name) ||
|
|
330
|
+
TOP_LEVEL_CONFIG_RE.test(e.name) ||
|
|
331
|
+
TOP_LEVEL_SOURCE_EXT_RE.test(e.name)) {
|
|
332
|
+
tryLoadFile(builder, scanRoot, join(scanRoot, e.name));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// 4. .github/workflows/*.{yml,yaml}.
|
|
336
|
+
const workflowsDir = join(scanRoot, ".github", "workflows");
|
|
337
|
+
if (existsSync(workflowsDir)) {
|
|
338
|
+
let wfEntries;
|
|
339
|
+
try {
|
|
340
|
+
wfEntries = readdirSync(workflowsDir, { withFileTypes: true });
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
wfEntries = [];
|
|
344
|
+
}
|
|
345
|
+
for (const e of wfEntries) {
|
|
346
|
+
if (!e.isFile())
|
|
347
|
+
continue;
|
|
348
|
+
if (e.name.endsWith(".yml") || e.name.endsWith(".yaml")) {
|
|
349
|
+
tryLoadFile(builder, scanRoot, join(workflowsDir, e.name));
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const combinedHaystack = builder.files.map(f => f.content).join("\n\x00\n");
|
|
354
|
+
return {
|
|
355
|
+
files: builder.files,
|
|
356
|
+
combinedHaystack,
|
|
357
|
+
truncated: builder.truncated,
|
|
358
|
+
maxTotalBytes,
|
|
359
|
+
firstSkippedRel: builder.firstSkippedRel ?? undefined,
|
|
360
|
+
packageJsonScripts,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function checkDependencyUsage(keyDependencies, index) {
|
|
364
|
+
const warnings = [];
|
|
365
|
+
for (let i = 0; i < keyDependencies.length; i++) {
|
|
366
|
+
const name = keyDependencies[i]?.name;
|
|
367
|
+
if (typeof name !== "string" || name.length === 0)
|
|
368
|
+
continue;
|
|
369
|
+
if (name.startsWith(TYPES_DEP_PREFIX))
|
|
370
|
+
continue;
|
|
371
|
+
if (TOOLING_DEP_ALLOWLIST.has(name))
|
|
372
|
+
continue;
|
|
373
|
+
if (findQuotedReference(name, index.combinedHaystack))
|
|
374
|
+
continue;
|
|
375
|
+
if (isUsedInScripts(name, index.packageJsonScripts))
|
|
376
|
+
continue;
|
|
377
|
+
warnings.push({
|
|
378
|
+
code: "unused-dependency-claim",
|
|
379
|
+
message: `key_dependencies[${i}].name "${name}" not found as a quoted reference in scanned source. Either it's unused (consider removing) or it's referenced in a location the cross-check doesn't scan.`,
|
|
380
|
+
pointer: `/substance/key_dependencies/${i}`,
|
|
381
|
+
actual: name,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
return warnings;
|
|
385
|
+
}
|
|
386
|
+
function collectClaimFields(doc) {
|
|
387
|
+
const out = [];
|
|
388
|
+
const d = doc;
|
|
389
|
+
if (Array.isArray(d.rules)) {
|
|
390
|
+
for (let i = 0; i < d.rules.length; i++) {
|
|
391
|
+
const r = d.rules[i];
|
|
392
|
+
if (typeof r?.rule === "string")
|
|
393
|
+
out.push({ arrayName: "rules", index: i, field: "rule", text: r.rule });
|
|
394
|
+
if (typeof r?.why === "string")
|
|
395
|
+
out.push({ arrayName: "rules", index: i, field: "why", text: r.why });
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (Array.isArray(d.flows)) {
|
|
399
|
+
for (let i = 0; i < d.flows.length; i++) {
|
|
400
|
+
const f = d.flows[i];
|
|
401
|
+
if (typeof f?.summary === "string")
|
|
402
|
+
out.push({ arrayName: "flows", index: i, field: "summary", text: f.summary });
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (Array.isArray(d.decisions)) {
|
|
406
|
+
for (let i = 0; i < d.decisions.length; i++) {
|
|
407
|
+
const dec = d.decisions[i];
|
|
408
|
+
if (typeof dec?.topic === "string")
|
|
409
|
+
out.push({ arrayName: "decisions", index: i, field: "topic", text: dec.topic });
|
|
410
|
+
if (typeof dec?.reason === "string")
|
|
411
|
+
out.push({ arrayName: "decisions", index: i, field: "reason", text: dec.reason });
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return out;
|
|
415
|
+
}
|
|
416
|
+
function checkLiteralCrossReferences(fields, scanRoot, index) {
|
|
417
|
+
const warnings = [];
|
|
418
|
+
for (const f of fields) {
|
|
419
|
+
const literals = extractLiterals(f.text);
|
|
420
|
+
for (const { literal, kind } of literals) {
|
|
421
|
+
let found = false;
|
|
422
|
+
if (kind === "source-path") {
|
|
423
|
+
if (existsSync(resolve(scanRoot, literal))) {
|
|
424
|
+
found = true;
|
|
425
|
+
}
|
|
426
|
+
else if (index.combinedHaystack.includes(literal)) {
|
|
427
|
+
found = true;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
if (index.combinedHaystack.includes(literal))
|
|
432
|
+
found = true;
|
|
433
|
+
}
|
|
434
|
+
if (found)
|
|
435
|
+
continue;
|
|
436
|
+
warnings.push({
|
|
437
|
+
code: "literal-not-in-source",
|
|
438
|
+
message: `${kind} literal "${literal}" referenced in ${f.arrayName}[${f.index}].${f.field} not found in scanned source. Either the claim is stale or the literal is in an unscanned location.`,
|
|
439
|
+
pointer: `/${f.arrayName}/${f.index}/${f.field}`,
|
|
440
|
+
actual: literal,
|
|
441
|
+
literalKind: kind,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return warnings;
|
|
446
|
+
}
|
|
447
|
+
export function sourceCrossCheck(doc, repoRoot, anatomyDir) {
|
|
448
|
+
if (!repoRoot)
|
|
449
|
+
return { errors: [], warnings: [] };
|
|
450
|
+
const scanRoot = anatomyDir ? resolve(repoRoot, anatomyDir) : repoRoot;
|
|
451
|
+
const structureEntries = doc?.structure?.entries ?? [];
|
|
452
|
+
const keyDependencies = doc?.substance?.key_dependencies ?? [];
|
|
453
|
+
const claimFields = collectClaimFields(doc);
|
|
454
|
+
if (keyDependencies.length === 0 && claimFields.length === 0) {
|
|
455
|
+
return { errors: [], warnings: [] };
|
|
456
|
+
}
|
|
457
|
+
const index = buildSourceIndex(scanRoot, structureEntries);
|
|
458
|
+
const warnings = [];
|
|
459
|
+
if (index.truncated) {
|
|
460
|
+
const skippedNote = index.firstSkippedRel
|
|
461
|
+
? ` First file skipped: ${JSON.stringify(index.firstSkippedRel)}.`
|
|
462
|
+
: "";
|
|
463
|
+
warnings.push({
|
|
464
|
+
code: "source-cross-check-truncated",
|
|
465
|
+
message: `source-cross-check stopped indexing at ${index.maxTotalBytes} bytes; some files were not scanned.${skippedNote} Set ANATOMY_SOURCE_SCAN_BYTES (e.g. 16M, 64M) to raise the budget, or split via cascading sub-.anatomy files for monorepos. Drift in unscanned files cannot be detected.`,
|
|
466
|
+
pointer: "",
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
warnings.push(...checkDependencyUsage(keyDependencies, index));
|
|
470
|
+
warnings.push(...checkLiteralCrossReferences(claimFields, scanRoot, index));
|
|
471
|
+
return { errors: [], warnings };
|
|
472
|
+
}
|
|
473
|
+
//# sourceMappingURL=source-cross-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-cross-check.js","sourceRoot":"","sources":["../../src/checks/source-cross-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-path-check.d.ts","sourceRoot":"","sources":["../../src/checks/source-path-check.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE7D,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,EACZ,QAAQ,CAAC,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB;IACD,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB,CAkDA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// src/checks/source-path-check.ts
|
|
2
|
+
// For [[substance.capabilities|limitations]].source:
|
|
3
|
+
// - Structured form ({ path, symbol }): hard error if path doesn't exist
|
|
4
|
+
// under repoRoot.
|
|
5
|
+
// - String form ("path#fragment"): soft warning if the leading path doesn't
|
|
6
|
+
// exist (the v0.1 string format was deliberately permissive).
|
|
7
|
+
// When repoRoot is undefined: skipped entirely.
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
export function sourcePathCheck(doc, repoRoot, anatomyDir) {
|
|
11
|
+
if (!repoRoot)
|
|
12
|
+
return { errors: [], warnings: [] };
|
|
13
|
+
const base = anatomyDir ? resolve(repoRoot, anatomyDir) : repoRoot;
|
|
14
|
+
const errors = [];
|
|
15
|
+
const warnings = [];
|
|
16
|
+
const subst = doc?.substance;
|
|
17
|
+
if (!subst)
|
|
18
|
+
return { errors, warnings };
|
|
19
|
+
for (const arrName of ["capabilities", "limitations"]) {
|
|
20
|
+
const arr = subst[arrName];
|
|
21
|
+
if (!Array.isArray(arr))
|
|
22
|
+
continue;
|
|
23
|
+
for (let i = 0; i < arr.length; i++) {
|
|
24
|
+
const src = arr[i]?.source;
|
|
25
|
+
if (src === undefined)
|
|
26
|
+
continue;
|
|
27
|
+
let path;
|
|
28
|
+
let isStructured = false;
|
|
29
|
+
if (typeof src === "string") {
|
|
30
|
+
const hashIdx = src.indexOf("#");
|
|
31
|
+
path = hashIdx === -1 ? src : src.slice(0, hashIdx);
|
|
32
|
+
if (path === "")
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
else if (src && typeof src === "object" && typeof src.path === "string") {
|
|
36
|
+
path = src.path;
|
|
37
|
+
isStructured = true;
|
|
38
|
+
}
|
|
39
|
+
if (path === undefined)
|
|
40
|
+
continue;
|
|
41
|
+
if (existsSync(resolve(base, path)))
|
|
42
|
+
continue;
|
|
43
|
+
if (isStructured) {
|
|
44
|
+
errors.push({
|
|
45
|
+
code: "source-path-not-found",
|
|
46
|
+
message: `substance.${arrName}[${i}].source.path not found: ${path}`,
|
|
47
|
+
pointer: `/substance/${arrName}/${i}/source/path`,
|
|
48
|
+
actual: path,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
warnings.push({
|
|
53
|
+
code: "source-path-soft-not-found",
|
|
54
|
+
message: `substance.${arrName}[${i}].source path not found: ${path} (string form is best-effort)`,
|
|
55
|
+
pointer: `/substance/${arrName}/${i}/source`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { errors, warnings };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=source-path-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-path-check.js","sourceRoot":"","sources":["../../src/checks/source-path-check.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,qDAAqD;AACrD,2EAA2E;AAC3E,sBAAsB;AACtB,8EAA8E;AAC9E,kEAAkE;AAClE,gDAAgD;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,UAAU,eAAe,CAC7B,GAAY,EACZ,QAAiB,EACjB,UAAmB;IAKnB,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAEnD,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnE,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAI,GAA+E,EAAE,SAAS,CAAC;IAC1G,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAExC,KAAK,MAAM,OAAO,IAAI,CAAC,cAAc,EAAE,aAAa,CAAU,EAAE,CAAC;QAC/D,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,SAAS;QAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;YAC3B,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YAEhC,IAAI,IAAwB,CAAC;YAC7B,IAAI,YAAY,GAAG,KAAK,CAAC;YAEzB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACjC,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBACpD,IAAI,IAAI,KAAK,EAAE;oBAAE,SAAS;YAC5B,CAAC;iBAAM,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAQ,GAA0B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAClG,IAAI,GAAI,GAAwB,CAAC,IAAI,CAAC;gBACtC,YAAY,GAAG,IAAI,CAAC;YACtB,CAAC;YAED,IAAI,IAAI,KAAK,SAAS;gBAAE,SAAS;YACjC,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAAE,SAAS;YAE9C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,uBAAuB;oBAC7B,OAAO,EAAE,aAAa,OAAO,IAAI,CAAC,4BAA4B,IAAI,EAAE;oBACpE,OAAO,EAAE,cAAc,OAAO,IAAI,CAAC,cAAc;oBACjD,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,4BAA4B;oBAClC,OAAO,EAAE,aAAa,OAAO,IAAI,CAAC,4BAA4B,IAAI,+BAA+B;oBACjG,OAAO,EAAE,cAAc,OAAO,IAAI,CAAC,SAAS;iBAC7C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ValidationError, Warning } from "../errors.js";
|
|
2
|
+
export declare function structurePathCheck(doc: unknown, repoRoot?: string, anatomyDir?: string): {
|
|
3
|
+
errors: ValidationError[];
|
|
4
|
+
warnings: Warning[];
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=structure-path-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure-path-check.d.ts","sourceRoot":"","sources":["../../src/checks/structure-path-check.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE7D,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,OAAO,EACZ,QAAQ,CAAC,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB;IACD,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB,CAsBA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/checks/structure-path-check.ts
|
|
2
|
+
// Verifies every [[structure.entries]].path exists on disk relative to the
|
|
3
|
+
// caller-supplied repoRoot. When repoRoot is undefined (library callers,
|
|
4
|
+
// conformance fixtures), the check is a no-op — paths are not checked.
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
export function structurePathCheck(doc, repoRoot, anatomyDir) {
|
|
8
|
+
if (!repoRoot)
|
|
9
|
+
return { errors: [], warnings: [] };
|
|
10
|
+
const entries = doc?.structure?.entries;
|
|
11
|
+
if (!Array.isArray(entries))
|
|
12
|
+
return { errors: [], warnings: [] };
|
|
13
|
+
const base = anatomyDir ? resolve(repoRoot, anatomyDir) : repoRoot;
|
|
14
|
+
const errors = [];
|
|
15
|
+
for (let i = 0; i < entries.length; i++) {
|
|
16
|
+
const p = entries[i]?.path;
|
|
17
|
+
if (typeof p !== "string")
|
|
18
|
+
continue; // schema-check catches malformed
|
|
19
|
+
const abs = resolve(base, p);
|
|
20
|
+
if (!existsSync(abs)) {
|
|
21
|
+
errors.push({
|
|
22
|
+
code: "structure-path-not-found",
|
|
23
|
+
message: `structure entry path not found: ${p}`,
|
|
24
|
+
pointer: `/structure/entries/${i}/path`,
|
|
25
|
+
actual: p,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { errors, warnings: [] };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=structure-path-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure-path-check.js","sourceRoot":"","sources":["../../src/checks/structure-path-check.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,2EAA2E;AAC3E,yEAAyE;AACzE,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,UAAU,kBAAkB,CAChC,GAAY,EACZ,QAAiB,EACjB,UAAmB;IAKnB,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAEnD,MAAM,OAAO,GAAI,GAA8D,EAAE,SAAS,EAAE,OAAO,CAAC;IACpG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAEjE,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnE,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAC3B,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS,CAAC,iCAAiC;QACtE,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,0BAA0B;gBAChC,OAAO,EAAE,mCAAmC,CAAC,EAAE;gBAC/C,OAAO,EAAE,sBAAsB,CAAC,OAAO;gBACvC,MAAM,EAAE,CAAC;aACV,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-grep-verifier.d.ts","sourceRoot":"","sources":["../../../src/checks/verify/ast-grep-verifier.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAoDnD,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,EAAE,CAAC,CA0GpB"}
|