@descent-vtt/spec-graph 0.9.9 → 0.10.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +132 -2
  2. package/README.md +523 -308
  3. package/dist/cli.d.ts +2 -2
  4. package/dist/cli.js +112 -67
  5. package/dist/cli.js.map +1 -1
  6. package/dist/extract.d.ts +14 -1
  7. package/dist/extract.js +114 -10
  8. package/dist/extract.js.map +1 -1
  9. package/dist/glob.d.ts +17 -2
  10. package/dist/glob.js +137 -34
  11. package/dist/glob.js.map +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/lifecycle.d.ts +11 -1
  16. package/dist/lifecycle.js +187 -28
  17. package/dist/lifecycle.js.map +1 -1
  18. package/dist/report.d.ts +22 -0
  19. package/dist/report.js +50 -3
  20. package/dist/report.js.map +1 -1
  21. package/dist/sections.d.ts +7 -1
  22. package/dist/sections.js +10 -2
  23. package/dist/sections.js.map +1 -1
  24. package/dist/state.js +19 -3
  25. package/dist/state.js.map +1 -1
  26. package/dist/vendor/spec-core/markdown/frontmatter.d.ts +11 -1
  27. package/dist/vendor/spec-core/markdown/frontmatter.js +20 -3
  28. package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -1
  29. package/dist/vendor/spec-core/pattern/glob.d.ts +88 -2
  30. package/dist/vendor/spec-core/pattern/glob.js +234 -32
  31. package/dist/vendor/spec-core/pattern/glob.js.map +1 -1
  32. package/dist/vendor/spec-core/pattern/index.d.ts +2 -2
  33. package/dist/vendor/spec-core/pattern/index.js +1 -1
  34. package/dist/vendor/spec-core/pattern/index.js.map +1 -1
  35. package/dist/vendor/spec-core/text/index.d.ts +1 -0
  36. package/dist/vendor/spec-core/text/index.js +1 -0
  37. package/dist/vendor/spec-core/text/index.js.map +1 -1
  38. package/dist/vendor/spec-core/text/width.d.ts +30 -0
  39. package/dist/vendor/spec-core/text/width.js +113 -0
  40. package/dist/vendor/spec-core/text/width.js.map +1 -0
  41. package/dist/yaml.js +6 -2
  42. package/dist/yaml.js.map +1 -1
  43. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEtI,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { compileGlob, globCovers, globWitness, isGlobSyntax, parseGlob, parseGlobList, GlobError, MAX_ALTERNATIVES } from './glob.js';\nexport type { Glob, GlobDialect, GlobList, GlobListParse, GlobOptions, GlobParse, LiteralReading } from './glob.js';\nexport { AutomatonTooLarge, MAX_STATES, WITNESS_BUDGET } from './automaton.js';\nexport type { Witness } from './automaton.js';\nexport { compileRegex, RegexError } from './regex.js';\nexport type { RegexMatcher, RegexOptions } from './regex.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,YAAY,EACZ,SAAS,EACT,aAAa,EACb,UAAU,EACV,SAAS,EACT,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAanB,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export {\n compileGlob,\n globAlternatives,\n globCovers,\n globWitness,\n isGlobSyntax,\n parseGlob,\n parseGlobList,\n rebaseGlob,\n GlobError,\n MAX_ALTERNATIVES,\n} from './glob.js';\nexport type {\n Glob,\n GlobAlternative,\n GlobAlternatives,\n GlobDialect,\n GlobList,\n GlobListParse,\n GlobOptions,\n GlobParse,\n GlobRebase,\n LiteralReading,\n} from './glob.js';\nexport { AutomatonTooLarge, MAX_STATES, WITNESS_BUDGET } from './automaton.js';\nexport type { Witness } from './automaton.js';\nexport { compileRegex, RegexError } from './regex.js';\nexport type { RegexMatcher, RegexOptions } from './regex.js';\n"]}
@@ -1,2 +1,3 @@
1
1
  export { createLineIndex, inRanges, lineEnding, lineStarts, locate, maskRanges, mergeRanges, splitLines, stripBom, } from './lines.js';
2
2
  export type { LineIndex, Position, Range } from './lines.js';
3
+ export { displayWidth } from './width.js';
@@ -1,2 +1,3 @@
1
1
  export { createLineIndex, inRanges, lineEnding, lineStarts, locate, maskRanges, mergeRanges, splitLines, stripBom, } from './lines.js';
