@danielsimonjr/repo-tools 2.2.1 → 2.2.2
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 +2 -2
- package/dist/cli.js +101 -8
- 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.2] - 2026-10-15
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- The workflows pin three GitHub Actions to a newer release: `actions/upload-artifact` v7.0.1 to v7.0.2 (in `ci.yml` and
|
|
14
|
+
`build.yml`), `actions/download-artifact` v8.0.1 to v8.0.2 (in `build.yml`) and `actions/setup-node` v7.0.0 to v7.1.0 (in
|
|
15
|
+
`ci.yml`). Each pin is the commit of the upstream release tag. `build.yml` runs only on a `v*` tag, so the next release
|
|
16
|
+
build is the first run of the new `download-artifact` pin.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- `repo-tools docs` reads a `.tsx` or `.jsx` file that has a bare `&` in JSX text (`<h3>Review & Start</h3>`).
|
|
21
|
+
React and `tsc` accept the text, and the grammar gave an error node, so the file was an unparsed file and its
|
|
22
|
+
symbols were not measured. The analyser now writes a space over a `&` that is the first character of an error
|
|
23
|
+
node directly inside a JSX element, which keeps the length, and parses again. Any other error stays an error.
|
|
24
|
+
A real syntax error beside such a text is still reported. In one application repository four files moved from
|
|
25
|
+
unparsed to measured, and two files with `import()` type expressions stay unparsed.
|
|
26
|
+
- `repo-tools docs check` reads the documentation of an overload set from its first overload. Before, the analyser read only
|
|
27
|
+
the comment that directly precedes a declaration, so an implementation signature that follows overload signatures counted
|
|
28
|
+
as undocumented (M1), although a caller sees only the overloads. A repository then needed a comment that no reader sees.
|
|
29
|
+
The implementation signature now takes the doc of the first overload of the same name, in a function set and in a class
|
|
30
|
+
member set. A doc that directly precedes the implementation still wins. A statement between the overloads and the
|
|
31
|
+
implementation ends the set. The `;` that ends a member signature in a class body does not end the set.
|
|
32
|
+
Rule M3 still compares the documented parameters with the implementation.
|
|
33
|
+
- `repo-tools docs` reads a file that has an `import("m")` type expression (`let v: import("fs").Dirent[]` and
|
|
34
|
+
`f<typeof import("m")>()`). `tsc` accepts both. The grammar reads the call as a member expression of a value, so it
|
|
35
|
+
cannot take `[]` after it, and it reads the call in a type argument as a comparison. Both gave error nodes, so the
|
|
36
|
+
file was an unparsed file. When the first parse has an error, the analyser now writes an identifier of equal length
|
|
37
|
+
over each `import("m")` call that holds a string literal, keeps its line breaks, and parses again. A file that
|
|
38
|
+
parses is never rewritten, and any other error stays an error. In the application repository of the earlier entry
|
|
39
|
+
the last two unparsed files move to measured.
|
|
40
|
+
- Two fan-out tests (`map-graph.test.ts` and `map-query.test.ts`) have an explicit 30 s timeout. Each builds a graph of about
|
|
41
|
+
9,000 nodes. The graph test took 0.85 s on a fast machine and 4.57 s on a slower one, against bun's 5 s default, so it
|
|
42
|
+
failed there under any load. The tests check a step bound, not time, so only the timeout changes. A comment on each test records the measurement and
|
|
43
|
+
names no machine, because the privacy check rejects machine names.
|
|
44
|
+
- The privacy check accepts one finding in the history: the squash commit of #18 (`46a45d4c19af`) carries a
|
|
45
|
+
`Co-authored-by` trailer that GitHub added for the maintainer identity on the pull request branch, at line 53 of the
|
|
46
|
+
message. A commit message cannot change after a merge, so `scripts/privacy-accepted.txt` holds the entry, as it does
|
|
47
|
+
for `fc930a32f5d2`. Before, the `privacy` job and the test `this repository scans clean` failed on `main` after the
|
|
48
|
+
merge, although the pull request was green. A squash whose commits are all by the pull request opener adds no trailer.
|
|
49
|
+
- `repo-tools docs` keeps the doc of a declaration when a tool directive stands between the doc comment and the
|
|
50
|
+
declaration (`// eslint-disable-next-line`, `// @ts-expect-error`, `// prettier-ignore`, `// biome-ignore` and the
|
|
51
|
+
other directives of a closed list). Before, the directive hid the doc and the symbol counted as undocumented (M1),
|
|
52
|
+
although a directive applies to the next line and so must stay directly above the declaration; a React repository
|
|
53
|
+
with the `react-refresh` lint rule had four such hooks and components. A plain line comment can move, so it still
|
|
54
|
+
separates a doc comment from its declaration. `docs stub` also writes
|
|
55
|
+
a new block above the directive and not between the directive and the declaration, where the directive would apply
|
|
56
|
+
to the block.
|
|
57
|
+
|
|
9
58
|
## [2.2.1] - 2026-10-08
|
|
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.2.
|
|
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.2):
|
|
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.2",
|
|
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",
|
|
@@ -18208,13 +18208,60 @@ function anchorOf(node) {
|
|
|
18208
18208
|
target = target.parent;
|
|
18209
18209
|
return target;
|
|
18210
18210
|
}
|
|
18211
|
-
|
|
18212
|
-
|
|
18211
|
+
var DIRECTIVE = new RegExp(`^//${SPACE_CLASS}*(?:eslint-(?:disable|enable)(?:-next-line|-line)?|@ts-(?:ignore|expect-error|nocheck|check)|` + "prettier-ignore|biome-ignore|oxlint-disable|deno-lint-ignore|tslint:(?:disable|enable)|" + `(?:istanbul|c8|v8)${SPACE_CLASS}+ignore)(?![\\w-])`);
|
|
18212
|
+
function isDirective(node, text) {
|
|
18213
|
+
return node.type === "comment" && DIRECTIVE.test(text(node));
|
|
18214
|
+
}
|
|
18215
|
+
function docBefore(anchor, text) {
|
|
18216
|
+
let prev = anchor.previousSibling;
|
|
18217
|
+
while (prev && isDirective(prev, text))
|
|
18218
|
+
prev = prev.previousSibling;
|
|
18213
18219
|
if (prev?.type !== "comment")
|
|
18214
18220
|
return "";
|
|
18215
18221
|
const comment = text(prev);
|
|
18216
18222
|
return comment.startsWith("/**") ? comment : "";
|
|
18217
18223
|
}
|
|
18224
|
+
function stubAnchor(anchor, source, text) {
|
|
18225
|
+
let first = anchor;
|
|
18226
|
+
for (let prev = anchor.previousSibling;prev && isDirective(prev, text); ) {
|
|
18227
|
+
if (prev.endPosition.row + 1 < first.startPosition.row)
|
|
18228
|
+
break;
|
|
18229
|
+
const lineStart = source.lastIndexOf(`
|
|
18230
|
+
`, prev.startIndex - 1) + 1;
|
|
18231
|
+
if (source.slice(lineStart, prev.startIndex).trim() !== "")
|
|
18232
|
+
break;
|
|
18233
|
+
first = prev;
|
|
18234
|
+
prev = prev.previousSibling;
|
|
18235
|
+
}
|
|
18236
|
+
return first;
|
|
18237
|
+
}
|
|
18238
|
+
var SIGNATURES = new Set(["function_signature", "method_signature"]);
|
|
18239
|
+
function signatureName(sibling, text) {
|
|
18240
|
+
const inner = sibling.type === "export_statement" ? sibling.childForFieldName("declaration") : sibling;
|
|
18241
|
+
if (!inner || !SIGNATURES.has(inner.type))
|
|
18242
|
+
return null;
|
|
18243
|
+
const name2 = inner.childForFieldName("name");
|
|
18244
|
+
return name2 ? text(name2) : null;
|
|
18245
|
+
}
|
|
18246
|
+
function leadingDoc(anchor, node, text) {
|
|
18247
|
+
const own = docBefore(anchor, text);
|
|
18248
|
+
if (own || node.type !== "function_declaration" && node.type !== "method_definition") {
|
|
18249
|
+
return own;
|
|
18250
|
+
}
|
|
18251
|
+
const name2 = node.childForFieldName("name");
|
|
18252
|
+
if (!name2)
|
|
18253
|
+
return "";
|
|
18254
|
+
const implementation = text(name2);
|
|
18255
|
+
let first = null;
|
|
18256
|
+
for (let sibling = anchor.previousSibling;sibling; sibling = sibling.previousSibling) {
|
|
18257
|
+
if (sibling.type === "comment" || sibling.type === ";")
|
|
18258
|
+
continue;
|
|
18259
|
+
if (signatureName(sibling, text) !== implementation)
|
|
18260
|
+
break;
|
|
18261
|
+
first = sibling;
|
|
18262
|
+
}
|
|
18263
|
+
return first ? docBefore(first, text) : "";
|
|
18264
|
+
}
|
|
18218
18265
|
function isExported2(node) {
|
|
18219
18266
|
let parent = node.parent;
|
|
18220
18267
|
while (parent) {
|
|
@@ -18240,8 +18287,53 @@ function proseOfComment(doc) {
|
|
|
18240
18287
|
return proseOf(lines.join(`
|
|
18241
18288
|
`));
|
|
18242
18289
|
}
|
|
18290
|
+
var JSX_PARENTS = new Set(["jsx_element", "jsx_fragment"]);
|
|
18291
|
+
var MAX_REPAIRS = 16;
|
|
18292
|
+
var IMPORT_CALL = new RegExp(`\\bimport${SPACE_CLASS}*\\(${SPACE_CLASS}*(?:"[^"\\n]*"|'[^'\\n]*')${SPACE_CLASS}*\\)`, "g");
|
|
18293
|
+
function blankImportCalls(text) {
|
|
18294
|
+
return text.replace(IMPORT_CALL, (call) => {
|
|
18295
|
+
let name2 = true;
|
|
18296
|
+
let out2 = "";
|
|
18297
|
+
for (const ch of call) {
|
|
18298
|
+
if (/\s/u.test(ch)) {
|
|
18299
|
+
name2 = false;
|
|
18300
|
+
out2 += ch;
|
|
18301
|
+
} else {
|
|
18302
|
+
out2 += (name2 ? "_" : " ").repeat(ch.length);
|
|
18303
|
+
}
|
|
18304
|
+
}
|
|
18305
|
+
return out2;
|
|
18306
|
+
});
|
|
18307
|
+
}
|
|
18308
|
+
function parseSource(parser, text) {
|
|
18309
|
+
let current = sanitise(text);
|
|
18310
|
+
let tree = parser.parse(current);
|
|
18311
|
+
let importsBlanked = false;
|
|
18312
|
+
for (let pass = 0;tree?.rootNode.hasError && pass < MAX_REPAIRS; pass++) {
|
|
18313
|
+
const marks = [];
|
|
18314
|
+
for (const node of tree.rootNode.descendantsOfType("ERROR")) {
|
|
18315
|
+
const start2 = node.startIndex;
|
|
18316
|
+
if (current[start2] === "&" && node.parent && JSX_PARENTS.has(node.parent.type)) {
|
|
18317
|
+
marks.push(start2);
|
|
18318
|
+
}
|
|
18319
|
+
}
|
|
18320
|
+
let next = current;
|
|
18321
|
+
for (const at of marks)
|
|
18322
|
+
next = `${next.slice(0, at)} ${next.slice(at + 1)}`;
|
|
18323
|
+
if (!importsBlanked) {
|
|
18324
|
+
importsBlanked = true;
|
|
18325
|
+
next = blankImportCalls(next);
|
|
18326
|
+
}
|
|
18327
|
+
if (next === current)
|
|
18328
|
+
break;
|
|
18329
|
+
tree.delete();
|
|
18330
|
+
current = next;
|
|
18331
|
+
tree = parser.parse(current);
|
|
18332
|
+
}
|
|
18333
|
+
return tree;
|
|
18334
|
+
}
|
|
18243
18335
|
function parsesAsTypeScript(path, text) {
|
|
18244
|
-
const tree = parserFor(grammarFor(path))
|
|
18336
|
+
const tree = parseSource(parserFor(grammarFor(path)), text.replace(/^\uFEFF/, ""));
|
|
18245
18337
|
if (!tree)
|
|
18246
18338
|
return false;
|
|
18247
18339
|
try {
|
|
@@ -18254,7 +18346,7 @@ async function analyseTypeScript(path, source) {
|
|
|
18254
18346
|
const report = newReport(path, "typescript");
|
|
18255
18347
|
const grammar = grammarFor(path);
|
|
18256
18348
|
await loadGrammar(grammar);
|
|
18257
|
-
const tree = parserFor(grammar)
|
|
18349
|
+
const tree = parseSource(parserFor(grammar), source);
|
|
18258
18350
|
if (!tree) {
|
|
18259
18351
|
report.error = "parse error (the parser returned no tree)";
|
|
18260
18352
|
return report;
|
|
@@ -18268,7 +18360,8 @@ async function analyseTypeScript(path, source) {
|
|
|
18268
18360
|
for (const node of tree.rootNode.descendantsOfType(DECLARATION_TYPES)) {
|
|
18269
18361
|
const kind = DECLARATIONS[node.type];
|
|
18270
18362
|
const anchor = anchorOf(node);
|
|
18271
|
-
const
|
|
18363
|
+
const lead = stubAnchor(anchor, source, text);
|
|
18364
|
+
const doc = leadingDoc(anchor, node, text);
|
|
18272
18365
|
const dialect = dialectOf(doc);
|
|
18273
18366
|
const typeLike = kind === "class" || kind === "interface" || kind === "type";
|
|
18274
18367
|
const line = node.startPosition.row + 1;
|
|
@@ -18276,8 +18369,8 @@ async function analyseTypeScript(path, source) {
|
|
|
18276
18369
|
const sym = {
|
|
18277
18370
|
file: path,
|
|
18278
18371
|
line,
|
|
18279
|
-
anchorLine:
|
|
18280
|
-
anchorColumn:
|
|
18372
|
+
anchorLine: lead.startPosition.row + 1,
|
|
18373
|
+
anchorColumn: lead.startPosition.column,
|
|
18281
18374
|
name: nameNode ? text(nameNode) : "<anonymous>",
|
|
18282
18375
|
kind,
|
|
18283
18376
|
exported: isExported2(node),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielsimonjr/repo-tools",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
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",
|