@danielsimonjr/repo-tools 2.2.5 → 2.2.7
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/CHANGELOG.md +38 -0
- package/README.md +2 -2
- package/dist/cli.js +97 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,44 @@ All notable changes to this project are recorded in this file. The format follow
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.2.7] - 2026-10-22
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `repo-tools ste` exits 2 when any path in the argument list does not exist, and prints `ERROR: path does not exist:
|
|
14
|
+
<path>` on stderr for each such path. Before, a mistyped path among valid paths was ignored and the run exited 0.
|
|
15
|
+
The report of each valid path is still printed.
|
|
16
|
+
- The warning that `repo-tools map` writes for a `package.json` entry that does not resolve is shorter (15 words).
|
|
17
|
+
It had 30 words, so `repo-tools ste` flagged the generated `FILE_INVENTORY.md`. A test now checks the word limit
|
|
18
|
+
of every warning and that the generated report passes `repo-tools ste`.
|
|
19
|
+
- `repo-tools map` reads a folder named `test/` as a tests folder, as version 1.x did. Before, only `tests/` counted,
|
|
20
|
+
so a file such as `test/setup.ts` got the area `src` in `FILE_INVENTORY.md` and counted as a source file in
|
|
21
|
+
`TEST_COVERAGE.md`. The disposition legend and the `--tests` message name both folders.
|
|
22
|
+
- The `TEST_COVERAGE.md` note on the coverage policy no longer links `COVERAGE_POLICY.md`, a file that the tool does
|
|
23
|
+
not write, and no longer names mathjs or AssemblyScript.
|
|
24
|
+
- The `Expected test` hint in `TEST_COVERAGE.md` names `tests/unit/<module>/`. It appears only when the repository
|
|
25
|
+
keeps tests in `tests/unit/`. Other repositories get the plain list of untested files.
|
|
26
|
+
- The text of `duplicate-symbols.md` and of the `duplicate-symbols.json` note no longer names `Bucket C` or
|
|
27
|
+
`AssemblyScript`.
|
|
28
|
+
|
|
29
|
+
## [2.2.6] - 2026-10-22
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- `repo-tools map` finds the entry roots of an app whose build output is not `dist/` and whose sources are not
|
|
34
|
+
only under `src/`. On an Electron app (main process built to `dist-electron/`, CLI built to `dist-cli/`, renderer
|
|
35
|
+
loaded from `src/index.html`) it reported 74 dormant files, among them 11 orphans, and now reports 5 dormant files,
|
|
36
|
+
among them 3 orphans. Four sources of roots were missing or broken:
|
|
37
|
+
- A `tsc -p <tsconfig>` script of the root package in a repository without workspaces seeds the files of that
|
|
38
|
+
tsconfig. Only a workspace package did this before.
|
|
39
|
+
- A tsconfig that holds comments or trailing commas is read. `JSON.parse` rejected it and the whole tsconfig was
|
|
40
|
+
ignored without a message.
|
|
41
|
+
- A root build or test config names entry files with an `entry`, `input`, `setupFiles`, `globalSetup` or
|
|
42
|
+
`globalTeardown` key (for example `path.resolve(__dirname, 'electron/main.ts')`). Each such file is a root.
|
|
43
|
+
Only `new URL(...)` was read before.
|
|
44
|
+
- The module script of `index.html` or `src/index.html` is a root.
|
|
45
|
+
The ambient declaration files (`vite-env.d.ts`) stay in the list of files without an importer, as before.
|
|
46
|
+
|
|
9
47
|
## [2.2.5] - 2026-10-22
|
|
10
48
|
|
|
11
49
|
### Changed
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
| `query` | Answers structural questions from the graph of `map`, and writes two derived reports. |
|
|
14
14
|
| `ste` | Checks Markdown or docstring prose against Simplified Technical English. |
|
|
15
15
|
|
|
16
|
-
Status: version 2.2.
|
|
16
|
+
Status: version 2.2.7.
|
|
17
17
|
|
|
18
18
|
- `map`, `check` and `query` read their settings from `repo-tools.config.json` in the root. The
|
|
19
19
|
section of `map` is `map` (its old name, `depgraph`, is also read). `--config=<file>` makes any
|
|
@@ -41,7 +41,7 @@ repo-tools --version
|
|
|
41
41
|
|
|
42
42
|
The executable holds the tool and the Bun runtime. It needs no Bun, Node or `node_modules`.
|
|
43
43
|
Download the file for your platform and `SHA256SUMS` from the
|
|
44
|
-
[GitHub release](https://github.com/danielsimonjr/repo-tools/releases/tag/v2.2.
|
|
44
|
+
[GitHub release](https://github.com/danielsimonjr/repo-tools/releases/tag/v2.2.7):
|
|
45
45
|
|
|
46
46
|
| Platform | File |
|
|
47
47
|
|---|---|
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// package.json
|
|
3
3
|
var package_default = {
|
|
4
4
|
name: "@danielsimonjr/repo-tools",
|
|
5
|
-
version: "2.2.
|
|
5
|
+
version: "2.2.7",
|
|
6
6
|
description: "One CLI for repository analysis: dependency graphs creation and query with per-export API facts, file chunking, and context compression. TypeScript on Bun, compiled to a single executable.",
|
|
7
7
|
type: "module",
|
|
8
8
|
license: "MIT",
|
|
@@ -974,7 +974,7 @@ function mergeDepgraphConfig(cli, file) {
|
|
|
974
974
|
// src/depgraph/args.ts
|
|
975
975
|
var SCAN_SCOPE_FLAGS = {
|
|
976
976
|
"--src": "the census finds the source files itself; the area of a file comes from its path",
|
|
977
|
-
"--tests": "a test file is found by its name or its tests/ folder",
|
|
977
|
+
"--tests": "a test file is found by its name or by its test/ or tests/ folder",
|
|
978
978
|
"--exclude": "the census reads the files that git tracks; list a file in .gitignore instead",
|
|
979
979
|
"--also-exclude": "the census reads the files that git tracks; list a file in .gitignore instead",
|
|
980
980
|
"--all": "the graph always holds every file; the disposition of each file shows reachability",
|
|
@@ -1372,7 +1372,7 @@ var TYPE_DUP_CATEGORIES = [
|
|
|
1372
1372
|
{ cat: "type", key: "types" },
|
|
1373
1373
|
{ cat: "enum", key: "enums" }
|
|
1374
1374
|
];
|
|
1375
|
-
var DUPLICATE_SYMBOLS_NOTE = "This report groups names by OWN definition, not by call graph, then classifies each " + "flagged name (see DupEntryTag): TRUE_DUPLICATE (the actionable merge targets), " + "DISPATCH_VARIANT (>=2 mathTyped(...) registrations of the same public name — distinct " + "dispatch surfaces,
|
|
1375
|
+
var DUPLICATE_SYMBOLS_NOTE = "This report groups names by OWN definition, not by call graph, then classifies each " + "flagged name (see DupEntryTag): TRUE_DUPLICATE (the actionable merge targets), " + "DISPATCH_VARIANT (>=2 mathTyped(...) registrations of the same public name — distinct " + "dispatch surfaces, not copy-paste bodies), " + "ALIAS_DELEGATION (a const-alias forward to an imported symbol, not an independent body — " + "excluded once fewer than 2 real bodies remain), and ALLOWLISTED (matches " + "duplicate-allowlist.json: for example hot-path is* guards, mirrors in another language, " + "per-package VERSION strings). NOT detected: same-file typed-dispatch overload polymorphism for " + "different argument shapes within one registration — a human still triages TRUE_DUPLICATE " + "entries using the defining files + public flags before merging anything.";
|
|
1376
1376
|
var DUP_ENTRY_TAG_SORT_ORDER = {
|
|
1377
1377
|
TRUE_DUPLICATE: 0,
|
|
1378
1378
|
DISPATCH_VARIANT: 1,
|
|
@@ -2066,13 +2066,55 @@ function tsupConfigEntries(root, pkgDir) {
|
|
|
2066
2066
|
}
|
|
2067
2067
|
return out2;
|
|
2068
2068
|
}
|
|
2069
|
+
function stringEnd(text, start2) {
|
|
2070
|
+
let j = start2 + 1;
|
|
2071
|
+
while (j < text.length && text.charAt(j) !== '"')
|
|
2072
|
+
j += text.charAt(j) === "\\" ? 2 : 1;
|
|
2073
|
+
return Math.min(j + 1, text.length);
|
|
2074
|
+
}
|
|
2075
|
+
function stripJsonc(text) {
|
|
2076
|
+
let plain = "";
|
|
2077
|
+
for (let i2 = 0;i2 < text.length; ) {
|
|
2078
|
+
const c = text.charAt(i2);
|
|
2079
|
+
if (c === '"') {
|
|
2080
|
+
const end = stringEnd(text, i2);
|
|
2081
|
+
plain += text.slice(i2, end);
|
|
2082
|
+
i2 = end;
|
|
2083
|
+
} else if (c === "/" && text.charAt(i2 + 1) === "/") {
|
|
2084
|
+
while (i2 < text.length && text.charAt(i2) !== `
|
|
2085
|
+
`)
|
|
2086
|
+
i2++;
|
|
2087
|
+
} else if (c === "/" && text.charAt(i2 + 1) === "*") {
|
|
2088
|
+
const end = text.indexOf("*/", i2 + 2);
|
|
2089
|
+
i2 = end === -1 ? text.length : end + 2;
|
|
2090
|
+
} else {
|
|
2091
|
+
plain += c;
|
|
2092
|
+
i2++;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
let out2 = "";
|
|
2096
|
+
for (let i2 = 0;i2 < plain.length; ) {
|
|
2097
|
+
const c = plain.charAt(i2);
|
|
2098
|
+
if (c === '"') {
|
|
2099
|
+
const end = stringEnd(plain, i2);
|
|
2100
|
+
out2 += plain.slice(i2, end);
|
|
2101
|
+
i2 = end;
|
|
2102
|
+
} else if (c === "," && /^\s*[}\]]/.test(plain.slice(i2 + 1))) {
|
|
2103
|
+
i2++;
|
|
2104
|
+
} else {
|
|
2105
|
+
out2 += c;
|
|
2106
|
+
i2++;
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
return out2;
|
|
2110
|
+
}
|
|
2069
2111
|
function seedTsconfigEntries(root, pkgDir, cfgRel, add) {
|
|
2070
2112
|
const cfgPath = join7(root, pkgDir, cfgRel);
|
|
2071
2113
|
if (!existsSync4(cfgPath))
|
|
2072
2114
|
return;
|
|
2073
2115
|
let cfg;
|
|
2074
2116
|
try {
|
|
2075
|
-
cfg = JSON.parse(readFileSync3(cfgPath, "utf-8"));
|
|
2117
|
+
cfg = JSON.parse(stripJsonc(readFileSync3(cfgPath, "utf-8")));
|
|
2076
2118
|
} catch {
|
|
2077
2119
|
return;
|
|
2078
2120
|
}
|
|
@@ -2226,6 +2268,8 @@ function selfPackage(root) {
|
|
|
2226
2268
|
entryFiles: packageEntryFiles(root, pkg)
|
|
2227
2269
|
};
|
|
2228
2270
|
}
|
|
2271
|
+
var CONFIG_ENTRY_KEY = /\b(?:entry|input|setupFiles|globalSetup|globalTeardown)["']?\s*:\s*(\[[^\]]*\]|\{[^}]*\}|[\w$.]+\([^)]*\)|['"`][^'"`]*['"`])/g;
|
|
2272
|
+
var SOURCE_LITERAL = /['"`]([^'"`]+\.[cm]?[jt]sx?)['"`]/g;
|
|
2229
2273
|
function configReferencedEntries(root) {
|
|
2230
2274
|
const out2 = new Set;
|
|
2231
2275
|
let names;
|
|
@@ -2247,9 +2291,36 @@ function configReferencedEntries(root) {
|
|
|
2247
2291
|
for (const m of code.matchAll(/new\s+URL\(\s*['"`]([^'"`]*?src\/[\w./-]+\.ts)['"`]/g)) {
|
|
2248
2292
|
out2.add((m[1] ?? "").replace(/^\.\//, ""));
|
|
2249
2293
|
}
|
|
2294
|
+
for (const key of code.matchAll(CONFIG_ENTRY_KEY)) {
|
|
2295
|
+
for (const lit of (key[1] ?? "").matchAll(SOURCE_LITERAL)) {
|
|
2296
|
+
out2.add(toPosix(lit[1] ?? "").replace(/^\.\//, ""));
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2250
2299
|
}
|
|
2251
2300
|
return [...out2];
|
|
2252
2301
|
}
|
|
2302
|
+
function htmlReferencedEntries(root) {
|
|
2303
|
+
const out2 = [];
|
|
2304
|
+
for (const page of ["index.html", "src/index.html"]) {
|
|
2305
|
+
let html;
|
|
2306
|
+
try {
|
|
2307
|
+
html = readFileSync3(join7(root, page), "utf-8");
|
|
2308
|
+
} catch {
|
|
2309
|
+
continue;
|
|
2310
|
+
}
|
|
2311
|
+
for (const m of html.matchAll(/<script\b[^>]*?\bsrc\s*=\s*["']([^"']+)["']/gi)) {
|
|
2312
|
+
const src = m[1] ?? "";
|
|
2313
|
+
if (/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(src) || !/\.[cm]?[jt]sx?$/.test(src))
|
|
2314
|
+
continue;
|
|
2315
|
+
const fromPage = toPosix(join7(dirname4(page), src)).replace(/^\.\//, "");
|
|
2316
|
+
const candidates = src.startsWith("/") ? [src.slice(1), fromPage] : [fromPage];
|
|
2317
|
+
const found = candidates.find((c) => existsSync4(join7(root, c)));
|
|
2318
|
+
if (found !== undefined && !out2.includes(found))
|
|
2319
|
+
out2.push(found);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
return out2;
|
|
2323
|
+
}
|
|
2253
2324
|
function runtimeLaunchedEntries(root, parsed) {
|
|
2254
2325
|
const known = new Set(parsed.map((f) => f.path));
|
|
2255
2326
|
const out2 = new Set;
|
|
@@ -6307,7 +6378,7 @@ function classifyArea(relPath) {
|
|
|
6307
6378
|
}
|
|
6308
6379
|
if (CONFIG_PATTERN.test(relPath))
|
|
6309
6380
|
return "config";
|
|
6310
|
-
if (isTestFile || /(^|\/)tests
|
|
6381
|
+
if (isTestFile || /(^|\/)tests?\//.test(relPath))
|
|
6311
6382
|
return "tests";
|
|
6312
6383
|
if (/^(bench|benchmarks)\//.test(relPath) || /\.bench\.\w+$/.test(relPath))
|
|
6313
6384
|
return "benchmarks";
|
|
@@ -12364,7 +12435,7 @@ function packageJsonRoots(root, known) {
|
|
|
12364
12435
|
continue;
|
|
12365
12436
|
const mapped = mapDistToSrc(spec, known) ?? launcherEntry(root, spec, known) ?? declaredSource(spec, known);
|
|
12366
12437
|
if (mapped === null) {
|
|
12367
|
-
warnings.push(`package.json entry ${pyRepr(spec)} did not resolve to a known source file
|
|
12438
|
+
warnings.push(`package.json entry ${pyRepr(spec)} did not resolve to a known source file. The entry is ignored.`);
|
|
12368
12439
|
continue;
|
|
12369
12440
|
}
|
|
12370
12441
|
if (!roots.includes(mapped))
|
|
@@ -12513,7 +12584,8 @@ function findRoots(root, known, language) {
|
|
|
12513
12584
|
return rustRoots(known);
|
|
12514
12585
|
const [rootRoots, rootWarnings] = packageJsonRoots(root, known);
|
|
12515
12586
|
const [wsRoots, wsWarnings] = workspaceRoots(root, known);
|
|
12516
|
-
const
|
|
12587
|
+
const scriptRoots = detectWorkspaces(root).size === 0 ? rootPackageEntries(root).filter((e) => known.has(e)) : [];
|
|
12588
|
+
const roots = [...new Set([...rootRoots, ...wsRoots, ...scriptRoots])];
|
|
12517
12589
|
const warnings = [...rootWarnings, ...wsWarnings];
|
|
12518
12590
|
if (roots.length > 0)
|
|
12519
12591
|
return [roots, warnings];
|
|
@@ -12689,7 +12761,7 @@ async function buildGraph(root) {
|
|
|
12689
12761
|
const [declaredRoots, rootWarnings] = findRoots(root, known, language);
|
|
12690
12762
|
const roots = [...declaredRoots];
|
|
12691
12763
|
if (language === "typescript") {
|
|
12692
|
-
for (const entry of configReferencedEntries(root)) {
|
|
12764
|
+
for (const entry of [...configReferencedEntries(root), ...htmlReferencedEntries(root)]) {
|
|
12693
12765
|
if (known.has(entry) && !roots.includes(entry))
|
|
12694
12766
|
roots.push(entry);
|
|
12695
12767
|
}
|
|
@@ -13559,7 +13631,7 @@ function generateTestCoverageMarkdown(coverage, options = {}) {
|
|
|
13559
13631
|
lines.push("");
|
|
13560
13632
|
lines.push(...basisNote);
|
|
13561
13633
|
const policyPath = options.policyPath ?? "docs/architecture/coverage-policy.json";
|
|
13562
|
-
lines.push("> The raw figure counts every source file the
|
|
13634
|
+
lines.push("> The raw figure counts every source file the map finds, including files that no test " + "imports directly by design (for example generated code, type-only barrels and code in " + `another language). The **effective** figure excludes the files that \`${policyPath}\` ` + "classifies, so it shows the active code only.");
|
|
13563
13635
|
lines.push("");
|
|
13564
13636
|
lines.push("### Untested-file breakdown by category");
|
|
13565
13637
|
lines.push("");
|
|
@@ -14155,7 +14227,7 @@ function emitTestCoverage(graph, root, outDir, options = {}) {
|
|
|
14155
14227
|
const jsonPath = join16(outDir, "test-coverage.json");
|
|
14156
14228
|
const namespaceImportBasis = !importsNameSymbols(graph.language);
|
|
14157
14229
|
const markdown = generateTestCoverageMarkdown(coverage, {
|
|
14158
|
-
expectedTestHint: graph.language === "typescript",
|
|
14230
|
+
expectedTestHint: graph.language === "typescript" && tests.some((t) => t.path.startsWith("tests/unit/")),
|
|
14159
14231
|
policyPath: options.policyNote ?? "docs/architecture/coverage-policy.json",
|
|
14160
14232
|
namespaceImportBasis
|
|
14161
14233
|
});
|
|
@@ -14215,17 +14287,14 @@ function generateDuplicateSymbolsMarkdown(report) {
|
|
|
14215
14287
|
md += "Each name carries one tag (see `DupEntryTag`), so the actionable subset is clear:\n\n";
|
|
14216
14288
|
md += "- `TRUE_DUPLICATE`: a real merge target.\n";
|
|
14217
14289
|
md += "- `DISPATCH_VARIANT`: two or more `mathTyped(...)` registrations of the same public name. ";
|
|
14218
|
-
md +=
|
|
14219
|
-
md += `not copy-paste bodies.
|
|
14290
|
+
md += `The registrations are distinct dispatch surfaces, not copy-paste bodies.
|
|
14220
14291
|
`;
|
|
14221
14292
|
md += "- `ALIAS_DELEGATION`: a `const X = importedY` forward. ";
|
|
14222
14293
|
md += `The entry is excluded once fewer than two real bodies remain.
|
|
14223
14294
|
`;
|
|
14224
14295
|
md += "- `ALLOWLISTED`: the name matches `duplicate-allowlist.json`. ";
|
|
14225
|
-
md += "Examples are hot-path `is*` guards,
|
|
14226
|
-
md += `strings
|
|
14227
|
-
|
|
14228
|
-
`;
|
|
14296
|
+
md += "Examples are hot-path `is*` guards, mirrors in another language and per-package ";
|
|
14297
|
+
md += "`VERSION` strings.\n\n";
|
|
14229
14298
|
md += `> **Note:** ${report.note}
|
|
14230
14299
|
|
|
14231
14300
|
`;
|
|
@@ -14241,7 +14310,7 @@ function generateDuplicateSymbolsMarkdown(report) {
|
|
|
14241
14310
|
|
|
14242
14311
|
`;
|
|
14243
14312
|
md += renderTaggedSection("TRUE_DUPLICATE — actionable merge targets", report.runtime, "TRUE_DUPLICATE");
|
|
14244
|
-
md += renderTaggedSection("DISPATCH_VARIANT — distinct public typed-dispatch surfaces
|
|
14313
|
+
md += renderTaggedSection("DISPATCH_VARIANT — distinct public typed-dispatch surfaces", report.runtime, "DISPATCH_VARIANT");
|
|
14245
14314
|
md += renderTaggedSection("ALIAS_DELEGATION — const-alias forwards (not independent bodies)", report.runtime, "ALIAS_DELEGATION");
|
|
14246
14315
|
md += renderTaggedSection("ALLOWLISTED — accepted layering (see duplicate-allowlist.json)", report.runtime, "ALLOWLISTED");
|
|
14247
14316
|
md += `## Type duplicates (lower priority)
|
|
@@ -14260,7 +14329,7 @@ var DISPOSITION_LEGEND = [
|
|
|
14260
14329
|
["build-entry", "A `src`-area file that is an entry root."],
|
|
14261
14330
|
["test-only", "A `src`-area file that only a test reaches."],
|
|
14262
14331
|
["orphan", "A `src`-area file that nothing reaches. Delete it, or wire it to a root."],
|
|
14263
|
-
["test", "A file in a `tests/` folder, or a `*.test.ts` or `*.spec.ts` file."],
|
|
14332
|
+
["test", "A file in a `test/` or `tests/` folder, or a `*.test.ts` or `*.spec.ts` file."],
|
|
14264
14333
|
["tool", "A file in a `tools/` or `scripts/` folder outside `src/`."],
|
|
14265
14334
|
["config", "A `*.config.*` file of TypeScript or JavaScript."],
|
|
14266
14335
|
["example", "A file in `examples/` or `docs/`."],
|
|
@@ -19903,8 +19972,8 @@ identifiers are not checked. A file whose first five lines hold
|
|
|
19903
19972
|
--help, -h Show this help.
|
|
19904
19973
|
|
|
19905
19974
|
Exit codes: 0 when no finding (Markdown mode) or always (--prose mode). 1 when a
|
|
19906
|
-
Markdown finding exists. 2 on a usage error, when
|
|
19907
|
-
or when a file is not UTF-8.
|
|
19975
|
+
Markdown finding exists. 2 on a usage error, when a path does not exist, when no
|
|
19976
|
+
Markdown file was examined, or when a file is not UTF-8.
|
|
19908
19977
|
`;
|
|
19909
19978
|
var HISTORICAL_MARKER = "<!-- ste:historical-record -->";
|
|
19910
19979
|
function readText(path) {
|
|
@@ -19988,7 +20057,10 @@ async function run7(argv, io) {
|
|
|
19988
20057
|
let total = 0;
|
|
19989
20058
|
let checked = 0;
|
|
19990
20059
|
let skipped = 0;
|
|
20060
|
+
const missing = [];
|
|
19991
20061
|
for (const arg of argv) {
|
|
20062
|
+
if (!existsSync13(arg))
|
|
20063
|
+
missing.push(arg);
|
|
19992
20064
|
for (const target of targetsFor(arg)) {
|
|
19993
20065
|
const name2 = basename10(target);
|
|
19994
20066
|
if (isHistoricalRecord(target)) {
|
|
@@ -20021,12 +20093,16 @@ async function run7(argv, io) {
|
|
|
20021
20093
|
const tail = skipped > 0 ? `; ${skipped} skipped as historical record(s)` : "";
|
|
20022
20094
|
io.stdout(`
|
|
20023
20095
|
TOTAL: ${total} problem(s) in ${checked} file(s)${tail}
|
|
20096
|
+
`);
|
|
20097
|
+
for (const path of missing)
|
|
20098
|
+
io.stderr(`ERROR: path does not exist: ${path}
|
|
20024
20099
|
`);
|
|
20025
20100
|
if (checked === 0) {
|
|
20026
20101
|
io.stderr(`ERROR: no Markdown file was examined. This is a failure, not a clean result -- check the path(s) given.
|
|
20027
20102
|
`);
|
|
20028
|
-
return 2;
|
|
20029
20103
|
}
|
|
20104
|
+
if (missing.length > 0 || checked === 0)
|
|
20105
|
+
return 2;
|
|
20030
20106
|
return total > 0 ? 1 : 0;
|
|
20031
20107
|
}
|
|
20032
20108
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielsimonjr/repo-tools",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.7",
|
|
4
4
|
"description": "One CLI for repository analysis: dependency graphs creation and query with per-export API facts, file chunking, and context compression. TypeScript on Bun, compiled to a single executable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|