2
+ export { displayWidth } from './width.js';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,UAAU,EACV,UAAU,EACV,MAAM,EACN,UAAU,EACV,WAAW,EACX,UAAU,EACV,QAAQ,GACT,MAAM,YAAY,CAAC","sourcesContent":["export {\n createLineIndex,\n inRanges,\n lineEnding,\n lineStarts,\n locate,\n maskRanges,\n mergeRanges,\n splitLines,\n stripBom,\n} from './lines.js';\nexport type { LineIndex, Position, Range } from './lines.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,UAAU,EACV,UAAU,EACV,MAAM,EACN,UAAU,EACV,WAAW,EACX,UAAU,EACV,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export {\n createLineIndex,\n inRanges,\n lineEnding,\n lineStarts,\n locate,\n maskRanges,\n mergeRanges,\n splitLines,\n stripBom,\n} from './lines.js';\nexport type { LineIndex, Position, Range } from './lines.js';\nexport { displayWidth } from './width.js';\n"]}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * How many columns of a terminal a text takes, for a tool that lines up the
3
+ * columns of a table it prints: `.padEnd` counts UTF-16 units, and `已接受`
4
+ * is three of them and six columns.
5
+ *
6
+ * Counted per grapheme cluster, as a terminal draws one: a cluster takes the
7
+ * width of the first character in it that shows, and what follows that
8
+ * character - a combining mark, a variation selector, a joiner and what it
9
+ * joins - adds nothing.
10
+ *
11
+ * - An East Asian Wide or Fullwidth character takes two: Han, kana and
12
+ * hangul, full-width forms, and most emoji.
13
+ * - So does an emoji sequence, whatever its first character's own width: an
14
+ * emoji and the presentation selector U+FE0F (`❤` with it, and a keycap),
15
+ * a modifier base and a skin tone (`☝` with one), and a flag, two
16
+ * regional indicators.
17
+ * - A cluster of nothing that shows takes none: combining marks, format
18
+ * characters - the zero-width space and joiners, the byte-order mark, the
19
+ * bidirectional controls - and control characters. A soft hyphen shows, as
20
+ * terminals draw one.
21
+ * - Everything else takes one, East Asian Ambiguous included, as a terminal
22
+ * draws it outside a legacy East Asian mode.
23
+ *
24
+ * The widths are the table below, fixed. Grapheme clusters and general
25
+ * categories are the runtime's, and a runtime knows the characters of its
26
+ * own Unicode version: only a character assigned after the older of two
27
+ * hosts' versions can be counted differently on them.
28
+ */
29
+ /** The columns a text takes in a terminal. */
30
+ export declare function displayWidth(text: string): number;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * How many columns of a terminal a text takes, for a tool that lines up the
3
+ * columns of a table it prints: `.padEnd` counts UTF-16 units, and `已接受`
4
+ * is three of them and six columns.
5
+ *
6
+ * Counted per grapheme cluster, as a terminal draws one: a cluster takes the
7
+ * width of the first character in it that shows, and what follows that
8
+ * character - a combining mark, a variation selector, a joiner and what it
9
+ * joins - adds nothing.
10
+ *
11
+ * - An East Asian Wide or Fullwidth character takes two: Han, kana and
12
+ * hangul, full-width forms, and most emoji.
13
+ * - So does an emoji sequence, whatever its first character's own width: an
14
+ * emoji and the presentation selector U+FE0F (`❤` with it, and a keycap),
15
+ * a modifier base and a skin tone (`☝` with one), and a flag, two
16
+ * regional indicators.
17
+ * - A cluster of nothing that shows takes none: combining marks, format
18
+ * characters - the zero-width space and joiners, the byte-order mark, the
19
+ * bidirectional controls - and control characters. A soft hyphen shows, as
20
+ * terminals draw one.
21
+ * - Everything else takes one, East Asian Ambiguous included, as a terminal
22
+ * draws it outside a legacy East Asian mode.
23
+ *
24
+ * The widths are the table below, fixed. Grapheme clusters and general
25
+ * categories are the runtime's, and a runtime knows the characters of its
26
+ * own Unicode version: only a character assigned after the older of two
27
+ * hosts' versions can be counted differently on them.
28
+ */
29
+ /**
30
+ * The East Asian Wide and Fullwidth code points of Unicode 16.0.0
31
+ * (EastAsianWidth-16.0.0.txt), the unassigned ones its `@missing` lines
32
+ * make Wide included, as the first and last of each run, in order.
33
+ *
34
+ * 16.0 is the version both supported lines have: Node 22.16.0 reports
35
+ * `process.versions.unicode` 16.0, and Node 24.18.1 17.0, which Node 22 does
36
+ * not ship. A character is counted as the older line knows it; one 17.0
37
+ * added counts one, as it does on a host that cannot name it.
38
+ */
39
+ const WIDE = [
40
+ 0x1100, 0x115f, 0x231a, 0x231b, 0x2329, 0x232a, 0x23e9, 0x23ec, 0x23f0, 0x23f0, 0x23f3, 0x23f3,
41
+ 0x25fd, 0x25fe, 0x2614, 0x2615, 0x2630, 0x2637, 0x2648, 0x2653, 0x267f, 0x267f, 0x268a, 0x268f,
42
+ 0x2693, 0x2693, 0x26a1, 0x26a1, 0x26aa, 0x26ab, 0x26bd, 0x26be, 0x26c4, 0x26c5, 0x26ce, 0x26ce,
43
+ 0x26d4, 0x26d4, 0x26ea, 0x26ea, 0x26f2, 0x26f3, 0x26f5, 0x26f5, 0x26fa, 0x26fa, 0x26fd, 0x26fd,
44
+ 0x2705, 0x2705, 0x270a, 0x270b, 0x2728, 0x2728, 0x274c, 0x274c, 0x274e, 0x274e, 0x2753, 0x2755,
45
+ 0x2757, 0x2757, 0x2795, 0x2797, 0x27b0, 0x27b0, 0x27bf, 0x27bf, 0x2b1b, 0x2b1c, 0x2b50, 0x2b50,
46
+ 0x2b55, 0x2b55, 0x2e80, 0x2e99, 0x2e9b, 0x2ef3, 0x2f00, 0x2fd5, 0x2ff0, 0x303e, 0x3041, 0x3096,
47
+ 0x3099, 0x30ff, 0x3105, 0x312f, 0x3131, 0x318e, 0x3190, 0x31e5, 0x31ef, 0x321e, 0x3220, 0x3247,
48
+ 0x3250, 0xa48c, 0xa490, 0xa4c6, 0xa960, 0xa97c, 0xac00, 0xd7a3, 0xf900, 0xfaff, 0xfe10, 0xfe19,
49
+ 0xfe30, 0xfe52, 0xfe54, 0xfe66, 0xfe68, 0xfe6b, 0xff01, 0xff60, 0xffe0, 0xffe6, 0x16fe0, 0x16fe4,
50
+ 0x16ff0, 0x16ff1, 0x17000, 0x187f7, 0x18800, 0x18cd5, 0x18cff, 0x18d08, 0x1aff0, 0x1aff3,
51
+ 0x1aff5, 0x1affb, 0x1affd, 0x1affe, 0x1b000, 0x1b122, 0x1b132, 0x1b132, 0x1b150, 0x1b152,
52
+ 0x1b155, 0x1b155, 0x1b164, 0x1b167, 0x1b170, 0x1b2fb, 0x1d300, 0x1d356, 0x1d360, 0x1d376,
53
+ 0x1f004, 0x1f004, 0x1f0cf, 0x1f0cf, 0x1f18e, 0x1f18e, 0x1f191, 0x1f19a, 0x1f200, 0x1f202,
54
+ 0x1f210, 0x1f23b, 0x1f240, 0x1f248, 0x1f250, 0x1f251, 0x1f260, 0x1f265, 0x1f300, 0x1f320,
55
+ 0x1f32d, 0x1f335, 0x1f337, 0x1f37c, 0x1f37e, 0x1f393, 0x1f3a0, 0x1f3ca, 0x1f3cf, 0x1f3d3,
56
+ 0x1f3e0, 0x1f3f0, 0x1f3f4, 0x1f3f4, 0x1f3f8, 0x1f43e, 0x1f440, 0x1f440, 0x1f442, 0x1f4fc,
57
+ 0x1f4ff, 0x1f53d, 0x1f54b, 0x1f54e, 0x1f550, 0x1f567, 0x1f57a, 0x1f57a, 0x1f595, 0x1f596,
58
+ 0x1f5a4, 0x1f5a4, 0x1f5fb, 0x1f64f, 0x1f680, 0x1f6c5, 0x1f6cc, 0x1f6cc, 0x1f6d0, 0x1f6d2,
59
+ 0x1f6d5, 0x1f6d7, 0x1f6dc, 0x1f6df, 0x1f6eb, 0x1f6ec, 0x1f6f4, 0x1f6fc, 0x1f7e0, 0x1f7eb,
60
+ 0x1f7f0, 0x1f7f0, 0x1f90c, 0x1f93a, 0x1f93c, 0x1f945, 0x1f947, 0x1f9ff, 0x1fa70, 0x1fa7c,
61
+ 0x1fa80, 0x1fa89, 0x1fa8f, 0x1fac6, 0x1face, 0x1fadc, 0x1fadf, 0x1fae9, 0x1faf0, 0x1faf8,
62
+ 0x20000, 0x2fffd, 0x30000, 0x3fffd,
63
+ ];
64
+ /** A character that shows: anything but a control, a format character or a mark, and the soft hyphen. */
65
+ const SHOWN = /[^\p{Cc}\p{Cf}\p{Mn}\p{Me}]|\u00ad/u;
66
+ /**
67
+ * The start of an emoji sequence a terminal draws as one wide picture: an
68
+ * emoji and the presentation selector, a modifier base and its modifier, or
69
+ * two regional indicators, a flag.
70
+ */
71
+ const EMOJI_SEQUENCE = /^(?:\p{Emoji}\ufe0f|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}|\p{Regional_Indicator}{2})/u;
72
+ // Made the first time a width is asked for: loading the segmentation rules
73
+ // costs milliseconds that a tool which never measures a string - every one
74
+ // that copies this module for its line tables - would pay on each start.
75
+ let graphemes;
76
+ /** The columns a text takes in a terminal. */
77
+ export function displayWidth(text) {
78
+ // A named locale, so the host's default is never read; clusters are the
79
+ // same in every locale, and they are what a segmenter gives unless told
80
+ // otherwise.
81
+ graphemes ??= new Intl.Segmenter('en');
82
+ let width = 0;
83
+ for (const { segment } of graphemes.segment(text))
84
+ width += clusterWidth(segment);
85
+ return width;
86
+ }
87
+ function clusterWidth(cluster) {
88
+ const at = cluster.search(SHOWN);
89
+ if (at < 0)
90
+ return 0;
91
+ const shown = cluster.slice(at);
92
+ return isWide(shown.codePointAt(0)) || EMOJI_SEQUENCE.test(shown) ? 2 : 1;
93
+ }
94
+ /**
95
+ * Whether a code point is in {@link WIDE}, by bisection over its runs. The
96
+ * search is half-open, as `inRanges`'s is: `high` is one past the last run
97
+ * still in question.
98
+ */
99
+ function isWide(point) {
100
+ let low = 0;
101
+ let high = WIDE.length / 2;
102
+ while (low < high) {
103
+ const mid = (low + high) >> 1;
104
+ if (point < WIDE[2 * mid])
105
+ high = mid;
106
+ else if (point > WIDE[2 * mid + 1])
107
+ low = mid + 1;
108
+ else
109
+ return true;
110
+ }
111
+ return false;
112
+ }
113
+ //# sourceMappingURL=width.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"width.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/text/width.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;;;;;GASG;AACH,MAAM,IAAI,GAAsB;IAC9B,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC9F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAChG,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACxF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;CACnC,CAAC;AAEF,yGAAyG;AACzG,MAAM,KAAK,GAAG,qCAAqC,CAAC;AAEpD;;;;GAIG;AACH,MAAM,cAAc,GAAG,2FAA2F,CAAC;AAEnH,2EAA2E;AAC3E,2EAA2E;AAC3E,yEAAyE;AACzE,IAAI,SAAqC,CAAC;AAE1C,8CAA8C;AAC9C,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,wEAAwE;IACxE,wEAAwE;IACxE,aAAa;IACb,SAAS,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,KAAK,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,OAAe;IACnC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACrB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChC,OAAO,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAW,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtF,CAAC;AAED;;;;GAIG;AACH,SAAS,MAAM,CAAC,KAAa;IAC3B,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3B,OAAO,GAAG,GAAG,IAAI,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,KAAK,GAAI,IAAI,CAAC,CAAC,GAAG,GAAG,CAAY;YAAE,IAAI,GAAG,GAAG,CAAC;aAC7C,IAAI,KAAK,GAAI,IAAI,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAY;YAAE,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;;YACzD,OAAO,IAAI,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * How many columns of a terminal a text takes, for a tool that lines up the\n * columns of a table it prints: `.padEnd` counts UTF-16 units, and `已接受`\n * is three of them and six columns.\n *\n * Counted per grapheme cluster, as a terminal draws one: a cluster takes the\n * width of the first character in it that shows, and what follows that\n * character - a combining mark, a variation selector, a joiner and what it\n * joins - adds nothing.\n *\n * - An East Asian Wide or Fullwidth character takes two: Han, kana and\n * hangul, full-width forms, and most emoji.\n * - So does an emoji sequence, whatever its first character's own width: an\n * emoji and the presentation selector U+FE0F (`❤` with it, and a keycap),\n * a modifier base and a skin tone (`☝` with one), and a flag, two\n * regional indicators.\n * - A cluster of nothing that shows takes none: combining marks, format\n * characters - the zero-width space and joiners, the byte-order mark, the\n * bidirectional controls - and control characters. A soft hyphen shows, as\n * terminals draw one.\n * - Everything else takes one, East Asian Ambiguous included, as a terminal\n * draws it outside a legacy East Asian mode.\n *\n * The widths are the table below, fixed. Grapheme clusters and general\n * categories are the runtime's, and a runtime knows the characters of its\n * own Unicode version: only a character assigned after the older of two\n * hosts' versions can be counted differently on them.\n */\n\n/**\n * The East Asian Wide and Fullwidth code points of Unicode 16.0.0\n * (EastAsianWidth-16.0.0.txt), the unassigned ones its `@missing` lines\n * make Wide included, as the first and last of each run, in order.\n *\n * 16.0 is the version both supported lines have: Node 22.16.0 reports\n * `process.versions.unicode` 16.0, and Node 24.18.1 17.0, which Node 22 does\n * not ship. A character is counted as the older line knows it; one 17.0\n * added counts one, as it does on a host that cannot name it.\n */\nconst WIDE: readonly number[] = [\n 0x1100, 0x115f, 0x231a, 0x231b, 0x2329, 0x232a, 0x23e9, 0x23ec, 0x23f0, 0x23f0, 0x23f3, 0x23f3,\n 0x25fd, 0x25fe, 0x2614, 0x2615, 0x2630, 0x2637, 0x2648, 0x2653, 0x267f, 0x267f, 0x268a, 0x268f,\n 0x2693, 0x2693, 0x26a1, 0x26a1, 0x26aa, 0x26ab, 0x26bd, 0x26be, 0x26c4, 0x26c5, 0x26ce, 0x26ce,\n 0x26d4, 0x26d4, 0x26ea, 0x26ea, 0x26f2, 0x26f3, 0x26f5, 0x26f5, 0x26fa, 0x26fa, 0x26fd, 0x26fd,\n 0x2705, 0x2705, 0x270a, 0x270b, 0x2728, 0x2728, 0x274c, 0x274c, 0x274e, 0x274e, 0x2753, 0x2755,\n 0x2757, 0x2757, 0x2795, 0x2797, 0x27b0, 0x27b0, 0x27bf, 0x27bf, 0x2b1b, 0x2b1c, 0x2b50, 0x2b50,\n 0x2b55, 0x2b55, 0x2e80, 0x2e99, 0x2e9b, 0x2ef3, 0x2f00, 0x2fd5, 0x2ff0, 0x303e, 0x3041, 0x3096,\n 0x3099, 0x30ff, 0x3105, 0x312f, 0x3131, 0x318e, 0x3190, 0x31e5, 0x31ef, 0x321e, 0x3220, 0x3247,\n 0x3250, 0xa48c, 0xa490, 0xa4c6, 0xa960, 0xa97c, 0xac00, 0xd7a3, 0xf900, 0xfaff, 0xfe10, 0xfe19,\n 0xfe30, 0xfe52, 0xfe54, 0xfe66, 0xfe68, 0xfe6b, 0xff01, 0xff60, 0xffe0, 0xffe6, 0x16fe0, 0x16fe4,\n 0x16ff0, 0x16ff1, 0x17000, 0x187f7, 0x18800, 0x18cd5, 0x18cff, 0x18d08, 0x1aff0, 0x1aff3,\n 0x1aff5, 0x1affb, 0x1affd, 0x1affe, 0x1b000, 0x1b122, 0x1b132, 0x1b132, 0x1b150, 0x1b152,\n 0x1b155, 0x1b155, 0x1b164, 0x1b167, 0x1b170, 0x1b2fb, 0x1d300, 0x1d356, 0x1d360, 0x1d376,\n 0x1f004, 0x1f004, 0x1f0cf, 0x1f0cf, 0x1f18e, 0x1f18e, 0x1f191, 0x1f19a, 0x1f200, 0x1f202,\n 0x1f210, 0x1f23b, 0x1f240, 0x1f248, 0x1f250, 0x1f251, 0x1f260, 0x1f265, 0x1f300, 0x1f320,\n 0x1f32d, 0x1f335, 0x1f337, 0x1f37c, 0x1f37e, 0x1f393, 0x1f3a0, 0x1f3ca, 0x1f3cf, 0x1f3d3,\n 0x1f3e0, 0x1f3f0, 0x1f3f4, 0x1f3f4, 0x1f3f8, 0x1f43e, 0x1f440, 0x1f440, 0x1f442, 0x1f4fc,\n 0x1f4ff, 0x1f53d, 0x1f54b, 0x1f54e, 0x1f550, 0x1f567, 0x1f57a, 0x1f57a, 0x1f595, 0x1f596,\n 0x1f5a4, 0x1f5a4, 0x1f5fb, 0x1f64f, 0x1f680, 0x1f6c5, 0x1f6cc, 0x1f6cc, 0x1f6d0, 0x1f6d2,\n 0x1f6d5, 0x1f6d7, 0x1f6dc, 0x1f6df, 0x1f6eb, 0x1f6ec, 0x1f6f4, 0x1f6fc, 0x1f7e0, 0x1f7eb,\n 0x1f7f0, 0x1f7f0, 0x1f90c, 0x1f93a, 0x1f93c, 0x1f945, 0x1f947, 0x1f9ff, 0x1fa70, 0x1fa7c,\n 0x1fa80, 0x1fa89, 0x1fa8f, 0x1fac6, 0x1face, 0x1fadc, 0x1fadf, 0x1fae9, 0x1faf0, 0x1faf8,\n 0x20000, 0x2fffd, 0x30000, 0x3fffd,\n];\n\n/** A character that shows: anything but a control, a format character or a mark, and the soft hyphen. */\nconst SHOWN = /[^\\p{Cc}\\p{Cf}\\p{Mn}\\p{Me}]|\\u00ad/u;\n\n/**\n * The start of an emoji sequence a terminal draws as one wide picture: an\n * emoji and the presentation selector, a modifier base and its modifier, or\n * two regional indicators, a flag.\n */\nconst EMOJI_SEQUENCE = /^(?:\\p{Emoji}\\ufe0f|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}|\\p{Regional_Indicator}{2})/u;\n\n// Made the first time a width is asked for: loading the segmentation rules\n// costs milliseconds that a tool which never measures a string - every one\n// that copies this module for its line tables - would pay on each start.\nlet graphemes: Intl.Segmenter | undefined;\n\n/** The columns a text takes in a terminal. */\nexport function displayWidth(text: string): number {\n // A named locale, so the host's default is never read; clusters are the\n // same in every locale, and they are what a segmenter gives unless told\n // otherwise.\n graphemes ??= new Intl.Segmenter('en');\n let width = 0;\n for (const { segment } of graphemes.segment(text)) width += clusterWidth(segment);\n return width;\n}\n\nfunction clusterWidth(cluster: string): number {\n const at = cluster.search(SHOWN);\n if (at < 0) return 0;\n const shown = cluster.slice(at);\n return isWide(shown.codePointAt(0) as number) || EMOJI_SEQUENCE.test(shown) ? 2 : 1;\n}\n\n/**\n * Whether a code point is in {@link WIDE}, by bisection over its runs. The\n * search is half-open, as `inRanges`'s is: `high` is one past the last run\n * still in question.\n */\nfunction isWide(point: number): boolean {\n let low = 0;\n let high = WIDE.length / 2;\n while (low < high) {\n const mid = (low + high) >> 1;\n if (point < (WIDE[2 * mid] as number)) high = mid;\n else if (point > (WIDE[2 * mid + 1] as number)) low = mid + 1;\n else return true;\n }\n return false;\n}\n"]}
package/dist/yaml.js CHANGED
@@ -21,8 +21,12 @@
21
21
  */
