@danielsimonjr/repo-tools 2.2.3 → 2.2.5
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 +49 -0
- package/README.md +5 -3
- package/dist/cli.js +64 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,55 @@ All notable changes to this project are recorded in this file. The format follow
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.2.5] - 2026-10-22
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- The C# test-coverage report states its basis. A C# `using` usually names a namespace, so a test covers every file
|
|
14
|
+
that declares the namespace, and a covered file is not proof that a test uses the file. A test in the same namespace,
|
|
15
|
+
or in a nested namespace, needs no `using` and does not count, so the percentage can be too high or too low.
|
|
16
|
+
`TEST_COVERAGE.md` now has a note under the summary table that says "counted by namespace import".
|
|
17
|
+
`test-coverage.json` now has `metadata.coverageBasis` (`namespace-import`) and `metadata.coverageCaveat`. The
|
|
18
|
+
percentage does not change. The reports of TypeScript, Python and Rust have no note and no new key, and the golden
|
|
19
|
+
files do not change.
|
|
20
|
+
`importsNameSymbols` in `src/map/artifacts.ts` is now the one rule for "does an import name a symbol"; the
|
|
21
|
+
unused-analysis caveat and its export classification use it as well.
|
|
22
|
+
- `docs/design.md` passes `repo-tools ste` with 0 problems. The check reported 4 sentences of 31 to 43 words in
|
|
23
|
+
section 16.3. Each of the 4 sentences is now a group of shorter sentences. No fact changes.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- `repo-tools docs` fails on a repository that has more files of a language it cannot read than TypeScript,
|
|
28
|
+
JavaScript and Python together. It printed `PASS -- 0/0 exported symbols documented, 0 MUST issues` and exited 0
|
|
29
|
+
for IronClaw, a Rust repository. `docs check src` measured the 1 JavaScript file below `src` and none of the 247
|
|
30
|
+
Rust files. `scan`, `check` and `stub` now exit 1 and print
|
|
31
|
+
`this repo is rust: 247 rust file(s) against 1 TypeScript, JavaScript or Python file(s)`. `map` already refused
|
|
32
|
+
such a repository. `docs` uses the file walk of `map`, so both commands give a repository the same language. A tie
|
|
33
|
+
is measured. A TypeScript repository with a few Rust files is measured as before. A repository of Go files only
|
|
34
|
+
now names Go. It said before that it found no source file.
|
|
35
|
+
|
|
36
|
+
## [2.2.4] - 2026-10-19
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- `repo-tools map` and `repo-tools docs` read a `.js`, `.mjs` or `.cjs` file with the TSX grammar. These files used
|
|
41
|
+
the TypeScript grammar, which cannot read JSX. A JavaScript file that holds JSX then gave error nodes, and a
|
|
42
|
+
`docs` run counted the file as unparsed. A JavaScript file cannot hold an angle-bracket type assertion, which
|
|
43
|
+
TSX cannot read. The measurement used 2446 tracked JavaScript files in 87 repositories. It skipped build-output
|
|
44
|
+
and vendor folders, minified files and files over 1.5 MB. The TSX grammar added no error node to any file. It
|
|
45
|
+
removed the error nodes of the one file that held JSX. No export count changed. A `.ts` file keeps the
|
|
46
|
+
TypeScript grammar.
|
|
47
|
+
|
|
48
|
+
- `repo-tools map` writes `duplicate-symbols.md` and `unused-analysis.md` with text that passes `repo-tools ste`. A
|
|
49
|
+
TypeScript repository got a 70-word introduction in `duplicate-symbols.md`. `unused-analysis.md` held caveat
|
|
50
|
+
sentences of 28 and 44 words and an ambiguous "This is". For C#, it held four more findings (three long sentences
|
|
51
|
+
and one ambiguous reference), and for Rust one long sentence. A hand edit of a generated report is lost at the
|
|
52
|
+
next run, so the generator text had to change. The introduction of `duplicate-symbols.md` is now three short
|
|
53
|
+
sentences and a list of the four tags. Each long caveat is split into short sentences. No fact changed, and no
|
|
54
|
+
opt-out marker is added. The new test `map-reports-ste.test.ts` maps a TypeScript, a C#, a Rust and a Python
|
|
55
|
+
repository and expects no STE finding in either report. A repository that commits these reports sees a one-time
|
|
56
|
+
diff at its next `repo-tools map`.
|
|
57
|
+
|
|
9
58
|
## [2.2.3] - 2026-10-16
|
|
10
59
|
|
|
11
60
|
### Fixed
|
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.5.
|
|
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.5):
|
|
45
45
|
|
|
46
46
|
| Platform | File |
|
|
47
47
|
|---|---|
|
|
@@ -238,7 +238,9 @@ The rules are:
|
|
|
238
238
|
| S6 | SHOULD | The prose follows Simplified Technical English (the rules of `repo-tools ste`). |
|
|
239
239
|
|
|
240
240
|
Only a MUST issue changes the exit code of `check`. A file that does not parse is also a failure,
|
|
241
|
-
because an unknown file is not a clean file. A repository with no source file fails too.
|
|
241
|
+
because an unknown file is not a clean file. A repository with no source file fails too. So does a
|
|
242
|
+
repository with more files of another language (Rust or Go, for example) than TypeScript, JavaScript
|
|
243
|
+
and Python together. The command names the language and exits 1.
|
|
242
244
|
|
|
243
245
|
`stub` is a dry run until you pass `--apply`. Each stub holds the marker `TODO:`, so `check` fails
|
|
244
246
|
until you replace the stub with real prose. The command parses a file again after the change.
|
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.5",
|
|
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",
|
|
@@ -10895,8 +10895,9 @@ function loadGrammar(name2) {
|
|
|
10895
10895
|
}
|
|
10896
10896
|
return pending;
|
|
10897
10897
|
}
|
|
10898
|
+
var TSX_SUFFIXES = [".tsx", ".jsx", ".js", ".mjs", ".cjs"];
|
|
10898
10899
|
function grammarFor(path) {
|
|
10899
|
-
return
|
|
10900
|
+
return TSX_SUFFIXES.some((suffix) => path.endsWith(suffix)) ? "tsx" : "typescript";
|
|
10900
10901
|
}
|
|
10901
10902
|
function parserFor(name2) {
|
|
10902
10903
|
const parser = parsers.get(name2);
|
|
@@ -13104,7 +13105,7 @@ var UNUSED_CAVEATS = [
|
|
|
13104
13105
|
"A literal relative `import(...)` is a graph edge. A runtime call is a namespace use (`*`), so the exports of that file count as used. A type-position `import(...).Name` counts only `Name`, and `typeof import(...)` counts none. A dynamic import built from a variable or a template, and other runtime loads (e.g. `new Worker(path)`), are still invisible -- a file or export reached ONLY through one of those is reported as no-importer/unreferenced even though it may be live.",
|
|
13105
13106
|
"`noImporterFiles` is NOT a deletion-candidate list. A file with zero in-repo importers is expected, not suspicious, for: a standalone script invoked directly (e.g. a smoketest run via `node script.mjs`, never `import`ed by anything), or a build/lint config file loaded by its own tool rather than by source code (e.g. `eslint.config.mjs`, read by eslint itself). Cross-check against package.json scripts / tool configs before treating any entry here as dead.",
|
|
13106
13107
|
"Only NAMED exports are analysed (`FileNode.exports` carries named exports only) -- `export default` usage is not checked here.",
|
|
13107
|
-
"The `referencedInModule`
|
|
13108
|
+
"The split of exports into `referencedInModule` and `unreferencedAnywhere` is a TEXT-LEVEL heuristic. The analysis counts whole-identifier occurrences in the source of the defining file, minus the declaration site itself. The count is not an AST reference count. The analysis can over-count a name that also appears in a string literal or comment. When the source text cannot be read (no `RepoGraph.root_path`, or the file is missing), the export lands in `unclassifiedExports`. The analysis does not guess a bucket for it.",
|
|
13108
13109
|
"`unreferencedAnywhereNotes`'s dynamic-import check (`_dynamic_import_referrers`) only sees `import(...)` calls with a LITERAL string specifier. A dynamic import built from a variable or template literal (e.g. `import(`./cmds/${name}.js`)`, a command-dispatcher pattern) is invisible to it -- 'found none' in a note means no LITERAL match was found, NOT that nothing imports the file."
|
|
13109
13110
|
];
|
|
13110
13111
|
var IMPORTS_NAME_SYMBOLS = {
|
|
@@ -13113,9 +13114,12 @@ var IMPORTS_NAME_SYMBOLS = {
|
|
|
13113
13114
|
csharp: false,
|
|
13114
13115
|
rust: true
|
|
13115
13116
|
};
|
|
13117
|
+
function importsNameSymbols(language) {
|
|
13118
|
+
return IMPORTS_NAME_SYMBOLS[language] ?? true;
|
|
13119
|
+
}
|
|
13116
13120
|
var PUBLIC_API_LANGUAGES = new Set(["rust"]);
|
|
13117
|
-
var PUBLIC_API_CAVEAT = "A `pub` item with no user inside this crate is normally PUBLIC API, not dead code. `unused-analysis`
|
|
13118
|
-
var NAMESPACE_IMPORT_CAVEAT = "
|
|
13121
|
+
var PUBLIC_API_CAVEAT = "A `pub` item with no user inside this crate is normally PUBLIC API, not dead code. `unused-analysis` sees only the repository. A library crate's public surface exists for DOWNSTREAM consumers. These consumers are not in the graph. Therefore, 'no importer here' is the expected state for most public items. The state is not a finding. Measured on one real crate: 2,635 of 2,739 exports (96%) had no in-crate user, and essentially all of them were live API. Treat this list as 'candidates to check against the crate's intended surface', never as a deletion list.";
|
|
13122
|
+
var NAMESPACE_IMPORT_CAVEAT = "In this language, an import names a namespace, not the symbols that it brings in (C#'s `using App.Hosting;`). The import edges therefore cannot show the use of one symbol. Usage here is a whole-identifier text search across every scanned file instead. The search is the same class of TEXT-LEVEL heuristic as the `referencedInModule` split above. The limit is the same: a name in the comment or string literal of another file counts as a use. The search is conservative. It UNDER-reports dead code and never invents it. That direction is safe for a list whose entries read as deletion candidates. Neither the import edges nor the text search can see a type that only reflection reaches (`Activator.CreateInstance`, DI-by-convention) or that only a .csproj/XAML file names.";
|
|
13119
13123
|
var IDENTIFIER = new RegExp(`${B}[A-Za-z_]${W}*`, "gu");
|
|
13120
13124
|
function readSourceText(rootPath, rel) {
|
|
13121
13125
|
if (rootPath === null)
|
|
@@ -13143,7 +13147,7 @@ function identifierUsers(graph) {
|
|
|
13143
13147
|
}
|
|
13144
13148
|
function caveatsFor(graph) {
|
|
13145
13149
|
const caveats = [...UNUSED_CAVEATS];
|
|
13146
|
-
if (!(
|
|
13150
|
+
if (!importsNameSymbols(graph.language))
|
|
13147
13151
|
caveats.push(NAMESPACE_IMPORT_CAVEAT);
|
|
13148
13152
|
if (PUBLIC_API_LANGUAGES.has(graph.language))
|
|
13149
13153
|
caveats.push(PUBLIC_API_CAVEAT);
|
|
@@ -13184,7 +13188,7 @@ function classifyUnusedExports(graph) {
|
|
|
13184
13188
|
const unreferenced = {};
|
|
13185
13189
|
const referencedInModule = {};
|
|
13186
13190
|
const unclassified = {};
|
|
13187
|
-
const namesSymbols =
|
|
13191
|
+
const namesSymbols = importsNameSymbols(graph.language);
|
|
13188
13192
|
const users = namesSymbols ? new Map : identifierUsers(graph);
|
|
13189
13193
|
const push = (bucket, path, name2) => {
|
|
13190
13194
|
const list = bucket[path] ?? [];
|
|
@@ -13529,6 +13533,8 @@ import { basename as basename5 } from "node:path";
|
|
|
13529
13533
|
function percent(tested, total) {
|
|
13530
13534
|
return total > 0 ? (tested / total * 100).toFixed(1) : "0";
|
|
13531
13535
|
}
|
|
13536
|
+
var NAMESPACE_IMPORT_BASIS = "namespace-import";
|
|
13537
|
+
var NAMESPACE_IMPORT_COVERAGE_CAVEAT = "Coverage is counted by namespace import. A C# `using` directive usually names a namespace, not a type, so a test covers every file that declares the namespace. A namespace import does not show that a test uses the file. A test in the same namespace, or in a nested namespace, needs no `using` and does not count. The percentage can be too high or too low.";
|
|
13532
13538
|
function generateTestCoverageMarkdown(coverage, options = {}) {
|
|
13533
13539
|
const hint = options.expectedTestHint ?? true;
|
|
13534
13540
|
const lines = [];
|
|
@@ -13547,9 +13553,11 @@ function generateTestCoverageMarkdown(coverage, options = {}) {
|
|
|
13547
13553
|
lines.push(`| Source Files without Tests | ${totalUntested} |`);
|
|
13548
13554
|
lines.push(`| Coverage (raw, direct-import) | **${percent(totalTested, totalSource)}%** |`);
|
|
13549
13555
|
const b = coverage.policyBreakdown;
|
|
13556
|
+
const basisNote = options.namespaceImportBasis ? [`> ${NAMESPACE_IMPORT_COVERAGE_CAVEAT}`, ""] : [];
|
|
13550
13557
|
if (coverage.policy) {
|
|
13551
13558
|
lines.push(`| Coverage (effective, active code only) | **${b.effectivePercent}%** (${b.testedActive} / ${b.activeFiles}) |`);
|
|
13552
13559
|
lines.push("");
|
|
13560
|
+
lines.push(...basisNote);
|
|
13553
13561
|
const policyPath = options.policyPath ?? "docs/architecture/coverage-policy.json";
|
|
13554
13562
|
lines.push("> The raw figure counts every source file the CDG tool finds, including code that is " + "intentionally not direct-imported by a vitest `*.test.ts` (synced mathjs categories, " + "AssemblyScript sources, type-only barrels, …). The **effective** figure excludes those " + `per \`${policyPath}\` so the number reflects the genuinely-active hand-written code only. ` + "See [`COVERAGE_POLICY.md`](./COVERAGE_POLICY.md) for the policy.");
|
|
13555
13563
|
lines.push("");
|
|
@@ -13565,6 +13573,8 @@ function generateTestCoverageMarkdown(coverage, options = {}) {
|
|
|
13565
13573
|
}
|
|
13566
13574
|
lines.push(`| **Active (real gap — needs a test)** | ${b.byCategory.active_untested ?? 0} | These are the files that should grow a direct-import test. |`);
|
|
13567
13575
|
lines.push("");
|
|
13576
|
+
} else if (basisNote.length > 0) {
|
|
13577
|
+
lines.push("", ...basisNote);
|
|
13568
13578
|
}
|
|
13569
13579
|
lines.push("---");
|
|
13570
13580
|
lines.push("");
|
|
@@ -13620,7 +13630,7 @@ function generateTestCoverageMarkdown(coverage, options = {}) {
|
|
|
13620
13630
|
return lines.join(`
|
|
13621
13631
|
`);
|
|
13622
13632
|
}
|
|
13623
|
-
function generateTestCoverageJson(coverage) {
|
|
13633
|
+
function generateTestCoverageJson(coverage, options = {}) {
|
|
13624
13634
|
const coverageMapObj = {};
|
|
13625
13635
|
for (const [source, tests] of coverage.coverageMap)
|
|
13626
13636
|
coverageMapObj[source] = tests;
|
|
@@ -13635,6 +13645,10 @@ function generateTestCoverageJson(coverage) {
|
|
|
13635
13645
|
testedCount: coverage.testedFiles.length,
|
|
13636
13646
|
untestedCount: coverage.untestedFiles.length,
|
|
13637
13647
|
coveragePercent: percent(coverage.testedFiles.length, coverage.sourceFiles.length),
|
|
13648
|
+
...options.namespaceImportBasis ? {
|
|
13649
|
+
coverageBasis: NAMESPACE_IMPORT_BASIS,
|
|
13650
|
+
coverageCaveat: NAMESPACE_IMPORT_COVERAGE_CAVEAT
|
|
13651
|
+
} : {},
|
|
13638
13652
|
effectiveCoverage: {
|
|
13639
13653
|
policyLoaded: coverage.policy !== null,
|
|
13640
13654
|
activeFiles: b.activeFiles,
|
|
@@ -14139,12 +14153,14 @@ function emitTestCoverage(graph, root, outDir, options = {}) {
|
|
|
14139
14153
|
const coverage = analyzeTestCoverage(sources, tests, root, options.policyPath ?? join16(root, "docs", "architecture", "coverage-policy.json"));
|
|
14140
14154
|
const mdPath = join16(outDir, "TEST_COVERAGE.md");
|
|
14141
14155
|
const jsonPath = join16(outDir, "test-coverage.json");
|
|
14156
|
+
const namespaceImportBasis = !importsNameSymbols(graph.language);
|
|
14142
14157
|
const markdown = generateTestCoverageMarkdown(coverage, {
|
|
14143
14158
|
expectedTestHint: graph.language === "typescript",
|
|
14144
|
-
policyPath: options.policyNote ?? "docs/architecture/coverage-policy.json"
|
|
14159
|
+
policyPath: options.policyNote ?? "docs/architecture/coverage-policy.json",
|
|
14160
|
+
namespaceImportBasis
|
|
14145
14161
|
});
|
|
14146
14162
|
writeReport(mdPath, withBanner(markdown, { command: MAP_REGENERATE_COMMAND, ...options.banner }));
|
|
14147
|
-
writeReport(jsonPath, JSON.stringify(generateTestCoverageJson(coverage), null, 2));
|
|
14163
|
+
writeReport(jsonPath, JSON.stringify(generateTestCoverageJson(coverage, { namespaceImportBasis }), null, 2));
|
|
14148
14164
|
return [mdPath, jsonPath];
|
|
14149
14165
|
}
|
|
14150
14166
|
|
|
@@ -14194,14 +14210,22 @@ function generateDuplicateSymbolsMarkdown(report) {
|
|
|
14194
14210
|
let md = `# Duplicate Symbols
|
|
14195
14211
|
|
|
14196
14212
|
`;
|
|
14197
|
-
md += "
|
|
14198
|
-
md += "
|
|
14199
|
-
md += "
|
|
14200
|
-
md += "
|
|
14201
|
-
md += "
|
|
14202
|
-
md += "
|
|
14203
|
-
md +=
|
|
14204
|
-
|
|
14213
|
+
md += "A name is listed here when two or more distinct files across the monorepo define it. ";
|
|
14214
|
+
md += "A file that only re-exports the name does not count. ";
|
|
14215
|
+
md += "Each name carries one tag (see `DupEntryTag`), so the actionable subset is clear:\n\n";
|
|
14216
|
+
md += "- `TRUE_DUPLICATE`: a real merge target.\n";
|
|
14217
|
+
md += "- `DISPATCH_VARIANT`: two or more `mathTyped(...)` registrations of the same public name. ";
|
|
14218
|
+
md += "The registrations are distinct dispatch surfaces and Bucket C delegation candidates, ";
|
|
14219
|
+
md += `not copy-paste bodies.
|
|
14220
|
+
`;
|
|
14221
|
+
md += "- `ALIAS_DELEGATION`: a `const X = importedY` forward. ";
|
|
14222
|
+
md += `The entry is excluded once fewer than two real bodies remain.
|
|
14223
|
+
`;
|
|
14224
|
+
md += "- `ALLOWLISTED`: the name matches `duplicate-allowlist.json`. ";
|
|
14225
|
+
md += "Examples are hot-path `is*` guards, AssemblyScript mirrors and per-package `VERSION` ";
|
|
14226
|
+
md += `strings.
|
|
14227
|
+
|
|
14228
|
+
`;
|
|
14205
14229
|
md += `> **Note:** ${report.note}
|
|
14206
14230
|
|
|
14207
14231
|
`;
|
|
@@ -14357,7 +14381,7 @@ function unusedMarkdown(unused, graph) {
|
|
|
14357
14381
|
lines.push("Source files that only a test reaches. They ship nothing, but a test uses them.", "");
|
|
14358
14382
|
bulletList(lines, testOnly);
|
|
14359
14383
|
lines.push("## Files with no in-repo importer", "");
|
|
14360
|
-
lines.push("No file of this repository imports these files.
|
|
14384
|
+
lines.push("No file of this repository imports these files. Do not use the list as a deletion list.", "");
|
|
14361
14385
|
bulletList(lines, unused.noImporterFiles ?? []);
|
|
14362
14386
|
bucket(lines, "Exports unreferenced anywhere", "No other file imports these names, and their own module does not use them.", unused.unreferencedAnywhere ?? {});
|
|
14363
14387
|
const notes = unused.unreferencedAnywhereNotes ?? {};
|
|
@@ -17508,6 +17532,22 @@ class ConfigError extends Error {
|
|
|
17508
17532
|
this.name = "ConfigError";
|
|
17509
17533
|
}
|
|
17510
17534
|
}
|
|
17535
|
+
|
|
17536
|
+
class UnreadableRepoLanguage extends Error {
|
|
17537
|
+
constructor(message) {
|
|
17538
|
+
super(message);
|
|
17539
|
+
this.name = "UnreadableRepoLanguage";
|
|
17540
|
+
}
|
|
17541
|
+
}
|
|
17542
|
+
function assertReadableLanguage(root) {
|
|
17543
|
+
const counts = countLanguages(root);
|
|
17544
|
+
const readable = (counts.typescript ?? 0) + (counts.python ?? 0);
|
|
17545
|
+
const unreadable = Object.entries(counts).filter(([language]) => language !== "typescript" && language !== "python").sort(([a, x], [b, y]) => y - x || (a < b ? -1 : a > b ? 1 : 0));
|
|
17546
|
+
const [language, n] = unreadable[0] ?? ["", 0];
|
|
17547
|
+
if (n > readable) {
|
|
17548
|
+
throw new UnreadableRepoLanguage(`this repo is ${language}: ${n} ${language} file(s) against ${readable} TypeScript, ` + "JavaScript or Python file(s). repo-tools docs reads TypeScript, JavaScript and Python " + "only, so a PASS here would describe the wrong files. It fails rather than print a gate " + "that measured nothing.");
|
|
17549
|
+
}
|
|
17550
|
+
}
|
|
17511
17551
|
function languageOf(path) {
|
|
17512
17552
|
const suffix = suffixOf(path.slice(path.lastIndexOf("/") + 1));
|
|
17513
17553
|
if (PYTHON_SUFFIXES2.has(suffix))
|
|
@@ -18702,7 +18742,9 @@ var DOCS_HELP = `Usage: repo-tools docs scan [root] [--out=<dir>]
|
|
|
18702
18742
|
Measure, stub and gate the documentation comments of the TypeScript, JavaScript
|
|
18703
18743
|
and Python files of a repository. The files are the files that git tracks. A
|
|
18704
18744
|
file in a skipped folder (node_modules, dist, build, bundle, out, vendor) or
|
|
18705
|
-
with a generated name (.d.ts, .min.js, _pb2.py) is not read.
|
|
18745
|
+
with a generated name (.d.ts, .min.js, _pb2.py) is not read. A repository with
|
|
18746
|
+
more files of another language (for example Rust or Go) than TypeScript,
|
|
18747
|
+
JavaScript and Python together is refused: the run names the language and exits 1.
|
|
18706
18748
|
|
|
18707
18749
|
Actions:
|
|
18708
18750
|
scan Measure the coverage. Write COVERAGE.md and coverage.json.
|
|
@@ -19076,6 +19118,7 @@ async function run5(argv, io) {
|
|
|
19076
19118
|
root = resolve8(options.root);
|
|
19077
19119
|
if (!isDirectory(root))
|
|
19078
19120
|
throw new Error("the root <root> is not an existing directory");
|
|
19121
|
+
assertReadableLanguage(root);
|
|
19079
19122
|
if (options.action === "scan")
|
|
19080
19123
|
return await runScan(root, options, io);
|
|
19081
19124
|
if (options.action === "stub")
|
|
@@ -19085,7 +19128,7 @@ async function run5(argv, io) {
|
|
|
19085
19128
|
const message = error instanceof Error ? error.message : String(error);
|
|
19086
19129
|
stderr(`repo-tools docs: ${message}
|
|
19087
19130
|
`);
|
|
19088
|
-
return error instanceof NothingToMeasure ? 1 : 2;
|
|
19131
|
+
return error instanceof NothingToMeasure || error instanceof UnreadableRepoLanguage ? 1 : 2;
|
|
19089
19132
|
}
|
|
19090
19133
|
}
|
|
19091
19134
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielsimonjr/repo-tools",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.5",
|
|
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",
|