@descent-vtt/spec-guard 0.10.3 → 0.12.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/CHANGELOG.md +410 -0
- package/README.md +385 -27
- package/dist/cites.d.ts +192 -0
- package/dist/cites.d.ts.map +1 -0
- package/dist/cites.js +599 -0
- package/dist/cites.js.map +1 -0
- package/dist/cli.d.ts +14 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +315 -22
- package/dist/cli.js.map +1 -1
- package/dist/comments.d.ts +51 -2
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +353 -57
- package/dist/comments.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +46 -5
- package/dist/config.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +38 -14
- package/dist/engine.js.map +1 -1
- package/dist/glob.d.ts +128 -24
- package/dist/glob.d.ts.map +1 -1
- package/dist/glob.js +304 -61
- package/dist/glob.js.map +1 -1
- package/dist/impact.d.ts +179 -0
- package/dist/impact.d.ts.map +1 -0
- package/dist/impact.js +360 -0
- package/dist/impact.js.map +1 -0
- package/dist/imports.d.ts.map +1 -1
- package/dist/imports.js +5 -58
- package/dist/imports.js.map +1 -1
- package/dist/index.d.ts +13 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +16 -75
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +198 -370
- package/dist/mcp.js.map +1 -1
- package/dist/overlay.d.ts +39 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +133 -0
- package/dist/overlay.js.map +1 -0
- package/dist/parser.d.ts +41 -24
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +217 -160
- package/dist/parser.js.map +1 -1
- package/dist/prove.d.ts +46 -0
- package/dist/prove.d.ts.map +1 -0
- package/dist/prove.js +549 -0
- package/dist/prove.js.map +1 -0
- package/dist/query.d.ts +11 -0
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +9 -3
- package/dist/query.js.map +1 -1
- package/dist/reporter.d.ts +139 -1
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +593 -21
- package/dist/reporter.js.map +1 -1
- package/dist/rules.js +3 -3
- package/dist/rules.js.map +1 -1
- package/dist/runner.d.ts +24 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +84 -21
- package/dist/runner.js.map +1 -1
- package/dist/specs.d.ts +5 -1
- package/dist/specs.d.ts.map +1 -1
- package/dist/specs.js +5 -1
- package/dist/specs.js.map +1 -1
- package/dist/structure.d.ts.map +1 -1
- package/dist/structure.js +7 -6
- package/dist/structure.js.map +1 -1
- package/dist/types.d.ts +193 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vendor/spec-core/jsonrpc/index.d.ts +3 -0
- package/dist/vendor/spec-core/jsonrpc/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/index.js +2 -0
- package/dist/vendor/spec-core/jsonrpc/index.js.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.d.ts +158 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.d.ts.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.js +353 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.js.map +1 -0
- package/dist/vendor/spec-core/markdown/frontmatter.d.ts +104 -0
- package/dist/vendor/spec-core/markdown/frontmatter.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js +459 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -0
- package/dist/vendor/spec-core/markdown/headings.d.ts +46 -0
- package/dist/vendor/spec-core/markdown/headings.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/headings.js +199 -0
- package/dist/vendor/spec-core/markdown/headings.js.map +1 -0
- package/dist/vendor/spec-core/markdown/index.d.ts +6 -0
- package/dist/vendor/spec-core/markdown/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/index.js +4 -0
- package/dist/vendor/spec-core/markdown/index.js.map +1 -0
- package/dist/vendor/spec-core/markdown/layout.d.ts +40 -0
- package/dist/vendor/spec-core/markdown/layout.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/layout.js +28 -0
- package/dist/vendor/spec-core/markdown/layout.js.map +1 -0
- package/dist/vendor/spec-core/markdown/links.d.ts +23 -0
- package/dist/vendor/spec-core/markdown/links.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/links.js +364 -0
- package/dist/vendor/spec-core/markdown/links.js.map +1 -0
- package/dist/vendor/spec-core/markdown/lists.d.ts +23 -0
- package/dist/vendor/spec-core/markdown/lists.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/lists.js +127 -0
- package/dist/vendor/spec-core/markdown/lists.js.map +1 -0
- package/dist/vendor/spec-core/markdown/scan.d.ts +37 -0
- package/dist/vendor/spec-core/markdown/scan.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/scan.js +439 -0
- package/dist/vendor/spec-core/markdown/scan.js.map +1 -0
- package/dist/vendor/spec-core/markdown/syntax.d.ts +76 -0
- package/dist/vendor/spec-core/markdown/syntax.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/syntax.js +181 -0
- package/dist/vendor/spec-core/markdown/syntax.js.map +1 -0
- package/dist/vendor/spec-core/markdown/tables.d.ts +19 -0
- package/dist/vendor/spec-core/markdown/tables.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/tables.js +86 -0
- package/dist/vendor/spec-core/markdown/tables.js.map +1 -0
- package/dist/vendor/spec-core/markdown/types.d.ts +288 -0
- package/dist/vendor/spec-core/markdown/types.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/types.js +9 -0
- package/dist/vendor/spec-core/markdown/types.js.map +1 -0
- package/dist/vendor/spec-core/path/index.d.ts +2 -0
- package/dist/vendor/spec-core/path/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/path/index.js +2 -0
- package/dist/vendor/spec-core/path/index.js.map +1 -0
- package/dist/vendor/spec-core/path/posix.d.ts +84 -0
- package/dist/vendor/spec-core/path/posix.d.ts.map +1 -0
- package/dist/vendor/spec-core/path/posix.js +150 -0
- package/dist/vendor/spec-core/path/posix.js.map +1 -0
- package/dist/vendor/spec-core/pattern/automaton.d.ts +130 -0
- package/dist/vendor/spec-core/pattern/automaton.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/automaton.js +340 -0
- package/dist/vendor/spec-core/pattern/automaton.js.map +1 -0
- package/dist/vendor/spec-core/pattern/charset.d.ts +59 -0
- package/dist/vendor/spec-core/pattern/charset.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/charset.js +116 -0
- package/dist/vendor/spec-core/pattern/charset.js.map +1 -0
- package/dist/vendor/spec-core/pattern/glob.d.ts +122 -0
- package/dist/vendor/spec-core/pattern/glob.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/glob.js +481 -0
- package/dist/vendor/spec-core/pattern/glob.js.map +1 -0
- package/dist/vendor/spec-core/pattern/index.d.ts +7 -0
- package/dist/vendor/spec-core/pattern/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/index.js +4 -0
- package/dist/vendor/spec-core/pattern/index.js.map +1 -0
- package/dist/vendor/spec-core/pattern/regex.d.ts +68 -0
- package/dist/vendor/spec-core/pattern/regex.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/regex.js +813 -0
- package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
- package/dist/vendor/spec-core/text/index.d.ts +3 -0
- package/dist/vendor/spec-core/text/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/text/index.js +2 -0
- package/dist/vendor/spec-core/text/index.js.map +1 -0
- package/dist/vendor/spec-core/text/lines.d.ts +73 -0
- package/dist/vendor/spec-core/text/lines.d.ts.map +1 -0
- package/dist/vendor/spec-core/text/lines.js +156 -0
- package/dist/vendor/spec-core/text/lines.js.map +1 -0
- package/package.json +8 -1
- package/src/vendor/spec-core/LICENSE +21 -0
- package/src/vendor/spec-core/README.md +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,416 @@ All notable changes to this project are documented here. Versions follow
|
|
|
5
5
|
may change in a minor release — each such change is listed under **Changed**
|
|
6
6
|
with the flag that restores the previous behaviour.
|
|
7
7
|
|
|
8
|
+
## 0.12.0
|
|
9
|
+
|
|
10
|
+
The family's core, and three commands. Patterns and Markdown are read through
|
|
11
|
+
spec-core, copied in and checked by hash: a pattern that cannot be read is
|
|
12
|
+
refused rather than matched as a literal, a glob no longer backtracks, and
|
|
13
|
+
directives are found as CommonMark finds code, comments and front matter.
|
|
14
|
+
`prove` shows every rule in force catching a violation, `cites` holds code
|
|
15
|
+
comments to the specs they cite, and `impact` names who depends on a path.
|
|
16
|
+
`archived` withholds a document.
|
|
17
|
+
|
|
18
|
+
### Upgrading
|
|
19
|
+
|
|
20
|
+
Run this release beside the one it replaces, each with `--json`, and compare
|
|
21
|
+
`summary.total` before trusting a green run - and, if the totals differ, each
|
|
22
|
+
result's `spec` file and line, which say which rule moved. A rule that stops
|
|
23
|
+
running reads exactly like one that passes. On a consumer of 114 specs and 301
|
|
24
|
+
assertions, both releases ran the same 301 at the same places with the same
|
|
25
|
+
counts. What can differ, and where this changelog says why:
|
|
26
|
+
|
|
27
|
+
- **A run that exits 2**, or a directive that is invalid, where one ran: a
|
|
28
|
+
pattern that cannot be read - `**` inside a name (`docs/**.md`), an
|
|
29
|
+
extended glob, an unclosed `[` or `{` - in `specs`, `exclude`, `--spec`,
|
|
30
|
+
`--exclude` or a directive's attributes.
|
|
31
|
+
- **`summary.total` moving** because a directive moved between prose and code:
|
|
32
|
+
the shapes under Fixed. Every directive-shaped comment left in code, raw
|
|
33
|
+
HTML or front matter is on one line of the report and in `maskedDirectives`.
|
|
34
|
+
- **`summary.inactive` moving**: `archived` withholds a document; a
|
|
35
|
+
front-matter `status` the reader cannot read - text after a closing quote,
|
|
36
|
+
`: ` in a plain value - keeps its document in force with a warning, where
|
|
37
|
+
0.11.0 took its first word, and nothing below the front matter is read in
|
|
38
|
+
its place; and an invalid directive in a draft is counted once, as invalid.
|
|
39
|
+
- **Warnings that fail nothing**, in `specWarnings`: a front-matter status
|
|
40
|
+
that cannot be read, a block never closed.
|
|
41
|
+
- **`impact` exits 2** when no spec matched, as `query` does.
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- **`spec-guard impact <paths...>`: who depends on this?** For each path, the
|
|
46
|
+
files that import it, transitively, each with its distance and the import
|
|
47
|
+
that takes it one step closer, and the rules in force that govern the path or
|
|
48
|
+
any of them, by `query`'s arithmetic. The import graph is ADR-0011's, read
|
|
49
|
+
backwards over the whole tree: relative JavaScript and TypeScript imports by
|
|
50
|
+
its resolution table, and relative Python imports, which name a module
|
|
51
|
+
beside the importing file. Go, Rust, C# and absolute Python references name
|
|
52
|
+
modules and are counted rather than followed; a path in one of those
|
|
53
|
+
languages says its dependents are not computed. An import naming no file, an
|
|
54
|
+
alias or a dynamic `import(name)` is listed, never guessed. `--depth <n>`,
|
|
55
|
+
`--ignore-status`, and `--json` with `formatVersion`. A path that does not
|
|
56
|
+
exist is exit 2, and so is a run in which no spec matched, as for `query`:
|
|
57
|
+
the dependents are written, and `--allow-empty` exits 0 with them. `impactOf`
|
|
58
|
+
is the API. [ADR-0018](docs/adr/0018-impact.md).
|
|
59
|
+
- **`get_dependents` on the MCP server**, a third tool beside
|
|
60
|
+
`get_architectural_rules` and `check_architecture`: `impact` for a list of
|
|
61
|
+
paths, with `depth` and `include_inactive`. Its structured content is the
|
|
62
|
+
document `impact --json` writes and its text the command's report, and it is
|
|
63
|
+
annotated read-only, as the other two are. Its description, and the server's
|
|
64
|
+
instructions, tell an agent to call it before changing a file others import.
|
|
65
|
+
A path that does not exist is a tool error the model can read. A client
|
|
66
|
+
that pinned the tool list sees three. `impactDocument` is the API for the
|
|
67
|
+
document both answer with. ADR-0018's amendment.
|
|
68
|
+
- **`spec-guard cites`: do the comments cite decisions in force?** A comment
|
|
69
|
+
such as `// ADR-0011: the domain imports no infrastructure` is a claim, and it
|
|
70
|
+
goes stale when the document is never written or is superseded. `cites` reads
|
|
71
|
+
the comment text of every source file - by the classifier's reading, so never
|
|
72
|
+
a string - for the ids of the families a project names in a new `cites`
|
|
73
|
+
option, `[{ "id": "ADR-{n}", "files": "docs/adr/{n}-*.md" }]`, where `{n}` is
|
|
74
|
+
a number (`ADR-7`, `ADR-007` and `0007-x.md` are one document). Without it, a
|
|
75
|
+
directory of numbered specs whose titles all begin with one id and their own
|
|
76
|
+
number is read as a family; anything less is a note and exit 0, not a guess.
|
|
77
|
+
A **ghost** citation, of no document, is an error with the nearest ids as its
|
|
78
|
+
hint. A **stale** one, of a document superseded, deprecated, rejected or
|
|
79
|
+
archived, is a warning (an error under `--strict`) that names the successor
|
|
80
|
+
the document's status line gives, followed to the one in force. Ids another
|
|
81
|
+
project qualifies - `spec-core's ADR-0005` - are counted and not checked,
|
|
82
|
+
and so are ids in a link: after a `/`, `#`, `=` or `?`, or past a `://`,
|
|
83
|
+
as in `https://github.com/org/repo/blob/main/docs/adr/ADR-0042.md`.
|
|
84
|
+
Markdown, spec files, excluded paths and files in no known language are not
|
|
85
|
+
read, and are counted. Human, `--json` (with `formatVersion`), SARIF, GitHub
|
|
86
|
+
and GitLab output; exit 1 on a ghost, 2 for a family whose files match no
|
|
87
|
+
document. `findCitations` is the API.
|
|
88
|
+
[ADR-0017](docs/adr/0017-citations-in-comments.md).
|
|
89
|
+
- **`spec-guard prove`: can each rule actually fail?** A passing rule cannot
|
|
90
|
+
say whether the code holds or the rule cannot see the code. `prove` shows
|
|
91
|
+
each rule in force a violation of itself - a file holding the forbidden text,
|
|
92
|
+
a file importing the forbidden module, a cycle, an import across layers, a
|
|
93
|
+
misnamed file, a required entry or a partner taken away, a required file
|
|
94
|
+
removed - and runs the rule over it, in memory, through the door every read
|
|
95
|
+
goes through: nothing is written to disk and nothing touches git. Each rule
|
|
96
|
+
is `killed`, `survived` (the finding, with the violation shown) or
|
|
97
|
+
`unprovable` (with the reason). Exit 1 when a rule survived, and under
|
|
98
|
+
`--strict` when one is unprovable; `--json` is versioned by `formatVersion`,
|
|
99
|
+
and `--format sarif` puts a survivor on its directive.
|
|
100
|
+
`proveSpecGuard` is the same for a caller of the API. The first proof of
|
|
101
|
+
this repository's own rules found one that could not fail as written, and
|
|
102
|
+
CI now proves every rule the repository states on each change.
|
|
103
|
+
[ADR-0016](docs/adr/0016-rules-seen-to-fail.md).
|
|
104
|
+
- **`RunOptions.io`: a run over a tree that is not on disk.** `runSpecGuard`
|
|
105
|
+
reads through the `Io` it is given - finding and reading the specs, checking
|
|
106
|
+
targets exist, walking them, scanning files, reading imports and listing
|
|
107
|
+
directories - and through `nodeIo` when it is given none, as before. The run
|
|
108
|
+
had the door all along and handed the filesystem to every reader itself.
|
|
109
|
+
ripgrep reads the disk in a process of its own, where no door reaches, so
|
|
110
|
+
`engine: 'ripgrep'` with an `io` is refused with a message that says so, and
|
|
111
|
+
`auto` with one searches with the built-in scanner. A search that fails
|
|
112
|
+
outright through the door fails the run, rather than falling back to the
|
|
113
|
+
scanner that reads the disk. [ADR-0014](docs/adr/0014-configuration-and-watch.md).
|
|
114
|
+
- **`--format gitlab` and `--format github`**, for the run, `prove` and
|
|
115
|
+
`cites`. `gitlab` writes a GitLab Code Quality report - `description`,
|
|
116
|
+
`check_name`, a `fingerprint`, a `severity` and a `location` - which a
|
|
117
|
+
merge request shows beside its changes. The fingerprint is the SHA-256 of
|
|
118
|
+
what a finding is about - a rule's document, kind, subject and targets, as
|
|
119
|
+
SARIF's is; a citation's file, family and id; a document's path - and never
|
|
120
|
+
of its message, which holds the count of matches and the directive's line:
|
|
121
|
+
one more match, or a line added above a directive, would otherwise have
|
|
122
|
+
closed every open issue and opened a new one. Findings that share an
|
|
123
|
+
identity, one ghost cited on two lines, are numbered in order. `github` writes one workflow command per finding, which a job's log
|
|
124
|
+
turns into an annotation on the pull request with no upload step. Both place
|
|
125
|
+
the findings SARIF places: a failing assertion or a surviving rule is
|
|
126
|
+
`critical`, a directive that could not be read `major`, a rule `prove` could
|
|
127
|
+
make no violation for `minor`, and a document not in force is named, as
|
|
128
|
+
`info`, on its first line. `formatGitlab`, `formatGithub`, `runAnnotations`,
|
|
129
|
+
`proveAnnotations` and `citesAnnotations` are the API.
|
|
130
|
+
- **What was not run is counted.** A comment shaped like a directive in code,
|
|
131
|
+
raw HTML or front matter is not run, and a report now says how many and
|
|
132
|
+
where: one dim line in the human report - "7 directive-shaped comments in
|
|
133
|
+
code, raw HTML or front matter were not run: README.md:120, ..." - naming
|
|
134
|
+
the first five, or every one under `--verbose`, and `maskedDirectives` in
|
|
135
|
+
the `--json` of a run and of `prove`, each with what hid it. Most are
|
|
136
|
+
examples; the ones that are not are rules 0.11.0 ran that this release does
|
|
137
|
+
not, such as a directive in an indented line or under a leading `---` read
|
|
138
|
+
as front matter. Warnings about how a document was read - a front-matter
|
|
139
|
+
status that cannot be read, a block never closed - are `specWarnings`.
|
|
140
|
+
Both fields are added, so no `formatVersion` moves.
|
|
141
|
+
[ADR-0002](docs/adr/0002-directive-format.md)'s amendment.
|
|
142
|
+
- **`formatVersion: 1` on the run's `--json` and on `query --json`**, as
|
|
143
|
+
`prove --json` has had from the start: a field removed or renamed moves it,
|
|
144
|
+
a field added does not. Both documents are otherwise unchanged; this is one
|
|
145
|
+
field more, first in each.
|
|
146
|
+
- **`io` on `loadRuleSet` and `queryRules`, too.** A query found and read the
|
|
147
|
+
specs, and asked whether each path exists, through the filesystem whatever
|
|
148
|
+
the caller had; it now goes through the door it is given, as a run does, so
|
|
149
|
+
a query over a tree in memory sees that tree.
|
|
150
|
+
|
|
151
|
+
### Fixed
|
|
152
|
+
|
|
153
|
+
- **An invalid directive in a document not in force was counted twice**, as
|
|
154
|
+
invalid and again as a rule not in force, so one bad directive in a draft
|
|
155
|
+
read "1 invalid · 1 not in force". It is counted once, as invalid, in the
|
|
156
|
+
summary, in the document's own line, and in the `inactive` of every JSON
|
|
157
|
+
report: it is no rule the document would run in force.
|
|
158
|
+
- **A glob could take a minute to fail one file name.** Every pattern was
|
|
159
|
+
compiled to a `RegExp`, and `*-*-*-*-*-*x` against a name of 121 dashes made
|
|
160
|
+
V8 try every way of dividing the name between six `[^/]*` groups: 55 seconds,
|
|
161
|
+
measured. Patterns are now read by the glob engine the spec-* tools share,
|
|
162
|
+
spec-core's, whose automaton keeps a set of live states and cannot backtrack:
|
|
163
|
+
the same match takes under a millisecond. spec-core is copied into
|
|
164
|
+
`src/vendor/spec-core` and verified by hash, so `dependencies` stays empty,
|
|
165
|
+
and its MIT notice ships in the package at `src/vendor/spec-core/LICENSE`.
|
|
166
|
+
[ADR-0015](docs/adr/0015-globs-from-spec-core.md).
|
|
167
|
+
- **ripgrep and the scanner still read some patterns differently**, so the same
|
|
168
|
+
rule could count differently on either side of the tree size at which `auto`
|
|
169
|
+
changes engine. ripgrep anchored every alternative of `{src/*.ts,*.md}`
|
|
170
|
+
because one held a `/`, dropped the empty one in `{,src/}a.ts`, matched
|
|
171
|
+
nothing for `src/./a.ts`, and failed on a `}` that closes nothing. It is now
|
|
172
|
+
handed each alternative as a glob of its own, spelled as the scanner reads
|
|
173
|
+
it. And ripgrep applies no glob to a path named on its command line, so a
|
|
174
|
+
rule whose target is a file its `glob` does not match, or a directory its
|
|
175
|
+
`exclude` does, counted under ripgrep what the scanner left out; its list of
|
|
176
|
+
files is now held to the same filters. ADR-0015.
|
|
177
|
+
- **What is code in a spec is what CommonMark says it is.** Directives inside
|
|
178
|
+
code never execute, and what counted as code was decided by `maskCode`'s own
|
|
179
|
+
rules. It is now decided by spec-core's Markdown scanner, which every spec-*
|
|
180
|
+
tool reads documents with, copied into `src/vendor/spec-core` from `cbe2223`
|
|
181
|
+
and verified by hash; `maskCode` is still exported, and is the scanner's
|
|
182
|
+
mask. [ADR-0002](docs/adr/0002-directive-format.md)'s amendment.
|
|
183
|
+
|
|
184
|
+
Directives that were hidden, and now execute:
|
|
185
|
+
- **A backtick fence's info string may not hold a backtick.** A line that
|
|
186
|
+
reads ```` ```js`x ```` is prose that opens with a code span. Read as a
|
|
187
|
+
fence, it hid every line under it, a real directive included, until
|
|
188
|
+
something closed it - and nothing said a rule had gone quiet.
|
|
189
|
+
- **A code span ends with its paragraph.** A backtick that closes nothing
|
|
190
|
+
there, as in ``press ` to open the console``, paired with the next
|
|
191
|
+
backtick anywhere in the document and hid every directive between the
|
|
192
|
+
two. An escaped backtick opens nothing.
|
|
193
|
+
- **A fence shown inside a comment opens nothing.** A template that showed
|
|
194
|
+
one hid every directive after it.
|
|
195
|
+
- **A fence line shown as code in a list item opens nothing.** Four columns
|
|
196
|
+
past an item's text is indented code, so a fence line written there - six
|
|
197
|
+
spaces under a `-` item, seven under `1.`, deeper in a nested item - is a
|
|
198
|
+
line of code. The first copy of the scanner read no indented code inside a
|
|
199
|
+
list, took the line for an opener that nothing closed, and hid every
|
|
200
|
+
directive after it.
|
|
201
|
+
|
|
202
|
+
And a code fence or a `<pre>`, `<script>`, `<style>` or `<textarea>`
|
|
203
|
+
block that is never closed, and runs to the end of the document, is a
|
|
204
|
+
warning on its opening line (`specWarnings`), since no directive after it
|
|
205
|
+
runs. It fails nothing: it is read as every renderer shows it, as code.
|
|
206
|
+
|
|
207
|
+
Directives that executed, and are now code:
|
|
208
|
+
- **A closing fence has no info string.** Inside a block opened by three
|
|
209
|
+
backticks, a line of three backticks followed by `js` is a line of the
|
|
210
|
+
block. It used to close it, and a directive shown after it executed.
|
|
211
|
+
- **A fence may be indented with the list item it sits in.** CommonMark
|
|
212
|
+
counts its three spaces from the item, so a fence in a `1.` item nested in
|
|
213
|
+
a `-` item is five or more spaces from the margin. It was not recognised,
|
|
214
|
+
and a directive shown inside it executed: always behind `~~~`, and behind
|
|
215
|
+
backticks whenever the prose above mentioned one, since the two fence lines
|
|
216
|
+
otherwise paired as a code span by accident. An opener may sit at any
|
|
217
|
+
indentation outside indented code, and a closer at most three columns
|
|
218
|
+
deeper than its opener.
|
|
219
|
+
- **Indented code, raw-text HTML and front matter are not read.** Four
|
|
220
|
+
columns past the margin, or past the text of the list item a line sits
|
|
221
|
+
in, after a blank line, are code in every renderer;
|
|
222
|
+
`<script>`, `<pre>`, `<style>` and `<textarea>` hold no Markdown; front
|
|
223
|
+
matter is metadata. `<details>` and `<div>` hold Markdown, and are read.
|
|
224
|
+
|
|
225
|
+
And a backtick inside a comment is a character, so a directive holding one
|
|
226
|
+
keeps it: ``symbol="`eval`"`` is searched for as written, where the two
|
|
227
|
+
backticks paired and the rule searched for six spaces.
|
|
228
|
+
|
|
229
|
+
This repository's own specs execute the same assertions, at the same lines,
|
|
230
|
+
and every directive in the 143 Markdown files of the five spec-* repositories
|
|
231
|
+
is read as before. A test holds the scanner to 0.11.0's masking on every
|
|
232
|
+
Markdown file here, and on random documents built from lines both read alike,
|
|
233
|
+
and shows it parting from 0.11.0 on each shape above.
|
|
234
|
+
|
|
235
|
+
### Changed
|
|
236
|
+
|
|
237
|
+
- **Mutation testing in CI runs in eight shards**, not four. Three of the four
|
|
238
|
+
took 23 to 28 minutes on the sweep that merged this release's code, and the
|
|
239
|
+
fourth was cancelled at the 30-minute job limit. ADR-0003 has the per-file
|
|
240
|
+
minutes and the split; the longest of the eight took 16m16s.
|
|
241
|
+
- **A pattern that cannot be read is refused.** An unclosed `[` or `{`, an
|
|
242
|
+
extended glob such as `+(a|b)` (a group holding a `|`: `C++(notes).md` and
|
|
243
|
+
`*(2017).md` are names with parentheses), a `..`, or a range that runs
|
|
244
|
+
backwards, in `glob`, `exclude`, `module`, `order`, `pattern`, `dirs` or
|
|
245
|
+
`required`, makes the directive invalid; in `exclude` in the configuration or `--exclude`, or in
|
|
246
|
+
a spec pattern, it is exit 2. Each used to be read as a literal or as whatever
|
|
247
|
+
its `RegExp` happened to mean, which is a filter that matches nothing and
|
|
248
|
+
passes. So is an alternative that names no path, as in `{dist/**,}`, whose
|
|
249
|
+
empty alternative matched the empty string. A brace group with a comma in it
|
|
250
|
+
in a directive is one more case: a list attribute splits on commas, so
|
|
251
|
+
`glob="*.{ts,tsx}"` was always the two patterns `*.{ts` and `tsx}`, and the
|
|
252
|
+
message now says so. A configuration's `exclude` is a JSON array, where braces
|
|
253
|
+
keep their commas. Nothing restores the old readings.
|
|
254
|
+
[ADR-0015](docs/adr/0015-globs-from-spec-core.md).
|
|
255
|
+
- **`**` inside a name is refused**: `docs/**.md`, `src/**.ts`, `**.ts`,
|
|
256
|
+
`a**b`. The message says what `**` means and gives the two ways to write
|
|
257
|
+
what was meant, `docs/**/*.md` for any depth and `*.md` for one level. It
|
|
258
|
+
used to cross directories under the scanner and not under ripgrep, so a rule
|
|
259
|
+
counted differently by engine; read as `*`, as `.gitignore` reads it,
|
|
260
|
+
`"specs": ["docs/**.md"]` would quietly have stopped finding every nested
|
|
261
|
+
document. In a directive the directive is invalid, in a draft as in a
|
|
262
|
+
document in force. A spec pattern is refused before any command starts: in
|
|
263
|
+
the configuration's `specs`, naming the file, and on the command line or in
|
|
264
|
+
`--spec`, for `query`, `impact`, `cites`, `prove` and `mcp` as for a run -
|
|
265
|
+
exit 2, as `exclude` in the configuration and `--exclude` are.
|
|
266
|
+
`specPatternError` is the check, for a caller of the API.
|
|
267
|
+
- **A `.` or empty segment is no segment** (`src/./a.ts` is `src/a.ts`), and
|
|
268
|
+
**a leading `/` anchors a `glob`** at the root, as it anchors an `exclude`.
|
|
269
|
+
Both matched nothing in the scanner before; ripgrep already anchored.
|
|
270
|
+
- **`archived` withholds a document**, a sixth word beside `draft`,
|
|
271
|
+
`proposed`, `rejected`, `deprecated` and `superseded`. `spec-brief` closes a
|
|
272
|
+
task brief's round by setting `status: archived` and moving the brief to an
|
|
273
|
+
archive directory. Its directives stated the round's premises and goals,
|
|
274
|
+
which are history once the round is closed, and executed anyway they failed.
|
|
275
|
+
An archived document is still parsed, validated and named in every output
|
|
276
|
+
format. `--ignore-status` executes it as before. The list stays closed:
|
|
277
|
+
`done`, `closed`, `archive` and every other near word stay in force, and
|
|
278
|
+
[ADR-0010](docs/adr/0010-spec-status.md)'s amendment says why this word and
|
|
279
|
+
no other.
|
|
280
|
+
- **A status is found by the scanner's headings and front-matter reader.**
|
|
281
|
+
The three spellings, their order and the words are unchanged, and every
|
|
282
|
+
status in the five spec-* repositories reads as it did. Where the scanner
|
|
283
|
+
reads a document differently, the status follows it:
|
|
284
|
+
- A `## Status` kept in a comment - a template not yet filled in - no longer
|
|
285
|
+
withholds the document, and a `##` in a comment or in code no longer ends
|
|
286
|
+
the preamble where the `**Status:**` label is read.
|
|
287
|
+
- An underlined heading is a heading. An underlined `Status` is the section,
|
|
288
|
+
and an underlined section ends the preamble, so a `status: draft` line with
|
|
289
|
+
`---` directly under it is a heading, as every renderer shows it, and not a
|
|
290
|
+
label.
|
|
291
|
+
- Front matter is read by spec-core's reader, the family's: a quoted value
|
|
292
|
+
to its closing quote and a plain one to a comment, as before. A value it
|
|
293
|
+
refuses declares nothing - a `: ` in a plain value, text after a closing
|
|
294
|
+
quote, a value continued on the next line, `*Draft*`, which YAML reads as
|
|
295
|
+
an alias - and a `status` nested under another key is that key's. Front
|
|
296
|
+
matter behind a byte-order mark, or closed by `...`, is read as front
|
|
297
|
+
matter.
|
|
298
|
+
- A front-matter `status` decides even when it cannot be read. A value the
|
|
299
|
+
reader refuses, an empty one, one with no word or a list leaves the
|
|
300
|
+
status unrecognised and the document in force, and the `## Status`
|
|
301
|
+
section and the `Status:` label are not read in its place: under 0.11.0
|
|
302
|
+
`status: "accepted" (2024-05-01)` was accepted, and falling through to a
|
|
303
|
+
section still saying `Proposed` would have withheld its rules. Every
|
|
304
|
+
format says so, on the key's line: a warning in the human report, a
|
|
305
|
+
`specWarnings` entry in `--json` (run and `prove`), a SARIF notification
|
|
306
|
+
and a `spec-warning` annotation for GitHub and GitLab.
|
|
307
|
+
|
|
308
|
+
[ADR-0010](docs/adr/0010-spec-status.md)'s second amendment.
|
|
309
|
+
- **A title is the first level-one heading as the scanner reads it.** An
|
|
310
|
+
underlined one (`===`) is a title and one kept in a comment is not; a code
|
|
311
|
+
span in it is kept as written, where it was blanked, and a comment in it is
|
|
312
|
+
dropped. A first level-one heading with no text leaves the document
|
|
313
|
+
untitled rather than promoting the next. In this repository one title
|
|
314
|
+
changed: ADR-0009's keeps its `` `--fix` ``.
|
|
315
|
+
- **`maskCode` keeps a carriage return inside code**, where it blanked one:
|
|
316
|
+
every line terminator stays where it was, a lone `\r` included.
|
|
317
|
+
- **Reading a spec costs about four times what it did**: 17 ms against 4 ms
|
|
318
|
+
over this repository's 18 ADRs, and 23 ms against 9 ms for a warm query of
|
|
319
|
+
one path, past the 20 ms ADR-0012 set out to meet. The scanner finds list
|
|
320
|
+
items, links and tables that nothing here reads.
|
|
321
|
+
[ADR-0002](docs/adr/0002-directive-format.md)'s amendment says where the
|
|
322
|
+
remedy lies.
|
|
323
|
+
- **The MCP server speaks the protocol through spec-core.** Classifying each
|
|
324
|
+
request, the two eras, dispatch, result shapes and the stdio framing are
|
|
325
|
+
spec-core's `jsonrpc` module, copied from `f085f29` and verified by hash;
|
|
326
|
+
`src/mcp.ts` keeps the instructions, the tools and the resources. What a
|
|
327
|
+
client sees is unchanged, and every test of the server passes as it was
|
|
328
|
+
written. One edge moved: a last line cut inside a UTF-8 character when stdin
|
|
329
|
+
closes is read as far as it goes rather than dropped. The protocol's names
|
|
330
|
+
are still exported from the package. [ADR-0015](docs/adr/0015-globs-from-spec-core.md).
|
|
331
|
+
- **API:**
|
|
332
|
+
- `createGlobMatcher`, `createExcludeMatcher` and `expandSpecPatterns` throw
|
|
333
|
+
for a pattern spec-core refuses - an unclosed `[` or `{`, an extended
|
|
334
|
+
glob, a `..`, `**` inside a name - naming the pattern, where they read it
|
|
335
|
+
as a literal or as whatever its `RegExp` meant. `globPatternError` and the
|
|
336
|
+
new `specPatternError` say why without throwing.
|
|
337
|
+
- `Annotation` has a required `identity`, which the GitLab fingerprint is
|
|
338
|
+
made of. `SpecSet` and `RunPlan` have required `warnings` and `masked`;
|
|
339
|
+
`RunReport` and `ProveReport` have optional `specWarnings` and
|
|
340
|
+
`maskedDirectives`, and `ParseResult` optional `warnings` and `masked`.
|
|
341
|
+
An `InactiveSpec`'s `directives` counts only those that resolve.
|
|
342
|
+
- New: `proveSpecGuard`, `PROVE_NAME`, `overlayIo` and `readOnce`;
|
|
343
|
+
`findCitations`, `findDocuments`, `deriveFamilies`, `scanCitations`,
|
|
344
|
+
`inComments`, `qualified`, `isStale`, `numberKey`, `documentNumber`,
|
|
345
|
+
`parseIdTemplate`, `parseFilesTemplate`, `citeIdError`, `citeFilesError`,
|
|
346
|
+
`CitesError` and `NUMBER`; `impactOf`, `impactDocument`, `dependentsOf`,
|
|
347
|
+
`buildReverseGraph`, `resolvePython`, `formatImpact`, `formatImpactJson`
|
|
348
|
+
and `ImpactError`; `formatProve`, `formatProveJson`, `formatProveSarif`,
|
|
349
|
+
`formatCites`, `formatCitesJson`, `formatCitesSarif`, `formatGitlab`,
|
|
350
|
+
`formatGithub`, `runAnnotations`, `proveAnnotations` and
|
|
351
|
+
`citesAnnotations`; `RUN_FORMAT_VERSION`, `QUERY_FORMAT_VERSION`,
|
|
352
|
+
`PROVE_FORMAT_VERSION`, `CITES_FORMAT_VERSION` and
|
|
353
|
+
`IMPACT_FORMAT_VERSION`; `globPatternError` and `specPatternError`; and
|
|
354
|
+
the types that go with them, `SpecWarning`, `MaskedDirective` and
|
|
355
|
+
`MaskedContext` among them.
|
|
356
|
+
|
|
357
|
+
## 0.11.0
|
|
358
|
+
|
|
359
|
+
The literal this lexer never read. A JavaScript or TypeScript regular
|
|
360
|
+
expression can hold a quote — `/'/`, `/["']/`, `replace(/\/\//g, '')` — and
|
|
361
|
+
without a rule for `/`, that quote opened a string that closed somewhere else
|
|
362
|
+
entirely. Every text rule over a TypeScript project reads through this
|
|
363
|
+
classifier, and this repository's own `src/parser.ts` was one of the files it
|
|
364
|
+
lost its place in. [ADR-0006](docs/adr/0006-comment-classification.md).
|
|
365
|
+
|
|
366
|
+
### Fixed
|
|
367
|
+
|
|
368
|
+
- **A regular expression holding a quote desynchronised the scan.** The quote
|
|
369
|
+
opened a string that ran to the next quote in the file, so the comments it
|
|
370
|
+
covered were counted as code — and, once it closed, the scan was half a
|
|
371
|
+
literal out of step, where a `//` inside a real string opened a comment that
|
|
372
|
+
**hid real code**. `/` now opens a literal in `.js`, `.mjs`, `.cjs`, `.jsx`,
|
|
373
|
+
`.ts`, `.mts`, `.cts` and `.tsx`, decided by the token before it with the
|
|
374
|
+
same two tables the import tokenizer has used since 0.2.0 — which now live in
|
|
375
|
+
one place and are read by both, so the two scanners cannot disagree. A
|
|
376
|
+
character class holds an unescaped `/`, `\/` does not close, and a `/` that
|
|
377
|
+
closes nothing before the end of its line was a division.
|
|
378
|
+
- **`/*` in JSX text opened a comment**, so `<div>/*</div>` hid every line up
|
|
379
|
+
to the next `*/` in the file. After a tag's `>` it is text.
|
|
380
|
+
- **An apostrophe in a YAML value opened a string.** Most YAML scalars are
|
|
381
|
+
unquoted and may hold one — `- name: Build the decoder's artefact` — and read
|
|
382
|
+
with the shell's quoting that apostrophe closed on the next one, lines away,
|
|
383
|
+
with every `#` between them no longer a comment. `.yaml` and `.yml` have a
|
|
384
|
+
profile of their own, `yaml`, which keeps the shell's `#` rule and takes a
|
|
385
|
+
quote as opening a scalar only where a word could start. `'it''s'` is one
|
|
386
|
+
scalar, YAML's own escape. A shell's quotes still open mid-word, because
|
|
387
|
+
`dir='C:\'` needs them to.
|
|
388
|
+
|
|
389
|
+
### Changed
|
|
390
|
+
|
|
391
|
+
- **A JavaScript string ends at its line.** Only a template may hold a line
|
|
392
|
+
break, so a quoted string that reaches one was never a string and is read as
|
|
393
|
+
code from there. It used to run to the end of the file. This is what JSX text
|
|
394
|
+
costs as well: `<p>Don't click</p>` opens a literal nothing closes, and it
|
|
395
|
+
now costs that line rather than everything after it.
|
|
396
|
+
- **The `shell-like` profile split in two.** `.sh`, `.bash` and `.zsh` are
|
|
397
|
+
read as `shell`, `.yaml` and `.yml` as `yaml`, because their quoting
|
|
398
|
+
differs: a shell's quotes open mid-word and YAML's open only where a value
|
|
399
|
+
starts. The names themselves are internal — no output reports them — so what
|
|
400
|
+
changed for a caller is the reading, described above.
|
|
401
|
+
|
|
402
|
+
Counts may move on a project that has any of these. A text rule over `.ts`,
|
|
403
|
+
`.tsx`, `.yaml` or `.yml` can now see code it could not see before, and can
|
|
404
|
+
stop counting comment text it was counting: on 7,953 files here, 119 phantom
|
|
405
|
+
comments in 63 files disappeared and 1,948 real comments in 53 files came back.
|
|
406
|
+
44 JavaScript files reported a lost scan before; 4 do now, every one of them a
|
|
407
|
+
template nested inside a `${…}` substitution, which ADR-0006 records as the
|
|
408
|
+
open item this release does not close.
|
|
409
|
+
|
|
410
|
+
The scan is also **faster than it has ever been** — 5.1× for TypeScript, 5.2×
|
|
411
|
+
for C#, 3.4× for C, 2.8× for shell scripts and 1.3× for Rust, whose raw strings
|
|
412
|
+
open with the letter `r` and so reach the slow path often. A character that
|
|
413
|
+
opens nothing in a language now costs one array lookup rather than four
|
|
414
|
+
searches that were always going to fail. That was not a bonus: adding the
|
|
415
|
+
regular-expression branch made C, which never enters it, 16% slower, and a
|
|
416
|
+
question asked per character has to be paid for per character.
|
|
417
|
+
|
|
8
418
|
## 0.10.3
|
|
9
419
|
|
|
10
420
|
Fixes from running 0.10.2 over a Rust and .NET monorepo, where an import rule
|