@descent-vtt/spec-graph 0.13.0 → 0.14.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 +109 -0
- package/README.md +109 -9
- package/bin/spec-graph.js +8 -1
- package/dist/cli.d.ts +8 -1
- package/dist/cli.js +227 -26
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.js +35 -5
- package/dist/config.js.map +1 -1
- package/dist/glob.js +3 -2
- package/dist/glob.js.map +1 -1
- package/dist/identity.d.ts +12 -0
- package/dist/identity.js +15 -0
- package/dist/identity.js.map +1 -1
- package/dist/report.d.ts +14 -2
- package/dist/report.js +16 -5
- package/dist/report.js.map +1 -1
- package/dist/resolve.d.ts +9 -0
- package/dist/resolve.js +1 -1
- package/dist/resolve.js.map +1 -1
- package/dist/runner.d.ts +4 -0
- package/dist/runner.js +9 -0
- package/dist/runner.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,115 @@ the family's
|
|
|
11
11
|
[versioning policy](https://github.com/DescentVTT/spec-core/blob/main/docs/adr/0009-versions-before-1-0.md)
|
|
12
12
|
records.
|
|
13
13
|
|
|
14
|
+
## 0.14.0
|
|
15
|
+
|
|
16
|
+
An input that is set and names nothing - a family name no family has, a list
|
|
17
|
+
of families no document belongs to, a `--root` that is no directory, a blank
|
|
18
|
+
value, an option of another command - was read as if it had not been given.
|
|
19
|
+
It is refused now: exit 2 and one line that names it
|
|
20
|
+
([ADR-0010](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0010-configuration-belongs-to-the-repository.md)).
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **A family name no family has is refused.** `--family ""`, which an unset
|
|
25
|
+
variable leaves, and `--family ADR,RFC` allowed no family at all, so every
|
|
26
|
+
citation was prose and a check that failed on a dangling one exited 0. Each
|
|
27
|
+
is exit 2 now, `--family expects one family's name, such as ADR, got ""`,
|
|
28
|
+
and so are `--ignore-family`, `families` and `ignoreFamilies` in the
|
|
29
|
+
configuration, and `createFamilyFilter()` from the package.
|
|
30
|
+
Upgrading: give one name each time, the prefix the identifiers are written
|
|
31
|
+
with, as in `--family ADR --family RFC`, and leave the option out where
|
|
32
|
+
there is none to give.
|
|
33
|
+
- **A `--root` that is no directory is refused by name.** `rules --root` given
|
|
34
|
+
a path that is not there, a file or an empty value listed the built-in rules
|
|
35
|
+
and exited 0, and `check`, `query` and `graph` exited 2 saying only that no
|
|
36
|
+
specification matched. Each ends with exit 2 and the option named: `--root
|
|
37
|
+
"<path>" is not there`, `is not a directory`, or `--root expects a
|
|
38
|
+
directory, got ""`.
|
|
39
|
+
Upgrading: name a directory that exists, or leave `--root` out and the
|
|
40
|
+
directory holding the configuration is the root.
|
|
41
|
+
- **A configuration file that is there and cannot be read stops the run.** A
|
|
42
|
+
directory called `.spec-graph.json`, or a file the run may not open, was
|
|
43
|
+
passed over as absent, and the run checked on defaults or on the
|
|
44
|
+
configuration of a directory above. It is a problem in the configuration
|
|
45
|
+
now, exit 2.
|
|
46
|
+
Upgrading: remove or repair the file, or run with `--no-config`.
|
|
47
|
+
- **A blank `--ignore` or `--record-baseline` is refused, as an empty one
|
|
48
|
+
was.** `--ignore " "` was read as a directory's name since 0.9.0 and
|
|
49
|
+
ignored nothing, `"ignore": [" "]` in the configuration likewise, and
|
|
50
|
+
`--record-baseline " "` wrote a file named with a space.
|
|
51
|
+
Upgrading: pass the option only where its variable is set, as in
|
|
52
|
+
`${IGNORE:+--ignore "$IGNORE"}`.
|
|
53
|
+
- **`rules` takes one rule id.** `spec-graph rules a b` listed `a` and said
|
|
54
|
+
nothing of `b`; it is exit 2 now, with both named.
|
|
55
|
+
Upgrading: one run for each rule, or no id for all of them.
|
|
56
|
+
- **`--format json` is refused by `graph` and `rules`.** `graph --format
|
|
57
|
+
json` wrote DOT and `rules --format json` its list, each with exit 0, as
|
|
58
|
+
`--format sarif` was already refused there.
|
|
59
|
+
Upgrading: `graph --graph-format json` writes the graph as JSON; `rules`
|
|
60
|
+
has one format.
|
|
61
|
+
- **A list of families that names none the documents belong to stops the
|
|
62
|
+
check.** `--family RFC` in a repository of ADRs, or `ADRS` for `ADR`,
|
|
63
|
+
allowed nothing, as `--family ""` did: `check` printed `the specification
|
|
64
|
+
graph is consistent` over a dangling citation, under `--strict` too. It is
|
|
65
|
+
exit 2 now, for `--family` and `families` alike, with the list and the
|
|
66
|
+
families the documents do belong to; a list that names such a family beside
|
|
67
|
+
one they belong to gets a line on stderr and fails nothing.
|
|
68
|
+
Upgrading: name a family whose identifiers the documents carry, `ADR` for
|
|
69
|
+
`ADR-0007`, or leave the list out until the first such document is written.
|
|
70
|
+
- **An option a command does not read is refused by that command.** `query
|
|
71
|
+
--strict`, `graph --record-baseline f`, `rules --max 1`, `diff --root x` and
|
|
72
|
+
some sixty more pairings ran as if the option were absent, and `spec-graph
|
|
73
|
+
--graph-format mermaid > graph.mmd` wrote the check's report into the file.
|
|
74
|
+
Each is exit 2 with the option, the command and the commands that read it:
|
|
75
|
+
`--graph-format belongs to graph, not to check`. `--no-config`,
|
|
76
|
+
`--no-color` and `--ascii` are taken everywhere
|
|
77
|
+
([the table](README.md#cli)).
|
|
78
|
+
Upgrading: drop the option from the command that does not read it, or move
|
|
79
|
+
what every run repeats into `.spec-graph.json`, which every command reads.
|
|
80
|
+
- **A value that begins with `--` is not taken as a value.** `--ignore
|
|
81
|
+
--strict` ignored a directory called `--strict` and left the check
|
|
82
|
+
unstrict, and `--record-baseline --verbose` wrote a file of that name; each
|
|
83
|
+
option that takes a value now says `--ignore needs a value, and --strict
|
|
84
|
+
reads as an option`, and so does one followed by `-h` or `-v`.
|
|
85
|
+
Upgrading: give the value, or for a name that does begin with two dashes
|
|
86
|
+
write `./--name` for a file, `[-]-name` in a pattern and `\--name` for a
|
|
87
|
+
reference target.
|
|
88
|
+
- **`CI` no longer turns colour off.** With `CI` set and stdout a terminal the
|
|
89
|
+
report was plain; it is coloured there, as spec-brief's and spec-guard's
|
|
90
|
+
are, and where stdout is no terminal it is plain as before.
|
|
91
|
+
Upgrading: set `NO_COLOR=1` or pass `--no-color` where a pipeline's
|
|
92
|
+
terminal should stay plain.
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- `SPEC_GRAPH_ASCII=0`, `false` and a blank value no longer turn ASCII glyphs
|
|
97
|
+
on: the variable was read for being set. `--help` and the README name it
|
|
98
|
+
beside `--ascii`, and the README says how colour is decided; neither was
|
|
99
|
+
written anywhere.
|
|
100
|
+
- An empty `--baseline` or `--record-baseline` is refused by the option's
|
|
101
|
+
name, `--baseline expects a file, got ""`, where the line was `cannot read
|
|
102
|
+
the baseline : EISDIR: illegal operation on a directory, read`. Exit 2, as
|
|
103
|
+
before.
|
|
104
|
+
- An empty name given to `diff` is refused as `diff expects a graph export on
|
|
105
|
+
each side, got "" for the first`, where the line was `cannot read : EISDIR`.
|
|
106
|
+
Exit 2, as before.
|
|
107
|
+
|
|
108
|
+
## 0.13.1
|
|
109
|
+
|
|
110
|
+
A reader that closed the output, as `| head` does, was answered with
|
|
111
|
+
`unexpected error:` and a stack; it is one line now, and still exit 2.
|
|
112
|
+
|
|
113
|
+
### Fixed
|
|
114
|
+
|
|
115
|
+
- **A reader that closes the output is answered in one line, not a stack.**
|
|
116
|
+
`spec-graph graph | head` ended with `spec-graph: unexpected error: Error:
|
|
117
|
+
EPIPE: broken pipe, write` and a stack once `head` had left before the
|
|
118
|
+
graph was written; it now prints `spec-graph: stdout was closed before all
|
|
119
|
+
of the output was written` on stderr, from every command. The exit code is
|
|
120
|
+
2, as it was
|
|
121
|
+
([ADR-0010](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0010-configuration-belongs-to-the-repository.md)).
|
|
122
|
+
|
|
14
123
|
## 0.13.0
|
|
15
124
|
|
|
16
125
|
An error spec-graph did not expect ended the run with exit 1, which reads as
|
package/README.md
CHANGED
|
@@ -869,7 +869,8 @@ SARIF — and is 8 unless set; `0` lists none.
|
|
|
869
869
|
|
|
870
870
|
A broken config stops the run with exit `2`, each problem named on stderr:
|
|
871
871
|
invalid JSON, a value of the wrong type, an unknown key, a rule that does not
|
|
872
|
-
compile
|
|
872
|
+
compile, a family name no family has, a file that is there and cannot be read.
|
|
873
|
+
Why a mistake stops the run:
|
|
873
874
|
|
|
874
875
|
- A configuration that did not load checks a different repository than the one
|
|
875
876
|
configured, and would report *that* one as consistent: a `{1.phse}` for
|
|
@@ -986,6 +987,37 @@ Every specification cites RFC 2119. In a repository that also keeps its own
|
|
|
986
987
|
`families` is the stronger statement — *these* are the families this repository
|
|
987
988
|
has — and turns every other noun-number construct back into prose.
|
|
988
989
|
|
|
990
|
+
Each entry, and each `--family` or `--ignore-family`, is one family's name:
|
|
991
|
+
the prefix its identifiers are written with, `ADR` for `ADR-0007`, in any case.
|
|
992
|
+
A name no family has — `""`, or `"ADR,RFC"` where two entries go — stops the
|
|
993
|
+
run with exit `2`: alone in `families` it allowed nothing, so every citation
|
|
994
|
+
was prose and a dangling one passed.
|
|
995
|
+
|
|
996
|
+
A name that is a family's, and that no document here belongs to, allows
|
|
997
|
+
nothing either. `--family RFC` in a repository of ADRs, or `ADRS` for `ADR`,
|
|
998
|
+
leaves every citation as prose, and the check would report a consistent graph
|
|
999
|
+
over a citation of an ADR nobody wrote. So a list has to name a family a
|
|
1000
|
+
document belongs to, or the check stops with exit `2`, before it reports or
|
|
1001
|
+
records anything:
|
|
1002
|
+
|
|
1003
|
+
```text
|
|
1004
|
+
spec-graph: no document here belongs to a family named by --family (RFC); the documents here belong to ADR
|
|
1005
|
+
name a family the documents belong to, or leave the list out
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
A document belongs to a family when its identifier is written with it, as
|
|
1009
|
+
`ADR-0007` is with `ADR`. A list that names such a family beside one the
|
|
1010
|
+
documents do belong to is a family the repository means to start, or a typo in
|
|
1011
|
+
half the list: it is said on stderr and fails nothing.
|
|
1012
|
+
|
|
1013
|
+
```text
|
|
1014
|
+
spec-graph: no document here belongs to RFC, named by --family; the documents here belong to ADR
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
A list whose every name has a document sees neither line. `ignoreFamilies`
|
|
1018
|
+
needs no such check: a name on it passes over citations of that family alone,
|
|
1019
|
+
so a mistyped one passes over nothing and the run reports more, not less.
|
|
1020
|
+
|
|
989
1021
|
Both are consulted only after resolution has already failed, so `RFC 0001` still
|
|
990
1022
|
resolves to your local RFC-0001 with `RFC` on the ignore list. No configuration
|
|
991
1023
|
can delete an edge. See
|
|
@@ -1025,15 +1057,18 @@ spec-graph diff <before> <after> Compare two JSON graph exports.
|
|
|
1025
1057
|
its directory is the root
|
|
1026
1058
|
--ignore <glob> Skip paths (repeatable)
|
|
1027
1059
|
--ignore-ref <glob> Do not report these reference targets (repeatable)
|
|
1028
|
-
--family <name> Families a bare identifier may name (repeatable
|
|
1029
|
-
|
|
1060
|
+
--family <name> Families a bare identifier may name (repeatable, one
|
|
1061
|
+
name each time)
|
|
1062
|
+
--ignore-family <name> Families that are never citations (repeatable, one
|
|
1063
|
+
name each time)
|
|
1030
1064
|
--history <glob> Files that log decisions rather than making them
|
|
1031
1065
|
--baseline <file> Accept these findings; report only what is new
|
|
1032
1066
|
--record-baseline <f> Write today's findings as accepted debt, exit 0
|
|
1033
1067
|
--ratchet Also fail when a baseline entry no longer occurs
|
|
1034
1068
|
--no-config Ignore .spec-graph.json and the package.json key
|
|
1035
|
-
--format <fmt> human | json
|
|
1036
|
-
|
|
|
1069
|
+
--format <fmt> human | json (check, query, diff) | sarif (check)
|
|
1070
|
+
| github (check) | gitlab (check)
|
|
1071
|
+
| markdown (check, diff)
|
|
1037
1072
|
--graph-format <fmt> dot | mermaid | json
|
|
1038
1073
|
--documents-only Hide items; their relations lift onto their documents
|
|
1039
1074
|
--rule <id>=<severity> error | warn | info | off (repeatable)
|
|
@@ -1041,7 +1076,7 @@ spec-graph diff <before> <after> Compare two JSON graph exports.
|
|
|
1041
1076
|
--max <n> Show at most n findings
|
|
1042
1077
|
--max-warnings <n> Fail when warnings exceed n
|
|
1043
1078
|
--color / --no-color Force colour
|
|
1044
|
-
--ascii ASCII glyphs only
|
|
1079
|
+
--ascii ASCII glyphs only, as SPEC_GRAPH_ASCII=1 asks too
|
|
1045
1080
|
--verbose Include parse problems
|
|
1046
1081
|
```
|
|
1047
1082
|
|
|
@@ -1049,7 +1084,60 @@ Exit codes: `0` clean, `1` findings, `2` the tool could not run. A mistyped flag
|
|
|
1049
1084
|
never masquerades as a passing build, and neither does a pattern that matches
|
|
1050
1085
|
nothing, a configuration file that did not load, or a `--baseline` that is not
|
|
1051
1086
|
there. An error spec-graph did not expect is `2` as well, never findings: it is
|
|
1052
|
-
reported on stderr as `spec-graph: unexpected error:` with its stack.
|
|
1087
|
+
reported on stderr as `spec-graph: unexpected error:` with its stack. So is a
|
|
1088
|
+
stdout its reader closed before all of the output was written, as a pipeline
|
|
1089
|
+
into `head` does: the answer did not arrive, and one line on stderr says so.
|
|
1090
|
+
|
|
1091
|
+
**An input that is set and names nothing is refused**: exit `2` and one line
|
|
1092
|
+
that names it, never a run that reads it as if it had not been given. An unset
|
|
1093
|
+
variable in `--family "$FAMILIES"` is the usual way to write one:
|
|
1094
|
+
|
|
1095
|
+
- a `--family` or `--ignore-family` holding a name no family has - empty,
|
|
1096
|
+
blank, or a list such as `ADR,RFC` where one name goes. Alone on the
|
|
1097
|
+
allowlist it would leave every citation as prose, and a dangling one
|
|
1098
|
+
unreported;
|
|
1099
|
+
- a `--root` that is empty, is not there, or is a file, for every command
|
|
1100
|
+
that reads one, `rules` included;
|
|
1101
|
+
- an empty or blank `--baseline`, `--record-baseline`, `--ignore`,
|
|
1102
|
+
`--ignore-ref`, `--history` or pattern;
|
|
1103
|
+
- a list of families, `--family` or `families`, none of which a document
|
|
1104
|
+
here belongs to ([Family rules](#family-rules));
|
|
1105
|
+
- a second word after `rules`, which takes one rule id, and an empty name
|
|
1106
|
+
given to `diff`;
|
|
1107
|
+
- `--format json` asked of `graph`, whose JSON is `--graph-format json`, or
|
|
1108
|
+
of `rules`, which has one format;
|
|
1109
|
+
- an option given to a command that does not read it, in the table below;
|
|
1110
|
+
- a value that begins with `--`, which reads as the option after one whose
|
|
1111
|
+
value was forgotten: `--ignore --strict` would ignore a directory called
|
|
1112
|
+
`--strict`, and `--record-baseline --verbose` write a file of that name.
|
|
1113
|
+
A name that does begin so is written `./--name` for a file, `[-]-name` in
|
|
1114
|
+
a pattern and `\--name` for a reference target;
|
|
1115
|
+
- a configuration file that is there and cannot be read, a directory called
|
|
1116
|
+
`.spec-graph.json` among them.
|
|
1117
|
+
|
|
1118
|
+
An option belongs to the commands that read it. Any other command refuses it
|
|
1119
|
+
by name, `--strict belongs to check, not to query`, rather than run as if the
|
|
1120
|
+
option were absent: `query --strict` would be no stricter, `graph
|
|
1121
|
+
--record-baseline` would write no file, and with the command forgotten,
|
|
1122
|
+
`spec-graph --graph-format mermaid > graph.mmd` would write the check's report
|
|
1123
|
+
into the file.
|
|
1124
|
+
|
|
1125
|
+
| Option | Read by |
|
|
1126
|
+
| --- | --- |
|
|
1127
|
+
| `--root`, `--verbose` | `check`, `query`, `graph`, `rules` |
|
|
1128
|
+
| `--ignore`, `--history` | `check`, `query`, `graph` |
|
|
1129
|
+
| `--format` | `check`, `query`, `diff` |
|
|
1130
|
+
| `--graph-format`, `--documents-only` | `graph` |
|
|
1131
|
+
| `--explain` | `rules` |
|
|
1132
|
+
| `--ignore-ref`, `--family`, `--ignore-family`, `--baseline`, `--record-baseline`, `--ratchet`, `--rule`, `--strict`, `--max`, `--max-warnings`, `--color` | `check` |
|
|
1133
|
+
| `--no-config`, `--no-color`, `--ascii`, `--help`, `--version` | every command |
|
|
1134
|
+
|
|
1135
|
+
`--no-config`, `--no-color` and `--ascii` are taken by every command because
|
|
1136
|
+
each is true already of a command with nothing to read it for: only a check
|
|
1137
|
+
colours its report or draws a glyph, and `diff` reads no configuration. A
|
|
1138
|
+
script can pass them to whatever it runs. The configuration file is not an
|
|
1139
|
+
option: `ignoreReferences` in `.spec-graph.json` stops no `graph`, which
|
|
1140
|
+
draws the same graph with it as without.
|
|
1053
1141
|
|
|
1054
1142
|
**There is no `--watch`.** A full run on this repository takes 60 ms, so the
|
|
1055
1143
|
loop that would justify a resident process is one line of shell, and it belongs
|
|
@@ -1059,6 +1147,18 @@ to whatever the developer already uses rather than to this tool:
|
|
|
1059
1147
|
npx --no-install @descent-vtt/spec-graph --format json | jq -r '.summary'
|
|
1060
1148
|
```
|
|
1061
1149
|
|
|
1150
|
+
### Colour and glyphs
|
|
1151
|
+
|
|
1152
|
+
`--color` and `--no-color` decide, then the environment, in this order:
|
|
1153
|
+
`NO_COLOR` set and not empty turns colour off; `FORCE_COLOR` set and not empty
|
|
1154
|
+
turns it on, and `0` turns it off; a `TERM` of `dumb` turns it off; otherwise
|
|
1155
|
+
the report is coloured when stdout is a terminal. `CI` is not read.
|
|
1156
|
+
|
|
1157
|
+
`--ascii` draws the report in ASCII glyphs, and so does `SPEC_GRAPH_ASCII`
|
|
1158
|
+
set to anything but `0`, `false` or nothing. Without either, a Windows console
|
|
1159
|
+
that sets neither `WT_SESSION` nor `TERM_PROGRAM` gets ASCII and every other
|
|
1160
|
+
terminal the box-drawing characters.
|
|
1161
|
+
|
|
1062
1162
|
## In CI
|
|
1063
1163
|
|
|
1064
1164
|
The exit code is the contract: `0` clean, `1` findings, `2` the tool could not
|
|
@@ -1318,9 +1418,9 @@ tools share, whose code is copied into `src/vendor/` and checked by hash rather
|
|
|
1318
1418
|
than installed. So the whole package is auditable in an afternoon — and nothing
|
|
1319
1419
|
in the pipeline can take longer than its input.
|
|
1320
1420
|
|
|
1321
|
-
**Verified, not just covered.** 2,
|
|
1421
|
+
**Verified, not just covered.** 2,141 tests; 99.4% statement and 99.8% line
|
|
1322
1422
|
coverage. Coverage says a line ran, so the suite is also held to a mutation
|
|
1323
|
-
score - 96.
|
|
1423
|
+
score - 96.50% over 8,832 mutants, measured by CI's full sweep, and a build
|
|
1324
1424
|
fails under 93 - because a vocabulary entry or a boundary
|
|
1325
1425
|
condition can be weakened by an ordinary-looking refactor without a single test
|
|
1326
1426
|
going red. [ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md) is straight about what
|
package/bin/spec-graph.js
CHANGED
|
@@ -8,8 +8,15 @@ import { pathToFileURL } from 'node:url';
|
|
|
8
8
|
// main answers the errors it awaits with exit 2. What nothing awaits - a
|
|
9
9
|
// stream's error, a timer's, a promise nobody holds - Node ends with exit 1,
|
|
10
10
|
// which a script reads as findings: the same answer for those.
|
|
11
|
+
//
|
|
12
|
+
// A reader that closed stdout, as `| head` does, is no defect, and it arrives
|
|
13
|
+
// here, as the stream's error: one line, with no stack to send a person
|
|
14
|
+
// looking for a bug. The code alone names it, since stdout and stderr are the
|
|
15
|
+
// only pipes spec-graph writes to, and a line about a closed stderr reaches
|
|
16
|
+
// nobody.
|
|
11
17
|
process.on('uncaughtException', (error) => {
|
|
12
|
-
|
|
18
|
+
const said = error?.code === 'EPIPE' ? 'stdout was closed before all of the output was written' : `unexpected error: ${error?.stack ?? error}`;
|
|
19
|
+
process.stderr.write(`spec-graph: ${said}\n`);
|
|
13
20
|
process.exit(2);
|
|
14
21
|
});
|
|
15
22
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -78,7 +78,7 @@ export interface CliIO {
|
|
|
78
78
|
readonly env?: Readonly<Record<string, string | undefined>> | undefined;
|
|
79
79
|
readonly isTTY?: boolean | undefined;
|
|
80
80
|
}
|
|
81
|
-
export declare const HELP = "spec-graph - turn Markdown specifications into a verifiable graph\n\nUSAGE\n spec-graph [check] [patterns...] [options]\n spec-graph query <selector|project:rule> [patterns...] [options]\n spec-graph graph [patterns...] [--graph-format dot|mermaid|json]\n spec-graph rules [rule-id] [--explain]\n spec-graph diff <before.json> <after.json> [--format human|json|markdown]\n\nCOMMANDS\n check Validate the specification graph. The default.\n query Run a selector - or a registered project rule, by its id - and\n print the matching paths.\n graph Export the graph for Graphviz, Mermaid, or another tool.\n rules List the diagnostics that will run, built in and project. Name one\n to see only that one; --explain adds its selector and the ADR that\n decided it.\n diff Compare two graph exports: documents added, removed, moved or\n accepted; relations added or removed; and obligations resolved or\n reopened where they can be told apart. Make both exports with the\n same spec-graph. Exits 0 whether anything changed or not.\n\nOPTIONS\n --root <dir> Directory the patterns resolve against. Without it,\n .spec-graph.json is looked for in the working\n directory and then upward as far as the repository,\n and the directory holding it becomes the root - so a\n run from a subdirectory reports what a run from the\n top reports. Paths typed on the command line stay\n relative to where they were typed.\n --ignore <glob> Skip paths. Repeatable.\n --ignore-ref <glob> Do not report these reference targets when they fail\n to resolve, for repositories where [[...]] tags a\n concept rather than naming a file. Repeatable.\n Suppresses findings only, never edges.\n --family <name> Families a bare identifier in prose may name. When\n given, everything else stays prose. Repeatable.\n --ignore-family <name> Families that are never citations - RFC when the repo\n cites RFC 2119 and keeps its own RFCs. Repeatable.\n --history <glob> Files that log what was decided rather than deciding\n it - journals, changelogs, minutes. Their links are\n still checked; their obligations are not. Repeatable.\n --baseline <file> Accept the findings recorded in this file and report\n only what is new since. The file has to be there: a\n path that reads nothing accepts nothing and says so\n nowhere. A \"baseline\" in the configuration may name a\n file not recorded yet; a path typed here may not.\n --record-baseline <f> Write today's findings to this file as accepted debt,\n and exit 0 without judging them.\n --ratchet Also fail when a baseline entry no longer occurs, so\n a paid-off exemption cannot outlive the defect.\n --no-config Ignore .spec-graph.json and the package.json key.\n --format <fmt> human, json, sarif, github, gitlab or markdown. sarif\n is the interchange format GitHub code scanning and\n editors already read, github the workflow commands a\n GitHub Actions log turns into annotations, and gitlab\n the Code Quality report a GitLab merge request reads,\n all three for check; markdown is a table for a\n pull-request comment or $GITHUB_STEP_SUMMARY, for\n check or diff (default: human)\n --graph-format <fmt> dot, mermaid or json (default: dot)\n --documents-only Leave items out of the exported graph\n --rule <id>=<severity> Override one rule: error, warn, info or off. A project\n rule is named in full: project:no-draft-dependency.\n Repeatable.\n --max <n> Show at most n findings (0 = no limit)\n --max-warnings <n> Fail when warnings exceed n (default: no limit)\n --strict Raise every warning to an error. An explicit --rule\n still wins, so --strict --rule x=warn exempts x.\n --color / --no-color Force colour on or off\n --ascii Use ASCII glyphs only\n --verbose Include parse problems, per-file detail, and every\n reference --ignore-ref or --ignore-family silenced\n -h, --help Show this help\n -v, --version Show the version\n\nSELECTORS\n A selector is a path through the graph.\n\n item[openness=open] -delegates-to-> document[phase=retired]\n document[phase=active] -assumes-> document[phase=retired]\n document =supersedes=> document\n *[path^=docs/adr] -contains-> item[state=accepted-debt]\n\n Node types: document, item, * (any)\n Attributes: id, kind, title, path, file, line, phase, status, receptivity,\n alias, document, state (or disposition), openness, section,\n text, body, evidence, conflicted, fm.<front-matter-key>\n Operators: = != ^= $= *= ~= and [attr] for \"is present\"\n ~= is a regular expression, matched by an automaton that cannot\n backtrack: linear in the subject, whatever the pattern. It reads\n the usual syntax minus backreferences and lookaround, which are\n not regular - both are refused when the selector is read, with\n the character pointed at\n Relations: -kind-> <-kind- =kind=> <=kind= (= forms are transitive)\n\nEXIT CODES\n 0 clean\n 1 findings at error severity (or over --max-warnings)\n 2 the tool could not run\n\nCONFIGURATION\n Anything repeated on every run belongs in the repository rather than in the\n command. spec-graph reads the first of these that exists:\n\n .spec-graph.json, spec-graph.config.json, or a \"spec-graph\" key in\n package.json\n\n { \"patterns\": [\"docs/**/*.md\"],\n \"ignoreReferences\": [\"trap *\"],\n \"ignoreFamilies\": [\"RFC\"],\n \"historyPatterns\": [\"**/JOURNAL_*.md\", \"archive/**\"],\n \"baseline\": \".spec-graph-baseline.json\",\n \"severities\": { \"self-reference\": \"off\" },\n \"strict\": true,\n \"maxRelated\": 3 }\n\n A flag always wins over the file, and list flags add to it rather than\n replacing it. maxRelated has no flag: it caps how many related locations one\n finding lists, 8 unless set, and 0 lists none.\n\n A problem in that file stops the run with exit 2, named on stderr: invalid\n JSON, an unknown key, a rule that does not compile. A configuration that did\n not load checks a different repository than the one configured, and would\n report that one as consistent. --no-config runs on defaults instead.\n\nPROJECT RULES\n A convention spec-graph never anticipated is a selector plus a sentence, and\n belongs in the same file. Every rule declared here runs beside the built-ins\n and is reported, baselined, escalated by --strict and silenced by --rule in\n exactly the same way.\n\n { \"rules\": {\n \"no-draft-dependency\": {\n \"query\": \"document[phase=active] -depends-on-> document[phase=draft]\",\n \"message\": \"{0} depends on {1}, which is still a draft\",\n \"hint\": \"wait for {1} to be accepted, or drop it from {0.path}\",\n \"severity\": \"error\" } } }\n\n query One selector, or a list of them read as a union.\n message The headline. {0} is the first node on the path, {1} the next;\n {1.phase} and {0.fm.owner} read any selector attribute.\n hint The next action. Optional, and templated the same way.\n severity error, warn, info or off. Defaults to warn - a rule a team has\n just written has not yet earned the right to fail their build.\n\n The id is the name with project: in front, which is why it can never collide\n with a built-in. A selector that does not parse, or a {2} the query can never\n reach, is reported when the file is read rather than found missing later.\n\n To see what one matches without copying its selector out of the file:\n\n spec-graph query project:no-draft-dependency --verbose\n\nADOPTING THIS ON AN OLD REPOSITORY\n Record what is already wrong, then report only what happens next:\n\n spec-graph check --record-baseline .spec-graph-baseline.json\n git add .spec-graph-baseline.json\n\n The file is keyed by specification and citation, not by line number, so it\n survives edits, moves and renames. Findings that stop occurring are reported\n so the file can be tightened; nothing new gets in.\n\nEXAMPLES\n spec-graph \"docs/**/*.md\"\n spec-graph check --rule self-reference=off --format json\n spec-graph query 'item[openness=open] -delegates-to-> document[phase=retired]'\n spec-graph check --ignore-ref \"trap *\" # [[trap 55]] tags a concept, not a file\n spec-graph graph --documents-only --graph-format mermaid > graph.mmd\n spec-graph check --history \"**/JOURNAL_*.md\" # a log is not a specification\n spec-graph check --baseline .spec-graph-baseline.json\n spec-graph rules --explain # including this repository's own\n spec-graph rules ghost-handover --explain # and why it exists\n spec-graph check --rule project:no-draft-dependency=off\n spec-graph query project:no-draft-dependency # what does that rule match?\n spec-graph check --format markdown >> \"$GITHUB_STEP_SUMMARY\"\n spec-graph check --format github # annotations from an Actions log\n spec-graph check --format gitlab > gl-code-quality-report.json\n spec-graph diff base.json head.json --format markdown >> \"$GITHUB_STEP_SUMMARY\"\n";
|
|
81
|
+
export declare const HELP = "spec-graph - turn Markdown specifications into a verifiable graph\n\nUSAGE\n spec-graph [check] [patterns...] [options]\n spec-graph query <selector|project:rule> [patterns...] [options]\n spec-graph graph [patterns...] [--graph-format dot|mermaid|json]\n spec-graph rules [rule-id] [--explain]\n spec-graph diff <before.json> <after.json> [--format human|json|markdown]\n\nCOMMANDS\n check Validate the specification graph. The default.\n query Run a selector - or a registered project rule, by its id - and\n print the matching paths.\n graph Export the graph for Graphviz, Mermaid, or another tool.\n rules List the diagnostics that will run, built in and project. Name one\n to see only that one; --explain adds its selector and the ADR that\n decided it.\n diff Compare two graph exports: documents added, removed, moved or\n accepted; relations added or removed; and obligations resolved or\n reopened where they can be told apart. Make both exports with the\n same spec-graph. Exits 0 whether anything changed or not.\n\nOPTIONS\n --root <dir> Directory the patterns resolve against. Without it,\n .spec-graph.json is looked for in the working\n directory and then upward as far as the repository,\n and the directory holding it becomes the root - so a\n run from a subdirectory reports what a run from the\n top reports. Paths typed on the command line stay\n relative to where they were typed. It has to be a\n directory that is there.\n --ignore <glob> Skip paths. Repeatable.\n --ignore-ref <glob> Do not report these reference targets when they fail\n to resolve, for repositories where [[...]] tags a\n concept rather than naming a file. Repeatable.\n Suppresses findings only, never edges.\n --family <name> Families a bare identifier in prose may name. When\n given, everything else stays prose. Repeatable: one\n name each time, the prefix its identifiers are\n written with, ADR for ADR-0007. A document here has\n to belong to one of them, or the check stops: a list\n that names none allows nothing.\n --ignore-family <name> Families that are never citations - RFC when the repo\n cites RFC 2119 and keeps its own RFCs. Repeatable,\n one name each time.\n --history <glob> Files that log what was decided rather than deciding\n it - journals, changelogs, minutes. Their links are\n still checked; their obligations are not. Repeatable.\n --baseline <file> Accept the findings recorded in this file and report\n only what is new since. The file has to be there: a\n path that reads nothing accepts nothing and says so\n nowhere. A \"baseline\" in the configuration may name a\n file not recorded yet; a path typed here may not.\n --record-baseline <f> Write today's findings to this file as accepted debt,\n and exit 0 without judging them.\n --ratchet Also fail when a baseline entry no longer occurs, so\n a paid-off exemption cannot outlive the defect.\n --no-config Ignore .spec-graph.json and the package.json key.\n --format <fmt> human, json, sarif, github, gitlab or markdown. json\n is for check, query or diff. sarif is the interchange\n format GitHub code scanning and editors already read,\n github the workflow commands a GitHub Actions log\n turns into annotations, and gitlab the Code Quality\n report a GitLab merge request reads, all three for\n check; markdown is a table for a pull-request comment\n or $GITHUB_STEP_SUMMARY, for check or diff (default:\n human)\n --graph-format <fmt> dot, mermaid or json (default: dot)\n --documents-only Leave items out of the exported graph\n --rule <id>=<severity> Override one rule: error, warn, info or off. A project\n rule is named in full: project:no-draft-dependency.\n Repeatable.\n --max <n> Show at most n findings (0 = no limit)\n --max-warnings <n> Fail when warnings exceed n (default: no limit)\n --strict Raise every warning to an error. An explicit --rule\n still wins, so --strict --rule x=warn exempts x.\n --color / --no-color Force colour on or off\n --ascii Use ASCII glyphs only. SPEC_GRAPH_ASCII asks for the\n same, unless it is empty, 0 or false\n --verbose Include parse problems, per-file detail, and every\n reference --ignore-ref or --ignore-family silenced\n --explain With rules: add each rule's selector and the ADR\n that decided it\n -h, --help Show this help\n -v, --version Show the version\n\n An option belongs to the commands that read it, and any other command\n refuses it by name:\n\n --root, --verbose check, query, graph, rules\n --ignore, --history check, query, graph\n --format check, query, diff\n --graph-format, --documents-only graph\n --explain rules\n every other option check\n\n --no-config, --no-color and --ascii are taken by every command: each is\n true already of a command with nothing to read it for.\n\n A value that begins with -- reads as an option, so the option before it is\n refused as missing its value. A name that does begin so is written ./--name\n for a file, [-]-name in a pattern and \\--name for a reference target.\n\nSELECTORS\n A selector is a path through the graph.\n\n item[openness=open] -delegates-to-> document[phase=retired]\n document[phase=active] -assumes-> document[phase=retired]\n document =supersedes=> document\n *[path^=docs/adr] -contains-> item[state=accepted-debt]\n\n Node types: document, item, * (any)\n Attributes: id, kind, title, path, file, line, phase, status, receptivity,\n alias, document, state (or disposition), openness, section,\n text, body, evidence, conflicted, fm.<front-matter-key>\n Operators: = != ^= $= *= ~= and [attr] for \"is present\"\n ~= is a regular expression, matched by an automaton that cannot\n backtrack: linear in the subject, whatever the pattern. It reads\n the usual syntax minus backreferences and lookaround, which are\n not regular - both are refused when the selector is read, with\n the character pointed at\n Relations: -kind-> <-kind- =kind=> <=kind= (= forms are transitive)\n\nEXIT CODES\n 0 clean\n 1 findings at error severity (or over --max-warnings)\n 2 the tool could not run\n\n An input that is set and names nothing is a 2, named on stderr, and never\n read as if it had not been given: an empty value, a family name no family\n has, a list of families no document here belongs to, a --root that is no\n directory, a second word after rules, an option of another command.\n\nCONFIGURATION\n Anything repeated on every run belongs in the repository rather than in the\n command. spec-graph reads the first of these that exists:\n\n .spec-graph.json, spec-graph.config.json, or a \"spec-graph\" key in\n package.json\n\n { \"patterns\": [\"docs/**/*.md\"],\n \"ignoreReferences\": [\"trap *\"],\n \"ignoreFamilies\": [\"RFC\"],\n \"historyPatterns\": [\"**/JOURNAL_*.md\", \"archive/**\"],\n \"baseline\": \".spec-graph-baseline.json\",\n \"severities\": { \"self-reference\": \"off\" },\n \"strict\": true,\n \"maxRelated\": 3 }\n\n A flag always wins over the file, and list flags add to it rather than\n replacing it. maxRelated has no flag: it caps how many related locations one\n finding lists, 8 unless set, and 0 lists none.\n\n A problem in that file stops the run with exit 2, named on stderr: invalid\n JSON, an unknown key, a rule that does not compile, a file that is there and\n cannot be read. A configuration that did not load checks a different\n repository than the one configured, and would report that one as consistent.\n --no-config runs on defaults instead.\n\nPROJECT RULES\n A convention spec-graph never anticipated is a selector plus a sentence, and\n belongs in the same file. Every rule declared here runs beside the built-ins\n and is reported, baselined, escalated by --strict and silenced by --rule in\n exactly the same way.\n\n { \"rules\": {\n \"no-draft-dependency\": {\n \"query\": \"document[phase=active] -depends-on-> document[phase=draft]\",\n \"message\": \"{0} depends on {1}, which is still a draft\",\n \"hint\": \"wait for {1} to be accepted, or drop it from {0.path}\",\n \"severity\": \"error\" } } }\n\n query One selector, or a list of them read as a union.\n message The headline. {0} is the first node on the path, {1} the next;\n {1.phase} and {0.fm.owner} read any selector attribute.\n hint The next action. Optional, and templated the same way.\n severity error, warn, info or off. Defaults to warn - a rule a team has\n just written has not yet earned the right to fail their build.\n\n The id is the name with project: in front, which is why it can never collide\n with a built-in. A selector that does not parse, or a {2} the query can never\n reach, is reported when the file is read rather than found missing later.\n\n To see what one matches without copying its selector out of the file:\n\n spec-graph query project:no-draft-dependency --verbose\n\nADOPTING THIS ON AN OLD REPOSITORY\n Record what is already wrong, then report only what happens next:\n\n spec-graph check --record-baseline .spec-graph-baseline.json\n git add .spec-graph-baseline.json\n\n The file is keyed by specification and citation, not by line number, so it\n survives edits, moves and renames. Findings that stop occurring are reported\n so the file can be tightened; nothing new gets in.\n\nEXAMPLES\n spec-graph \"docs/**/*.md\"\n spec-graph check --rule self-reference=off --format json\n spec-graph query 'item[openness=open] -delegates-to-> document[phase=retired]'\n spec-graph check --ignore-ref \"trap *\" # [[trap 55]] tags a concept, not a file\n spec-graph graph --documents-only --graph-format mermaid > graph.mmd\n spec-graph check --history \"**/JOURNAL_*.md\" # a log is not a specification\n spec-graph check --baseline .spec-graph-baseline.json\n spec-graph rules --explain # including this repository's own\n spec-graph rules ghost-handover --explain # and why it exists\n spec-graph check --rule project:no-draft-dependency=off\n spec-graph query project:no-draft-dependency # what does that rule match?\n spec-graph check --format markdown >> \"$GITHUB_STEP_SUMMARY\"\n spec-graph check --format github # annotations from an Actions log\n spec-graph check --format gitlab > gl-code-quality-report.json\n spec-graph diff base.json head.json --format markdown >> \"$GITHUB_STEP_SUMMARY\"\n";
|
|
82
82
|
/** Parses argv into options. Throws {@link UsageError} on anything malformed. */
|
|
83
83
|
export declare function parseArgs(argv: readonly string[], cwd: string): CliOptions;
|
|
84
84
|
/**
|
|
@@ -90,5 +90,12 @@ export declare function parseArgs(argv: readonly string[], cwd: string): CliOpti
|
|
|
90
90
|
* error, exit 1, which CI reads as findings. The stack is what makes a report
|
|
91
91
|
* of it something to act on, and it goes to stderr alone: a script that reads
|
|
92
92
|
* a document from stdout is handed no part of one.
|
|
93
|
+
*
|
|
94
|
+
* A write its reader had closed the pipe for is not such an error: the answer
|
|
95
|
+
* was not delivered, which is still 2, and nothing in spec-graph is at fault,
|
|
96
|
+
* so it is said in a line and no stack sends a person looking for a defect.
|
|
97
|
+
* The process's own streams report it as an event, which the launcher answers
|
|
98
|
+
* in the same words; here it is a caller's stream that throws it. It is read
|
|
99
|
+
* by its code: stdout and stderr are the only pipes spec-graph writes to.
|
|
93
100
|
*/
|
|
94
101
|
export declare function main(io?: CliIO): Promise<number>;
|