@descent-vtt/spec-graph 0.11.1 → 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 +32 -0
- package/README.md +7 -5
- package/dist/extract.d.ts +1 -1
- package/dist/extract.js +26 -4
- package/dist/extract.js.map +1 -1
- package/dist/identity.js +28 -22
- package/dist/identity.js.map +1 -1
- package/dist/sections.js +28 -24
- package/dist/sections.js.map +1 -1
- package/dist/select.js +27 -16
- package/dist/select.js.map +1 -1
- package/dist/state.js +28 -22
- package/dist/state.js.map +1 -1
- package/dist/yaml.js +4 -4
- package/dist/yaml.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,38 @@ 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.12.0
|
|
15
|
+
|
|
16
|
+
Names every JavaScript object answers to - `constructor`, `__proto__` - are
|
|
17
|
+
read as the unknown names they are in seven places, three of which could
|
|
18
|
+
leave a run that passed refusing or finding something now.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- A node type named `constructor` is refused as any unknown type is: a
|
|
23
|
+
query or a project rule written with it matched nothing in silence, and is
|
|
24
|
+
now a usage error, exit 2. Upgrading: write `document`, `item` or `*`.
|
|
25
|
+
- A table column headed `Constructor` declares no relation, where it made
|
|
26
|
+
the table a register and each cell an edge of no kind. Upgrading: a table
|
|
27
|
+
that was a register only by that column needs a `Status` column or a
|
|
28
|
+
relation the README lists.
|
|
29
|
+
- A `@spec-edge` whose `kind` names no relation is a `references` edge, and
|
|
30
|
+
`--verbose` lists it as a parse problem; any other word drew an edge of a
|
|
31
|
+
kind no rule knows, and one to its own document ended the check with exit
|
|
32
|
+
2 (ADR-0014). Upgrading: write one of the eight relations.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- A front-matter key, a `state=` word or a directory named `constructor` or
|
|
37
|
+
`__proto__` no longer ends a query or a check on a TypeError: the key is
|
|
38
|
+
found where it was written, the state is ignored, and a document under
|
|
39
|
+
such a directory keeps its own id.
|
|
40
|
+
|
|
41
|
+
### Documentation
|
|
42
|
+
|
|
43
|
+
- The README's SARIF example pins the actions the workflows run now, and a
|
|
44
|
+
test holds it to them.
|
|
45
|
+
|
|
14
46
|
## 0.11.1
|
|
15
47
|
|
|
16
48
|
Documentation and robustness: the README's SARIF example is pinned as CI
|
package/README.md
CHANGED
|
@@ -552,6 +552,8 @@ Each takes these attributes. Any other is a parse problem, listed by
|
|
|
552
552
|
|
|
553
553
|
- `reason`, `note`, `owner` and a node's `kind` are for whoever reads the
|
|
554
554
|
source; spec-graph reads nothing from them.
|
|
555
|
+
- An edge's `kind` is one of the relations a selector steps along. Any other
|
|
556
|
+
word is a parse problem too, and the edge is read as `references`.
|
|
555
557
|
- `aliases` splits at commas, semicolons and spaces.
|
|
556
558
|
- A value is quoted with either quote mark, or bare when it holds no space or
|
|
557
559
|
quote, and an attribute with no value is a flag.
|
|
@@ -1061,16 +1063,16 @@ permissions:
|
|
|
1061
1063
|
contents: read
|
|
1062
1064
|
security-events: write
|
|
1063
1065
|
steps:
|
|
1064
|
-
- uses: actions/checkout@
|
|
1066
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
1065
1067
|
with:
|
|
1066
1068
|
persist-credentials: false
|
|
1067
|
-
- uses: actions/setup-node@
|
|
1069
|
+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
1068
1070
|
with:
|
|
1069
1071
|
node-version: '24'
|
|
1070
1072
|
- run: npm ci
|
|
1071
1073
|
- run: npx spec-graph --format sarif > spec-graph.sarif
|
|
1072
1074
|
continue-on-error: true
|
|
1073
|
-
- uses: github/codeql-action/upload-sarif@
|
|
1075
|
+
- uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
|
|
1074
1076
|
with:
|
|
1075
1077
|
sarif_file: spec-graph.sarif
|
|
1076
1078
|
```
|
|
@@ -1287,9 +1289,9 @@ tools share, whose code is copied into `src/vendor/` and checked by hash rather
|
|
|
1287
1289
|
than installed. So the whole package is auditable in an afternoon — and nothing
|
|
1288
1290
|
in the pipeline can take longer than its input.
|
|
1289
1291
|
|
|
1290
|
-
**Verified, not just covered.** 1,
|
|
1292
|
+
**Verified, not just covered.** 1,918 tests; 99.4% statement and 99.8% line
|
|
1291
1293
|
coverage. Coverage says a line ran, so the suite is also held to a mutation
|
|
1292
|
-
score - 96.
|
|
1294
|
+
score - 96.38% over 8,539 mutants, measured by CI's full sweep, and a build
|
|
1293
1295
|
fails under 93 - because a vocabulary entry or a boundary
|
|
1294
1296
|
condition can be weakened by an ordinary-looking refactor without a single test
|
|
1295
1297
|
going red. [ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md) is straight about what
|
package/dist/extract.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { type DocumentIdentity } from './identity.js';
|
|
18
18
|
import { type ScannedDocument } from './markdown.js';
|
|
19
|
-
import type
|
|
19
|
+
import { type DocumentNode, type EdgeKind, type EdgeOrigin, type ItemNode, type MisreadKey, type ParseProblem, type SourceRef } from './types.js';
|
|
20
20
|
import { type YamlEntry } from './yaml.js';
|
|
21
21
|
/**
|
|
22
22
|
* A relation that has been read but not yet resolved to a target node.
|
package/dist/extract.js
CHANGED
|
@@ -21,6 +21,7 @@ import { anchorsOf, isMarkdownLine, isOnlyComment, referenceLinks, scanMarkdown,
|
|
|
21
21
|
import { findSpecificationRegions, isRegisterTable, opensHeading, regionAt, } from './sections.js';
|
|
22
22
|
import { resolveItemState } from './state.js';
|
|
23
23
|
import { refOf } from './source.js';
|
|
24
|
+
import { EDGE_KINDS, } from './types.js';
|
|
24
25
|
import { readEntries, toRecord, valuesOf } from './yaml.js';
|
|
25
26
|
/* -------------------------------------------------------------------------- */
|
|
26
27
|
/* Vocabulary */
|
|
@@ -513,6 +514,13 @@ export function extractDocument(input) {
|
|
|
513
514
|
at: at(directive.start, directive.end),
|
|
514
515
|
});
|
|
515
516
|
}
|
|
517
|
+
const kind = directive.name === 'spec-edge' ? attr(directive, 'kind') : null;
|
|
518
|
+
if (kind !== null && !isEdgeKind(kind.value)) {
|
|
519
|
+
problems.push({
|
|
520
|
+
message: `unknown relation "${kind.value}" on @spec-edge, read as references - expected one of: ${EDGE_KINDS.join(', ')}`,
|
|
521
|
+
at: at(kind.start, kind.end),
|
|
522
|
+
});
|
|
523
|
+
}
|
|
516
524
|
}
|
|
517
525
|
const { entries, problems: unread } = readEntries(scanned);
|
|
518
526
|
for (const problem of unread) {
|
|
@@ -981,6 +989,17 @@ function summarise(text) {
|
|
|
981
989
|
function isClaimed(claimed, offset) {
|
|
982
990
|
return claimed.some((range) => offset >= range.start && offset < range.end);
|
|
983
991
|
}
|
|
992
|
+
/**
|
|
993
|
+
* Whether a word a `@spec-edge` gives as its kind is a relation.
|
|
994
|
+
*
|
|
995
|
+
* Asked of the list, as a selector's relation is: the word was once taken as
|
|
996
|
+
* it stood, so `kind="blocks"` made an edge of a kind no rule knows, a
|
|
997
|
+
* document with such an edge to itself ended the run, and `kind="constructor"`
|
|
998
|
+
* did not, since the table of kinds is an object and answers to that name.
|
|
999
|
+
*/
|
|
1000
|
+
function isEdgeKind(word) {
|
|
1001
|
+
return EDGE_KINDS.includes(word);
|
|
1002
|
+
}
|
|
984
1003
|
function extractReferences(context) {
|
|
985
1004
|
const { scanned, directives, document, documentAt, items, byKey, status, claimed, file, index } = context;
|
|
986
1005
|
// This list and the one `withoutOverlaps` builds from it are only ever read
|
|
@@ -1035,11 +1054,14 @@ function extractReferences(context) {
|
|
|
1035
1054
|
for (const directive of directives) {
|
|
1036
1055
|
if (directive.name !== 'spec-edge')
|
|
1037
1056
|
continue;
|
|
1038
|
-
const
|
|
1057
|
+
const written = attr(directive, 'kind')?.value;
|
|
1039
1058
|
const to = attr(directive, 'to');
|
|
1040
1059
|
const from = attr(directive, 'from');
|
|
1041
|
-
if (!
|
|
1060
|
+
if (!written)
|
|
1042
1061
|
continue;
|
|
1062
|
+
// A word that names no relation is still a link to somewhere, as a cell
|
|
1063
|
+
// under a column that names none is: a citation, and no more than one.
|
|
1064
|
+
const kind = isEdgeKind(written) ? written : 'references';
|
|
1043
1065
|
const owner = ownerOf(items, directive.start) ?? documentAt(directive.start).id;
|
|
1044
1066
|
if (to) {
|
|
1045
1067
|
out.push({
|
|
@@ -1048,7 +1070,7 @@ function extractReferences(context) {
|
|
|
1048
1070
|
target: to.value,
|
|
1049
1071
|
origin: 'directive',
|
|
1050
1072
|
declaredAt: at(to.start, to.end),
|
|
1051
|
-
raw: `@spec-edge kind="${
|
|
1073
|
+
raw: `@spec-edge kind="${written}" to="${to.value}"`,
|
|
1052
1074
|
inverted: false,
|
|
1053
1075
|
opportunistic: false,
|
|
1054
1076
|
});
|
|
@@ -1060,7 +1082,7 @@ function extractReferences(context) {
|
|
|
1060
1082
|
target: from.value,
|
|
1061
1083
|
origin: 'directive',
|
|
1062
1084
|
declaredAt: at(from.start, from.end),
|
|
1063
|
-
raw: `@spec-edge kind="${
|
|
1085
|
+
raw: `@spec-edge kind="${written}" from="${from.value}"`,
|
|
1064
1086
|
inverted: true,
|
|
1065
1087
|
opportunistic: false,
|
|
1066
1088
|
});
|