22
22
  import { readFrontMatter } from './vendor/spec-core/markdown/index.js';
23
23
  const NOTHING = { entries: [], problems: [] };
24
- /** A line that reads as `key:` at any indentation, and the key it names. */
25
- const KEY_SHAPE = /^[ \t]*([A-Za-z_][\w.-]*)[ \t]*:/;
24
+ /**
25
+ * A line that reads as `key:` at any indentation, and the key it names: a key
26
+ * as spec-core's reader takes one, of any script, so ` 狀態: 草案` names a
27
+ * status and ` 標題: B` a title. A full-width colon ends no key there.
28
+ */
29
+ const KEY_SHAPE = /^[ \t]*([\p{L}_][\p{L}\p{M}\p{N}_.-]*)[ \t]*:/u;
26
30
  /** Reads a scanned document's front matter. */
27
31
  export function readEntries(scanned) {
28
32
  const block = scanned.frontMatter;
package/dist/yaml.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"yaml.js","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What spec-graph reads out of a document's front matter.\n *\n * The reader is spec-core's, copied into `src/vendor/spec-core/markdown/`: the\n * subset of YAML that specifications use - scalars, quoted scalars, inline and\n * block sequences, `#` comments and, as spec-graph reads it, one level of nested\n * mapping flattened to `parent.child` - with the offset of every key and value,\n * because when a status is wrong the report has to point at the line that\n * declares it.\n *\n * Anything richer is recognised and not guessed at: a value continued on the\n * next line, a plain value holding `: `, a block scalar, an anchor. Such a value\n * is not read, and the reason is a parse problem at the value, so a key that\n * says nothing to the graph says why under `--verbose`. Each problem says\n * whether it left something out and which key, for the count a run prints\n * without `--verbose`.\n *\n * What stays here is the shape the rest of spec-graph reads: a key in lower\n * case, which is how a relation key, a status key and `fm.<key>` in a selector\n * have always been compared, and a value that is a string or a list of them.\n */\n\nimport { readFrontMatter, type FrontMatter as Read } from './vendor/spec-core/markdown/index.js';\nimport type { ScannedDocument } from './markdown.js';\n\nexport interface YamlEntry {\n /** Lower-cased key. Nested keys are flattened with a dot. */\n readonly key: string;\n readonly value: string | readonly string[];\n /** Offset of the key. */\n readonly start: number;\n /** Offset just past the value. */\n readonly end: number;\n /** Offset of the first character of the value, for precise diagnostics. */\n readonly valueStart: number;\n}\n\n/** Something in the front matter that was not read, and where. */\nexport interface FrontMatterProblem {\n readonly message: string;\n readonly start: number;\n readonly end: number;\n /**\n * Whether it left something out: a value, a line or the whole block. A key\n * written twice is a problem that leaves nothing out, since the last is read.\n */\n readonly unread: boolean;\n /**\n * The key, lower-cased, whose value or line was left out, when the line\n * names one; `null` for a line that names none and for the whole block.\n */\n readonly key: string | null;\n}\n\nexport interface FrontMatterReading {\n readonly entries: readonly YamlEntry[];\n readonly problems: readonly FrontMatterProblem[];\n}\n\nconst NOTHING: FrontMatterReading = { entries: [], problems: [] };\n\n/** A line that reads as `key:` at any indentation, and the key it names. */\nconst KEY_SHAPE = /^[ \\t]*([A-Za-z_][\\w.-]*)[ \\t]*:/;\n\n/** Reads a scanned document's front matter. */\nexport function readEntries(scanned: ScannedDocument): FrontMatterReading {\n const block = scanned.frontMatter;\n if (block === null) return neverClosed(scanned);\n const index = scanned.index;\n // The block and nothing after it: the reader splits what it is given into\n // lines, and the body is none of its business. It stops at the closing\n // delimiter all the same, so the mutant that hands it the whole text reads\n // the same entries, and is equivalent.\n const read = readFrontMatter(scanned.text.slice(0, block.bodyStart), { nested: true });\n // The scan found a closed block, and the reader closes one by the same rule,\n // so this never returns and its mutant is equivalent.\n if (read === null) return NOTHING;\n const { entries, problems } = entriesOf(read, 0);\n return {\n entries,\n problems: [\n ...read.problems.map((problem) => {\n // A key written twice is read, the last of it; any other line with a\n // problem is not, and the key it looks like it names is what went\n // missing - ` status: accepted`, indented under nothing, is a status.\n const unread = !read.entries.some((entry) => entry.line === problem.line);\n const text = index.lineText(problem.line + 1);\n return {\n message: `front matter: ${problem.message}`,\n start: index.lineStart(problem.line + 1),\n end: index.lineEnd(problem.line + 1),\n unread,\n // A match always has its one group, so `?.[1].` reads the same as\n // `?.[1]?.`: that mutant is equivalent.\n key: KEY_SHAPE.exec(text)?.[1]?.toLowerCase() ?? null,\n };\n }),\n ...problems,\n ].sort((a, b) => a.start - b.start),\n };\n}\n\n/**\n * Front matter that opens and never closes, which the scan reads as a rule\n * and Markdown after it, so nothing in it reaches the graph.\n *\n * The scan reports it, with its opening line, rather than leaving a document\n * that wrote front matter looking like one that wrote none. The usual cause is\n * a closer that only looks like one: `----` and `....` closed front matter\n * here before 0.9.0, and neither is one of YAML's document markers.\n */\nfunction neverClosed(scanned: ScannedDocument): FrontMatterReading {\n const open = scanned.unclosedFrontMatter;\n if (open === null) return NOTHING;\n const delimiter = open.kind === 'yaml' ? '---' : '+++';\n return {\n entries: [],\n problems: [\n {\n message: `front matter: opened here and never closed, so none of it is read - close it with \"${delimiter}\" on a line of its own`,\n start: open.start,\n end: open.end,\n unread: true,\n key: null,\n },\n ],\n };\n}\n\n/**\n * Parses front-matter text: what lies between the delimiters, as\n * `FrontMatter.raw` holds it.\n *\n * @param raw The text between the delimiters. It cannot hold a line that would\n * close them, as text a scan read between them never does.\n * @param baseOffset Offset of `raw` within the containing file, so the returned\n * spans address the file rather than the fragment.\n */\nexport function parseFrontMatter(raw: string, baseOffset = 0): YamlEntry[] {\n // The reader reads front matter at the top of a document, so the text goes\n // back between delimiters, and every offset back by the four characters the\n // opening one takes. The line break before the closing one is a blank line\n // when `raw` already ends in one, and a blank line is no key's.\n const read = readFrontMatter(`---\\n${raw}\\n---`, { nested: true });\n // Never null: the text opens with a delimiter and closes with one. The\n // mutants of that branch are equivalent.\n return read === null ? [] : entriesOf(read, baseOffset - 4).entries;\n}\n\n/** The entries a reading holds, and the values it could not read as problems. */\nfunction entriesOf(read: Read, shift: number): { entries: YamlEntry[]; problems: FrontMatterProblem[] } {\n const entries: YamlEntry[] = [];\n const problems: FrontMatterProblem[] = [];\n for (const entry of read.entries) {\n const { value } = entry;\n if (value.kind === 'unsupported') {\n // Only `readEntries` keeps these, and it shifts by 0, where adding and\n // subtracting agree: the mutants of the two sums below are equivalent.\n problems.push({\n message: `front matter: \"${entry.key}\" is not read: ${value.reason}`,\n start: entry.valueStart + shift,\n end: entry.valueEnd + shift,\n unread: true,\n key: entry.key.toLowerCase(),\n });\n continue;\n }\n entries.push({\n key: entry.key.toLowerCase(),\n value: value.kind === 'scalar' ? value.scalar.text : value.items.map((item) => item.text),\n start: entry.keyStart + shift,\n end: entry.valueEnd + shift,\n valueStart: entry.valueStart + shift,\n });\n }\n return { entries, problems };\n}\n\n/** Collapses parsed entries into the flat record stored on a document node. */\nexport function toRecord(entries: readonly YamlEntry[]): Record<string, string | readonly string[]> {\n const out: Record<string, string | readonly string[]> = {};\n for (const entry of entries) out[entry.key] = entry.value;\n return out;\n}\n\n/** Every value of a key as a flat list, whether it was a scalar or a sequence. */\nexport function valuesOf(entry: YamlEntry | undefined): string[] {\n if (!entry) return [];\n return typeof entry.value === 'string'\n ? entry.value.length > 0\n ? [entry.value]\n : []\n : [...entry.value];\n}\n"]}
1
+ {"version":3,"file":"yaml.js","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What spec-graph reads out of a document's front matter.\n *\n * The reader is spec-core's, copied into `src/vendor/spec-core/markdown/`: the\n * subset of YAML that specifications use - scalars, quoted scalars, inline and\n * block sequences, `#` comments and, as spec-graph reads it, one level of nested\n * mapping flattened to `parent.child` - with the offset of every key and value,\n * because when a status is wrong the report has to point at the line that\n * declares it.\n *\n * Anything richer is recognised and not guessed at: a value continued on the\n * next line, a plain value holding `: `, a block scalar, an anchor. Such a value\n * is not read, and the reason is a parse problem at the value, so a key that\n * says nothing to the graph says why under `--verbose`. Each problem says\n * whether it left something out and which key, for the count a run prints\n * without `--verbose`.\n *\n * What stays here is the shape the rest of spec-graph reads: a key in lower\n * case, which is how a relation key, a status key and `fm.<key>` in a selector\n * have always been compared, and a value that is a string or a list of them.\n */\n\nimport { readFrontMatter, type FrontMatter as Read } from './vendor/spec-core/markdown/index.js';\nimport type { ScannedDocument } from './markdown.js';\n\nexport interface YamlEntry {\n /** Lower-cased key. Nested keys are flattened with a dot. */\n readonly key: string;\n readonly value: string | readonly string[];\n /** Offset of the key. */\n readonly start: number;\n /** Offset just past the value. */\n readonly end: number;\n /** Offset of the first character of the value, for precise diagnostics. */\n readonly valueStart: number;\n}\n\n/** Something in the front matter that was not read, and where. */\nexport interface FrontMatterProblem {\n readonly message: string;\n readonly start: number;\n readonly end: number;\n /**\n * Whether it left something out: a value, a line or the whole block. A key\n * written twice is a problem that leaves nothing out, since the last is read.\n */\n readonly unread: boolean;\n /**\n * The key, lower-cased, whose value or line was left out, when the line\n * names one; `null` for a line that names none and for the whole block.\n */\n readonly key: string | null;\n}\n\nexport interface FrontMatterReading {\n readonly entries: readonly YamlEntry[];\n readonly problems: readonly FrontMatterProblem[];\n}\n\nconst NOTHING: FrontMatterReading = { entries: [], problems: [] };\n\n/**\n * A line that reads as `key:` at any indentation, and the key it names: a key\n * as spec-core's reader takes one, of any script, so ` 狀態: 草案` names a\n * status and ` 標題: B` a title. A full-width colon ends no key there.\n */\nconst KEY_SHAPE = /^[ \\t]*([\\p{L}_][\\p{L}\\p{M}\\p{N}_.-]*)[ \\t]*:/u;\n\n/** Reads a scanned document's front matter. */\nexport function readEntries(scanned: ScannedDocument): FrontMatterReading {\n const block = scanned.frontMatter;\n if (block === null) return neverClosed(scanned);\n const index = scanned.index;\n // The block and nothing after it: the reader splits what it is given into\n // lines, and the body is none of its business. It stops at the closing\n // delimiter all the same, so the mutant that hands it the whole text reads\n // the same entries, and is equivalent.\n const read = readFrontMatter(scanned.text.slice(0, block.bodyStart), { nested: true });\n // The scan found a closed block, and the reader closes one by the same rule,\n // so this never returns and its mutant is equivalent.\n if (read === null) return NOTHING;\n const { entries, problems } = entriesOf(read, 0);\n return {\n entries,\n problems: [\n ...read.problems.map((problem) => {\n // A key written twice is read, the last of it; any other line with a\n // problem is not, and the key it looks like it names is what went\n // missing - ` status: accepted`, indented under nothing, is a status.\n const unread = !read.entries.some((entry) => entry.line === problem.line);\n const text = index.lineText(problem.line + 1);\n return {\n message: `front matter: ${problem.message}`,\n start: index.lineStart(problem.line + 1),\n end: index.lineEnd(problem.line + 1),\n unread,\n // A match always has its one group, so `?.[1].` reads the same as\n // `?.[1]?.`: that mutant is equivalent.\n key: KEY_SHAPE.exec(text)?.[1]?.toLowerCase() ?? null,\n };\n }),\n ...problems,\n ].sort((a, b) => a.start - b.start),\n };\n}\n\n/**\n * Front matter that opens and never closes, which the scan reads as a rule\n * and Markdown after it, so nothing in it reaches the graph.\n *\n * The scan reports it, with its opening line, rather than leaving a document\n * that wrote front matter looking like one that wrote none. The usual cause is\n * a closer that only looks like one: `----` and `....` closed front matter\n * here before 0.9.0, and neither is one of YAML's document markers.\n */\nfunction neverClosed(scanned: ScannedDocument): FrontMatterReading {\n const open = scanned.unclosedFrontMatter;\n if (open === null) return NOTHING;\n const delimiter = open.kind === 'yaml' ? '---' : '+++';\n return {\n entries: [],\n problems: [\n {\n message: `front matter: opened here and never closed, so none of it is read - close it with \"${delimiter}\" on a line of its own`,\n start: open.start,\n end: open.end,\n unread: true,\n key: null,\n },\n ],\n };\n}\n\n/**\n * Parses front-matter text: what lies between the delimiters, as\n * `FrontMatter.raw` holds it.\n *\n * @param raw The text between the delimiters. It cannot hold a line that would\n * close them, as text a scan read between them never does.\n * @param baseOffset Offset of `raw` within the containing file, so the returned\n * spans address the file rather than the fragment.\n */\nexport function parseFrontMatter(raw: string, baseOffset = 0): YamlEntry[] {\n // The reader reads front matter at the top of a document, so the text goes\n // back between delimiters, and every offset back by the four characters the\n // opening one takes. The line break before the closing one is a blank line\n // when `raw` already ends in one, and a blank line is no key's.\n const read = readFrontMatter(`---\\n${raw}\\n---`, { nested: true });\n // Never null: the text opens with a delimiter and closes with one. The\n // mutants of that branch are equivalent.\n return read === null ? [] : entriesOf(read, baseOffset - 4).entries;\n}\n\n/** The entries a reading holds, and the values it could not read as problems. */\nfunction entriesOf(read: Read, shift: number): { entries: YamlEntry[]; problems: FrontMatterProblem[] } {\n const entries: YamlEntry[] = [];\n const problems: FrontMatterProblem[] = [];\n for (const entry of read.entries) {\n const { value } = entry;\n if (value.kind === 'unsupported') {\n // Only `readEntries` keeps these, and it shifts by 0, where adding and\n // subtracting agree: the mutants of the two sums below are equivalent.\n problems.push({\n message: `front matter: \"${entry.key}\" is not read: ${value.reason}`,\n start: entry.valueStart + shift,\n end: entry.valueEnd + shift,\n unread: true,\n key: entry.key.toLowerCase(),\n });\n continue;\n }\n entries.push({\n key: entry.key.toLowerCase(),\n value: value.kind === 'scalar' ? value.scalar.text : value.items.map((item) => item.text),\n start: entry.keyStart + shift,\n end: entry.valueEnd + shift,\n valueStart: entry.valueStart + shift,\n });\n }\n return { entries, problems };\n}\n\n/** Collapses parsed entries into the flat record stored on a document node. */\nexport function toRecord(entries: readonly YamlEntry[]): Record<string, string | readonly string[]> {\n const out: Record<string, string | readonly string[]> = {};\n for (const entry of entries) out[entry.key] = entry.value;\n return out;\n}\n\n/** Every value of a key as a flat list, whether it was a scalar or a sequence. */\nexport function valuesOf(entry: YamlEntry | undefined): string[] {\n if (!entry) return [];\n return typeof entry.value === 'string'\n ? entry.value.length > 0\n ? [entry.value]\n : []\n : [...entry.value];\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@descent-vtt/spec-graph",
3
- "version": "0.9.9",
3
+ "version": "0.10.0",
4
4
  "description": "Turn Markdown specs into a verifiable relational graph. Catches ghost handovers, stale premises and broken references in CI.",
5
5
  "keywords": [
6
6
  "adr",