pm-ops 2026.7.29 → 2026.8.1
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 +23 -0
- package/dist/docstrings.d.ts +148 -0
- package/dist/docstrings.d.ts.map +1 -0
- package/dist/docstrings.js +1278 -0
- package/dist/docstrings.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +195 -4
- package/dist/index.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +24 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.8.1 - 2026-08-01
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Docstring coverage gate: a lexer-backed, fail-closed documentation gate the fleet can share ([ops-073p](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/features/ops-073p.toon))
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Brace-ending initializers consume following ASI declarations and members ([ops-cqyv](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-cqyv.toon))
|
|
12
|
+
- Prevent symlink cycles during docstring source traversal ([ops-hkxb](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-hkxb.toon))
|
|
13
|
+
- Semicolon-free exported variables consume following declarations ([ops-aun4](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-aun4.toon))
|
|
14
|
+
- Sanitize Node test-runner context before release verification ([ops-hq5u](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-hq5u.toon))
|
|
15
|
+
- The docstrings command writes JSON on the failure path under the default toon format ([ops-k6wq](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-k6wq.toon))
|
|
16
|
+
- Semicolon-free class fields bypass docstring evaluation ([ops-6wen](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-6wen.toon))
|
|
17
|
+
- The docstring gate is fail-open for exported bindings it cannot decompose ([ops-f25k](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/issues/ops-f25k.toon))
|
|
18
|
+
|
|
19
|
+
## 2026.7.31 - 2026-07-31
|
|
20
|
+
|
|
21
|
+
### Other
|
|
22
|
+
|
|
23
|
+
- Expose the analyzer as a pm ops subcommand and a package subpath export ([ops-qvbu](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/tasks/ops-qvbu.toon))
|
|
24
|
+
- Build the lexer-backed docstring analyzer and its negative controls ([ops-w8n4](https://github.com/unbraind/pm-ops/blob/main/.agents/pm/tasks/ops-w8n4.toon))
|
|
25
|
+
|
|
3
26
|
## 2026.7.29 - 2026-07-29
|
|
4
27
|
|
|
5
28
|
### Added
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Lexer-backed docstring coverage analyzer.
|
|
3
|
+
*
|
|
4
|
+
* The fleet mandate requires every source declaration to carry a real
|
|
5
|
+
* docstring, enforced by a gate that cannot be cheated. A naive implementation
|
|
6
|
+
* is worse than none: a green check that proves nothing is active cover for
|
|
7
|
+
* missing documentation. This module is the replacement for a prior regex-based
|
|
8
|
+
* attempt, rebuilt on the one source of truth that distinguishes real syntax
|
|
9
|
+
* from text that merely looks syntactic: the TypeScript token stream.
|
|
10
|
+
*
|
|
11
|
+
* ## Why a lexer, not a regex or the compiler
|
|
12
|
+
*
|
|
13
|
+
* TypeScript 7 removed the stable compiler API (`createSourceFile`,
|
|
14
|
+
* `forEachChild`, …), so there is no AST to walk: `import ts from "typescript"`
|
|
15
|
+
* yields only `{ version }` at run time. What the `typescript/unstable/ast`
|
|
16
|
+
* surface still exposes is the lexer — `createScanner` — which emits exactly
|
|
17
|
+
* the punctuation and keywords that exist in the file. A brace inside a string,
|
|
18
|
+
* template literal, regex, or comment is never a `OpenBraceToken`; a declaration
|
|
19
|
+
* written inside a comment produces no tokens at all. That is precisely the
|
|
20
|
+
* property a brace-counting regex lacks, and it is what makes the rules below
|
|
21
|
+
* trustworthy.
|
|
22
|
+
*
|
|
23
|
+
* The scanner needs two corrections the unstable surface does not apply
|
|
24
|
+
* automatically, both handled in {@link tokenize}:
|
|
25
|
+
*
|
|
26
|
+
* 1. A template substitution `${ … }` emits a `CloseBraceToken` for the `}`
|
|
27
|
+
* without a matching `OpenBraceToken` (the `${` is folded into the
|
|
28
|
+
* `TemplateHead`). Plain brace counting is corrupted by it, exactly as the
|
|
29
|
+
* regex version was corrupted by braces in strings. The fix is to track a
|
|
30
|
+
* frame stack and, only when a `}` closes a substitution frame, call
|
|
31
|
+
* `reScanTemplateToken` so it becomes a `TemplateMiddle` / `TemplateTail`
|
|
32
|
+
* and never reaches the brace counter.
|
|
33
|
+
*
|
|
34
|
+
* 2. The scanner does not decide regex versus division on its own: a `/` is
|
|
35
|
+
* always a `SlashToken`, and `reScanSlashToken` scans a regex
|
|
36
|
+
* unconditionally — which swallows a division operator and everything after
|
|
37
|
+
* it as one unterminated regular expression. The fix is to rescan `/` as a
|
|
38
|
+
* regex only when the previous significant token cannot end an expression,
|
|
39
|
+
* matching the heuristic every JavaScript lexer uses.
|
|
40
|
+
*
|
|
41
|
+
* After that, the token array contains only real, balanced braces, and group
|
|
42
|
+
* matching over it is exact.
|
|
43
|
+
*
|
|
44
|
+
* ## Docstring recovery
|
|
45
|
+
*
|
|
46
|
+
* `getLeadingCommentRanges(text, tokenFullStart)` returns only the comments in
|
|
47
|
+
* the contiguous trivia immediately preceding a token, so a JSDoc block that
|
|
48
|
+
* lives inside a string literal, a template, or a commented-out line is
|
|
49
|
+
* invisible to it — the four classic cheats. JSDoc is a block comment (`kind`
|
|
50
|
+
* `3`) beginning with `/**`; a `//` line comment is `kind` `2` and does not
|
|
51
|
+
* count.
|
|
52
|
+
*
|
|
53
|
+
* ## Rules
|
|
54
|
+
*
|
|
55
|
+
* The documented surface — every symbol {@link judge} evaluates — is:
|
|
56
|
+
*
|
|
57
|
+
* - every exported declaration (`function`, `class`, `interface`, `type`,
|
|
58
|
+
* `const` / `let` / `var`, including `export default function|class`);
|
|
59
|
+
* - every non-`private`, non-`protected`, non-`#` member of an exported class
|
|
60
|
+
* (methods, properties, and `get` / `set` accessors);
|
|
61
|
+
* - every non-exported `function` whose body spans more than
|
|
62
|
+
* {@link INTERNAL_BODY_LINES} lines, implemented (unlike the prior attempt's
|
|
63
|
+
* declared-but-never-read constant).
|
|
64
|
+
*
|
|
65
|
+
* A passing docstring must carry at least {@link MIN_DOC_WORDS} meaningful words
|
|
66
|
+
* after filler removal and contribute at least {@link MIN_NOVEL_WORDS} terms the
|
|
67
|
+
* identifier did not already carry, so a `Gets the name.` JSDoc on `getName`
|
|
68
|
+
* fails.
|
|
69
|
+
*
|
|
70
|
+
* ## Fail-closed
|
|
71
|
+
*
|
|
72
|
+
* A declaration keyword the finder cannot classify is a violation with reason
|
|
73
|
+
* `unrecognized declaration form`, never a silent skip. The silent skip is the
|
|
74
|
+
* cheat this gate exists to prevent.
|
|
75
|
+
*
|
|
76
|
+
* ## Out of scope (structural, not configurable)
|
|
77
|
+
*
|
|
78
|
+
* `.d.ts` ambient declarations, `test/`, `dist/`, and `node_modules` are skipped
|
|
79
|
+
* by hard-coded directory rules; imports and re-export statements (`export { … }
|
|
80
|
+
* from`, `export * from`) declare nothing; `export default <expression>`,
|
|
81
|
+
* overload signatures, constructors, index signatures, computed-name members,
|
|
82
|
+
* `private` / `protected` / `#` members, and anonymous function/arrow
|
|
83
|
+
* expressions carry no stable identifier and are therefore not in the documented
|
|
84
|
+
* surface. There is deliberately no ignore list: an exemption must be a
|
|
85
|
+
* documented rule with a reason, not a configuration entry.
|
|
86
|
+
*/
|
|
87
|
+
/**
|
|
88
|
+
* Minimum number of meaningful words a docstring must contain after filler
|
|
89
|
+
* removal. Below this the comment is too thin to document anything.
|
|
90
|
+
*/
|
|
91
|
+
export declare const MIN_DOC_WORDS = 4;
|
|
92
|
+
/**
|
|
93
|
+
* Minimum number of meaningful words a docstring must contribute that the
|
|
94
|
+
* identifier itself does not already carry. This is what rejects a comment that
|
|
95
|
+
* merely restates the name.
|
|
96
|
+
*/
|
|
97
|
+
export declare const MIN_NOVEL_WORDS = 2;
|
|
98
|
+
/**
|
|
99
|
+
* Number of source lines a non-exported function body must span before it joins
|
|
100
|
+
* the documented surface. Short private helpers stay undocumented; substantial
|
|
101
|
+
* ones must explain themselves.
|
|
102
|
+
*/
|
|
103
|
+
export declare const INTERNAL_BODY_LINES = 4;
|
|
104
|
+
/** A single documentation violation found in one source file. */
|
|
105
|
+
export interface DocstringViolation {
|
|
106
|
+
/** Path of the file, relative to the scanned root. */
|
|
107
|
+
readonly file: string;
|
|
108
|
+
/** 1-based line of the declaration that failed. */
|
|
109
|
+
readonly line: number;
|
|
110
|
+
/** Symbol that failed, e.g. `parseFoo` or `Widget.render`. */
|
|
111
|
+
readonly symbol: string;
|
|
112
|
+
/** Actionable reason naming the rule that failed. */
|
|
113
|
+
readonly reason: string;
|
|
114
|
+
}
|
|
115
|
+
/** Aggregate result of scanning one tree. */
|
|
116
|
+
export interface DocstringReport {
|
|
117
|
+
/** Number of `.ts` files analyzed. */
|
|
118
|
+
readonly files_scanned: number;
|
|
119
|
+
/** Number of declarations evaluated against the rules. */
|
|
120
|
+
readonly declarations_checked: number;
|
|
121
|
+
/** Every violation, in source order. */
|
|
122
|
+
readonly violations: readonly DocstringViolation[];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Result of analyzing a single source text via {@link analyzeSource}: the
|
|
126
|
+
* violations it produced and how many declarations were evaluated.
|
|
127
|
+
*/
|
|
128
|
+
export interface SourceAnalysis {
|
|
129
|
+
/** Violations found in this source. */
|
|
130
|
+
readonly violations: readonly DocstringViolation[];
|
|
131
|
+
/** Declarations evaluated against the rules. */
|
|
132
|
+
readonly declarations: number;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Analyze one already-read TypeScript source text and report the docstring
|
|
136
|
+
* violations it contains plus how many declarations were evaluated.
|
|
137
|
+
*/
|
|
138
|
+
export declare function analyzeSource(text: string, file: string): SourceAnalysis;
|
|
139
|
+
/**
|
|
140
|
+
* Walk a directory tree and analyze every authored `.ts` source beneath it,
|
|
141
|
+
* skipping `.d.ts` files and the structural non-source directories. Scanning
|
|
142
|
+
* zero files fails by throwing rather than passing vacuously.
|
|
143
|
+
*/
|
|
144
|
+
export declare function analyzeDocstringCoverage(options: {
|
|
145
|
+
root: string;
|
|
146
|
+
sourceDirs?: readonly string[];
|
|
147
|
+
}): DocstringReport;
|
|
148
|
+
//# sourceMappingURL=docstrings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docstrings.d.ts","sourceRoot":"","sources":["../docstrings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AAOH;;;GAGG;AACH,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B;;;;GAIG;AACH,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,iEAAiE;AACjE,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACpD;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD,gDAAgD;IAChD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AA2lCD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,CAKxE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,eAAe,CAoBnH"}
|