@descent-vtt/spec-graph 0.7.0 → 0.9.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 +477 -0
- package/README.md +109 -17
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +38 -19
- package/dist/cli.js.map +1 -1
- package/dist/directives.d.ts +9 -2
- package/dist/directives.js +15 -4
- package/dist/directives.js.map +1 -1
- package/dist/extract.d.ts +1 -1
- package/dist/extract.js +50 -16
- package/dist/extract.js.map +1 -1
- package/dist/glob.d.ts +44 -44
- package/dist/glob.js +152 -116
- package/dist/glob.js.map +1 -1
- package/dist/identity.d.ts +12 -4
- package/dist/identity.js +32 -8
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.js +10 -2
- package/dist/lifecycle.js.map +1 -1
- package/dist/markdown.d.ts +53 -161
- package/dist/markdown.js +42 -864
- package/dist/markdown.js.map +1 -1
- package/dist/report.d.ts +23 -0
- package/dist/report.js +80 -0
- package/dist/report.js.map +1 -1
- package/dist/rules.js +48 -14
- package/dist/rules.js.map +1 -1
- package/dist/sections.d.ts +1 -1
- package/dist/sections.js +18 -4
- package/dist/sections.js.map +1 -1
- package/dist/select.d.ts +2 -2
- package/dist/select.js +3 -3
- package/dist/select.js.map +1 -1
- package/dist/source.d.ts +6 -19
- package/dist/source.js +4 -70
- package/dist/source.js.map +1 -1
- package/dist/types.d.ts +23 -3
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vendor/spec-core/markdown/frontmatter.d.ts +103 -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 +45 -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 +5 -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 +39 -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 +22 -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 +22 -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 +36 -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 +75 -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 +18 -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 +287 -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 +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 +83 -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 +129 -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 +58 -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 +121 -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 +6 -0
- package/dist/vendor/spec-core/pattern/index.js +4 -0
- package/dist/vendor/spec-core/pattern/index.js.map +1 -0
- package/dist/{regex.d.ts → vendor/spec-core/pattern/regex.d.ts} +20 -29
- package/dist/{regex.js → vendor/spec-core/pattern/regex.js} +40 -49
- package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
- package/dist/vendor/spec-core/text/index.d.ts +2 -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 +72 -0
- package/dist/vendor/spec-core/text/lines.js +156 -0
- package/dist/vendor/spec-core/text/lines.js.map +1 -0
- package/dist/yaml.d.ts +44 -12
- package/dist/yaml.js +115 -206
- package/dist/yaml.js.map +1 -1
- package/package.json +3 -2
- package/src/vendor/spec-core/LICENSE +21 -0
- package/src/vendor/spec-core/README.md +8 -0
- package/dist/regex.js.map +0 -1
package/dist/extract.js
CHANGED
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
import { attr, attrList, bindItemDirectives, parseDirectives } from './directives.js';
|
|
18
18
|
import { identify, isDocumentTarget, isExternal, looksLikePath, normaliseRef, parsePrefixedRef, withinOneEdit, ID_KEYS, } from './identity.js';
|
|
19
19
|
import { isStatusHeading, phaseFromPath, phaseOf, STATUS_KEYS, supersessionTargetsIn } from './lifecycle.js';
|
|
20
|
-
import { scanMarkdown, slugify } from './markdown.js';
|
|
20
|
+
import { anchorsOf, isMarkdownLine, isOnlyComment, referenceLinks, scanMarkdown, slugify, } from './markdown.js';
|
|
21
21
|
import { findSpecificationRegions, regionAt } from './sections.js';
|
|
22
22
|
import { resolveItemState } from './state.js';
|
|
23
23
|
import { refOf } from './source.js';
|
|
24
|
-
import {
|
|
24
|
+
import { readEntries, toRecord, valuesOf } from './yaml.js';
|
|
25
25
|
/* -------------------------------------------------------------------------- */
|
|
26
26
|
/* Vocabulary */
|
|
27
27
|
/* -------------------------------------------------------------------------- */
|
|
@@ -158,6 +158,19 @@ const RELATION_INDEX = new Map(Object.entries(RELATION_KEYS).map(([canonical, re
|
|
|
158
158
|
foldRelationKey(canonical),
|
|
159
159
|
{ ...relation, canonical },
|
|
160
160
|
]));
|
|
161
|
+
/**
|
|
162
|
+
* Whether a front-matter key is one the graph is built from: a status, an id
|
|
163
|
+
* or an alias, or a relation. Left unread, each changes a verdict - a status
|
|
164
|
+
* is unknown, a node is named by its path, an edge is missing. A title or a
|
|
165
|
+
* description left unread changes a label.
|
|
166
|
+
*/
|
|
167
|
+
function buildsGraph(key) {
|
|
168
|
+
return (STATUS_KEYS.includes(key) ||
|
|
169
|
+
ID_KEYS.includes(key) ||
|
|
170
|
+
key === 'alias' ||
|
|
171
|
+
key === 'aliases' ||
|
|
172
|
+
RELATION_INDEX.has(foldRelationKey(key)));
|
|
173
|
+
}
|
|
161
174
|
/**
|
|
162
175
|
* Keys a region must answer for itself, so the file's answer cannot shadow one.
|
|
163
176
|
*
|
|
@@ -476,6 +489,17 @@ export function extractDocument(input) {
|
|
|
476
489
|
at: at(nul, nul + 1),
|
|
477
490
|
});
|
|
478
491
|
}
|
|
492
|
+
// CommonMark reads a comment that opens a line and never closes as running
|
|
493
|
+
// to the end of the document, and so does the scan: nothing after it is a
|
|
494
|
+
// heading, an item or a link. A renderer hides it all, so the author may see
|
|
495
|
+
// it, but the graph would lose it without a word.
|
|
496
|
+
const unclosed = scanned.comments.find((comment) => !comment.closed);
|
|
497
|
+
if (unclosed !== undefined) {
|
|
498
|
+
problems.push({
|
|
499
|
+
message: 'a comment opened here is never closed, so nothing after it is read - close it with -->',
|
|
500
|
+
at: at(unclosed.start, unclosed.start + 4),
|
|
501
|
+
});
|
|
502
|
+
}
|
|
479
503
|
for (const directive of directives) {
|
|
480
504
|
for (const unknown of directive.unknownAttributes) {
|
|
481
505
|
problems.push({
|
|
@@ -484,7 +508,13 @@ export function extractDocument(input) {
|
|
|
484
508
|
});
|
|
485
509
|
}
|
|
486
510
|
}
|
|
487
|
-
const entries
|
|
511
|
+
const { entries, problems: unread } = readEntries(scanned);
|
|
512
|
+
for (const problem of unread) {
|
|
513
|
+
// A line that names no key could have held any of them, and so could a
|
|
514
|
+
// block that was not read at all.
|
|
515
|
+
const lost = problem.unread && (problem.key === null || buildsGraph(problem.key));
|
|
516
|
+
problems.push({ message: problem.message, at: at(problem.start, problem.end), ...(lost ? { unread: true } : {}) });
|
|
517
|
+
}
|
|
488
518
|
const byKey = new Map();
|
|
489
519
|
for (const entry of entries)
|
|
490
520
|
byKey.set(entry.key, entry);
|
|
@@ -534,6 +564,7 @@ export function extractDocument(input) {
|
|
|
534
564
|
path: input.path,
|
|
535
565
|
aliases: identity.aliases,
|
|
536
566
|
phase,
|
|
567
|
+
history: record,
|
|
537
568
|
rawStatus: status.raw,
|
|
538
569
|
statusAt: status.at,
|
|
539
570
|
frontMatter: toRecord(entries),
|
|
@@ -587,7 +618,7 @@ export function extractDocument(input) {
|
|
|
587
618
|
const ownItems = allItems.filter((item) => item.document === identity.id);
|
|
588
619
|
const ownReferences = allReferences.filter((reference) => belongsTo(reference, identity.id, allItems));
|
|
589
620
|
const misreadKeys = misreadRelationKeys(byKey, identity.id, at);
|
|
590
|
-
const anchors =
|
|
621
|
+
const anchors = anchorsOf(scanned.headings);
|
|
591
622
|
const filled = subSpecifications.map((spec) => ({
|
|
592
623
|
...spec.extracted,
|
|
593
624
|
items: allItems.filter((item) => item.document === spec.document.id),
|
|
@@ -659,11 +690,12 @@ function buildRegion(context) {
|
|
|
659
690
|
// wrote for itself. Being a record is a statement about the file made from
|
|
660
691
|
// outside it, and it does not stop at a heading.
|
|
661
692
|
phase: record ? 'record' : declaredPhase !== 'unknown' ? declaredPhase : pathPhase,
|
|
693
|
+
history: record,
|
|
662
694
|
rawStatus,
|
|
663
695
|
statusAt,
|
|
664
696
|
frontMatter: inherited,
|
|
665
697
|
};
|
|
666
|
-
const anchors =
|
|
698
|
+
const anchors = anchorsOf(scanned.headings.filter((h) => h.start >= region.start && h.start < region.end));
|
|
667
699
|
// Relations a table declares by column, typed by the header the author wrote.
|
|
668
700
|
const references = region.relations.map((relation) => ({
|
|
669
701
|
kind: relation.kind,
|
|
@@ -744,9 +776,9 @@ function statusSectionBody(scanned, headingLine) {
|
|
|
744
776
|
for (const line of scanned.lines) {
|
|
745
777
|
if (line.line <= headingLine)
|
|
746
778
|
continue;
|
|
747
|
-
if (line.blank)
|
|
779
|
+
if (line.blank || isOnlyComment(scanned, line))
|
|
748
780
|
continue;
|
|
749
|
-
if (line
|
|
781
|
+
if (!isMarkdownLine(line))
|
|
750
782
|
return null;
|
|
751
783
|
const trimmed = line.content.trim();
|
|
752
784
|
// A heading immediately after means the section is empty.
|
|
@@ -960,7 +992,8 @@ function extractReferences(context) {
|
|
|
960
992
|
// so `| ADR-0002 | ... | [ADR-0001](0001.md) |` yields one typed edge rather
|
|
961
993
|
// than a typed edge and a neutral citation beside it.
|
|
962
994
|
const linked = new Set();
|
|
963
|
-
|
|
995
|
+
const links = referenceLinks(scanned);
|
|
996
|
+
for (const link of links) {
|
|
964
997
|
if (link.form === 'definition')
|
|
965
998
|
continue;
|
|
966
999
|
if (isClaimed(claimed, link.start))
|
|
@@ -972,14 +1005,14 @@ function extractReferences(context) {
|
|
|
972
1005
|
continue;
|
|
973
1006
|
const owner = ownerOf(items, link.start) ?? documentAt(link.start).id;
|
|
974
1007
|
const section = sectionPathAt(scanned, link.start);
|
|
975
|
-
const classified = classifyReference(scanned.
|
|
1008
|
+
const classified = classifyReference(scanned.masks.structure, link.start, link.end, section);
|
|
976
1009
|
linked.add(normaliseRef(stripAnchor(target)));
|
|
977
1010
|
out.push({
|
|
978
1011
|
kind: classified.kind,
|
|
979
1012
|
from: owner,
|
|
980
1013
|
target,
|
|
981
1014
|
origin: 'link',
|
|
982
|
-
declaredAt: at(link.targetStart, link.
|
|
1015
|
+
declaredAt: at(link.targetStart, link.targetEnd),
|
|
983
1016
|
raw: renderLink(link),
|
|
984
1017
|
inverted: classified.inverted,
|
|
985
1018
|
opportunistic: false,
|
|
@@ -987,7 +1020,7 @@ function extractReferences(context) {
|
|
|
987
1020
|
}
|
|
988
1021
|
// Bare identifiers in prose. Everything already covered by a link is skipped
|
|
989
1022
|
// so a citation written as `[ADR-7](0007.md)` is not counted twice.
|
|
990
|
-
for (const bare of findBareReferences(scanned)) {
|
|
1023
|
+
for (const bare of findBareReferences(scanned, links)) {
|
|
991
1024
|
const key = normaliseRef(bare.text);
|
|
992
1025
|
if (linked.has(key))
|
|
993
1026
|
continue;
|
|
@@ -995,7 +1028,7 @@ function extractReferences(context) {
|
|
|
995
1028
|
continue;
|
|
996
1029
|
const owner = ownerOf(items, bare.start) ?? documentAt(bare.start).id;
|
|
997
1030
|
const section = sectionPathAt(scanned, bare.start);
|
|
998
|
-
const classified = classifyReference(scanned.
|
|
1031
|
+
const classified = classifyReference(scanned.masks.structure, bare.start, bare.end, section);
|
|
999
1032
|
out.push({
|
|
1000
1033
|
kind: classified.kind,
|
|
1001
1034
|
from: owner,
|
|
@@ -1167,15 +1200,16 @@ function sentenceAfter(text, end) {
|
|
|
1167
1200
|
* Link constructs are blanked first. Without that, `[ADR-7](https://x/adr-7)`
|
|
1168
1201
|
* would yield three references to the same thing - one real and two harvested
|
|
1169
1202
|
* out of a URL - which is precisely the mis-match that makes hand-rolled regex
|
|
1170
|
-
* checks untrustworthy.
|
|
1203
|
+
* checks untrustworthy. Images are not blanked, since they are not references:
|
|
1204
|
+
* an identifier in one's text is prose, as it always was here.
|
|
1171
1205
|
*/
|
|
1172
|
-
function findBareReferences(scanned) {
|
|
1206
|
+
function findBareReferences(scanned, links) {
|
|
1173
1207
|
// Slice-based for the same reason as the scanner's masking: this runs over
|
|
1174
1208
|
// every document, and a per-character array is the wrong shape for the job.
|
|
1175
|
-
const source = scanned.
|
|
1209
|
+
const source = scanned.masks.structure;
|
|
1176
1210
|
let text = '';
|
|
1177
1211
|
let cursor = 0;
|
|
1178
|
-
for (const link of
|
|
1212
|
+
for (const link of links) {
|
|
1179
1213
|
const start = Math.max(link.start, cursor);
|
|
1180
1214
|
const end = Math.min(link.end, source.length);
|
|
1181
1215
|
if (end <= start)
|