@descent-vtt/spec-brief 0.1.0 → 0.2.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 (128) hide show
  1. package/CHANGELOG.md +264 -0
  2. package/README.md +90 -20
  3. package/dist/archive.d.ts +52 -2
  4. package/dist/archive.js +205 -37
  5. package/dist/archive.js.map +1 -1
  6. package/dist/brief.d.ts +2 -0
  7. package/dist/brief.js +5 -1
  8. package/dist/brief.js.map +1 -1
  9. package/dist/cli.d.ts +1 -1
  10. package/dist/cli.js +48 -14
  11. package/dist/cli.js.map +1 -1
  12. package/dist/collisions.d.ts +43 -12
  13. package/dist/collisions.js +90 -58
  14. package/dist/collisions.js.map +1 -1
  15. package/dist/config.d.ts +11 -0
  16. package/dist/config.js +58 -10
  17. package/dist/config.js.map +1 -1
  18. package/dist/corpus.d.ts +21 -1
  19. package/dist/corpus.js +51 -2
  20. package/dist/corpus.js.map +1 -1
  21. package/dist/engine.d.ts +33 -3
  22. package/dist/engine.js +112 -9
  23. package/dist/engine.js.map +1 -1
  24. package/dist/frontmatter.d.ts +18 -61
  25. package/dist/frontmatter.js +31 -300
  26. package/dist/frontmatter.js.map +1 -1
  27. package/dist/glob.d.ts +77 -54
  28. package/dist/glob.js +104 -433
  29. package/dist/glob.js.map +1 -1
  30. package/dist/index.d.ts +10 -8
  31. package/dist/index.js +8 -6
  32. package/dist/index.js.map +1 -1
  33. package/dist/links.d.ts +1 -1
  34. package/dist/links.js +3 -4
  35. package/dist/links.js.map +1 -1
  36. package/dist/lint.d.ts +33 -2
  37. package/dist/lint.js +9 -2
  38. package/dist/lint.js.map +1 -1
  39. package/dist/markdown.d.ts +26 -23
  40. package/dist/markdown.js +60 -237
  41. package/dist/markdown.js.map +1 -1
  42. package/dist/plugins.d.ts +14 -0
  43. package/dist/plugins.js +142 -6
  44. package/dist/plugins.js.map +1 -1
  45. package/dist/report.d.ts +40 -3
  46. package/dist/report.js +227 -11
  47. package/dist/report.js.map +1 -1
  48. package/dist/rules.d.ts +22 -4
  49. package/dist/rules.js +175 -45
  50. package/dist/rules.js.map +1 -1
  51. package/dist/scaffold.d.ts +1 -1
  52. package/dist/scaffold.js +10 -9
  53. package/dist/scaffold.js.map +1 -1
  54. package/dist/schedule.d.ts +133 -0
  55. package/dist/schedule.js +265 -0
  56. package/dist/schedule.js.map +1 -0
  57. package/dist/scope.d.ts +52 -0
  58. package/dist/scope.js +56 -0
  59. package/dist/scope.js.map +1 -0
  60. package/dist/text.d.ts +13 -0
  61. package/dist/text.js +23 -0
  62. package/dist/text.js.map +1 -1
  63. package/dist/trigger.d.ts +17 -0
  64. package/dist/trigger.js +49 -0
  65. package/dist/trigger.js.map +1 -0
  66. package/dist/types.d.ts +14 -5
  67. package/dist/types.js.map +1 -1
  68. package/dist/vendor/spec-core/markdown/frontmatter.d.ts +103 -0
  69. package/dist/vendor/spec-core/markdown/frontmatter.js +459 -0
  70. package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -0
  71. package/dist/vendor/spec-core/markdown/headings.d.ts +45 -0
  72. package/dist/vendor/spec-core/markdown/headings.js +199 -0
  73. package/dist/vendor/spec-core/markdown/headings.js.map +1 -0
  74. package/dist/vendor/spec-core/markdown/index.d.ts +5 -0
  75. package/dist/vendor/spec-core/markdown/index.js +4 -0
  76. package/dist/vendor/spec-core/markdown/index.js.map +1 -0
  77. package/dist/vendor/spec-core/markdown/layout.d.ts +39 -0
  78. package/dist/vendor/spec-core/markdown/layout.js +28 -0
  79. package/dist/vendor/spec-core/markdown/layout.js.map +1 -0
  80. package/dist/vendor/spec-core/markdown/links.d.ts +22 -0
  81. package/dist/vendor/spec-core/markdown/links.js +364 -0
  82. package/dist/vendor/spec-core/markdown/links.js.map +1 -0
  83. package/dist/vendor/spec-core/markdown/lists.d.ts +22 -0
  84. package/dist/vendor/spec-core/markdown/lists.js +127 -0
  85. package/dist/vendor/spec-core/markdown/lists.js.map +1 -0
  86. package/dist/vendor/spec-core/markdown/scan.d.ts +36 -0
  87. package/dist/vendor/spec-core/markdown/scan.js +439 -0
  88. package/dist/vendor/spec-core/markdown/scan.js.map +1 -0
  89. package/dist/vendor/spec-core/markdown/syntax.d.ts +75 -0
  90. package/dist/vendor/spec-core/markdown/syntax.js +181 -0
  91. package/dist/vendor/spec-core/markdown/syntax.js.map +1 -0
  92. package/dist/vendor/spec-core/markdown/tables.d.ts +18 -0
  93. package/dist/vendor/spec-core/markdown/tables.js +86 -0
  94. package/dist/vendor/spec-core/markdown/tables.js.map +1 -0
  95. package/dist/vendor/spec-core/markdown/types.d.ts +287 -0
  96. package/dist/vendor/spec-core/markdown/types.js +9 -0
  97. package/dist/vendor/spec-core/markdown/types.js.map +1 -0
  98. package/dist/vendor/spec-core/path/index.d.ts +1 -0
  99. package/dist/vendor/spec-core/path/index.js +2 -0
  100. package/dist/vendor/spec-core/path/index.js.map +1 -0
  101. package/dist/vendor/spec-core/path/posix.d.ts +83 -0
  102. package/dist/vendor/spec-core/path/posix.js +150 -0
  103. package/dist/vendor/spec-core/path/posix.js.map +1 -0
  104. package/dist/vendor/spec-core/pattern/automaton.d.ts +129 -0
  105. package/dist/vendor/spec-core/pattern/automaton.js +340 -0
  106. package/dist/vendor/spec-core/pattern/automaton.js.map +1 -0
  107. package/dist/vendor/spec-core/pattern/charset.d.ts +58 -0
  108. package/dist/vendor/spec-core/pattern/charset.js +116 -0
  109. package/dist/vendor/spec-core/pattern/charset.js.map +1 -0
  110. package/dist/vendor/spec-core/pattern/glob.d.ts +121 -0
  111. package/dist/vendor/spec-core/pattern/glob.js +481 -0
  112. package/dist/vendor/spec-core/pattern/glob.js.map +1 -0
  113. package/dist/vendor/spec-core/pattern/index.d.ts +6 -0
  114. package/dist/vendor/spec-core/pattern/index.js +4 -0
  115. package/dist/vendor/spec-core/pattern/index.js.map +1 -0
  116. package/dist/vendor/spec-core/pattern/regex.d.ts +67 -0
  117. package/dist/vendor/spec-core/pattern/regex.js +813 -0
  118. package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
  119. package/dist/vendor/spec-core/text/index.d.ts +2 -0
  120. package/dist/vendor/spec-core/text/index.js +2 -0
  121. package/dist/vendor/spec-core/text/index.js.map +1 -0
  122. package/dist/vendor/spec-core/text/lines.d.ts +72 -0
  123. package/dist/vendor/spec-core/text/lines.js +156 -0
  124. package/dist/vendor/spec-core/text/lines.js.map +1 -0
  125. package/package.json +3 -2
  126. package/schema.json +17 -0
  127. package/src/vendor/spec-core/LICENSE +21 -0
  128. package/src/vendor/spec-core/README.md +8 -0
@@ -1,68 +1,25 @@
1
1
  /**
2
- * A front-matter reader and editor for the flat subset of YAML briefs use.
2
+ * A brief's front matter: spec-core's reader and editor, copied into
3
+ * `src/vendor/spec-core/`, over a brief's lines.
3
4
  *
4
- * Supported: `key: value` at the top level; plain, single-quoted and
5
- * double-quoted scalars; inline `[a, b]` sequences; block `- item` sequences;
6
- * `#` comments. Plain scalars follow the YAML 1.2 core schema, so `yes` is a
7
- * word and `035` keeps its leading zero for whoever reads it as text.
8
- *
9
- * Anything richer - nested mappings, block scalars, anchors, tags, a value
10
- * continued onto the next line - is recognised and reported as unsupported
11
- * rather than guessed at. A YAML library would parse more, and would be the
12
- * largest dependency of a package that has none; it would also not give back
13
- * the line of every value, and an edit that must leave every other line of a
14
- * file untouched needs exactly that.
5
+ * The flat subset of YAML briefs use: `key: value` lines, plain and quoted
6
+ * scalars, inline and block lists, comments. Anything richer is reported as
7
+ * unsupported rather than guessed at, TOML between `+++` lines included, and
8
+ * every value keeps its line, so an edit leaves every other line of the file
9
+ * as it was (ADR-0001). Offsets in what it reads count in the lines joined by
10
+ * `\n`, which for a brief are its `lines`, not its `text`.
15
11
  */
16
- export interface YamlScalar {
17
- readonly text: string;
18
- readonly quoted: boolean;
19
- }
20
- export type YamlValue = {
21
- readonly kind: 'scalar';
22
- readonly scalar: YamlScalar;
23
- } | {
24
- readonly kind: 'list';
25
- readonly items: readonly YamlScalar[];
26
- } | {
27
- readonly kind: 'unsupported';
28
- readonly reason: string;
29
- };
30
- export interface FrontMatterEntry {
31
- /** The key as written. */
32
- readonly key: string;
33
- /** The key compared: lower case, without `-` or `_`, so `depends-on` is `dependsOn`. */
34
- readonly name: string;
35
- /** 0-based line of the key. */
36
- readonly line: number;
37
- /** 0-based line after the entry's last line. */
38
- readonly end: number;
39
- readonly value: YamlValue;
40
- }
41
- export interface FrontMatterProblem {
42
- readonly line: number;
43
- readonly message: string;
44
- }
45
- export interface FrontMatter {
46
- /** 0-based line of the closing delimiter, or -1 when the block is never closed. */
47
- readonly close: number;
48
- readonly entries: readonly FrontMatterEntry[];
49
- readonly problems: readonly FrontMatterProblem[];
50
- }
51
- export declare function keyName(key: string): string;
12
+ import { type FrontMatter } from './vendor/spec-core/markdown/index.js';
13
+ export { findEntry, isNull, keyName, parseInline, removeEntry, renderScalar, setEntry, type FrontMatter, type FrontMatterEntry, type FrontMatterProblem, type YamlScalar, type YamlValue, } from './vendor/spec-core/markdown/index.js';
52
14
  /** Reads the front matter at the top of `lines`, or `null` when there is none. */
53
15
  export declare function readFrontMatter(lines: readonly string[]): FrontMatter | null;
54
- /** Parses a value written on the key's own line. `text` is trimmed and non-empty. */
55
- export declare function parseInline(text: string): YamlValue;
56
- /** Null in the YAML 1.2 core schema: empty, `~` or `null` in any of its three spellings. */
57
- export declare function isNull(scalar: YamlScalar): boolean;
58
- /** Renders a string as a scalar that reads back as the same string. */
59
- export declare function renderScalar(value: string): string;
60
- export declare function findEntry(frontMatter: FrontMatter | null, key: string): FrontMatterEntry | undefined;
61
16
  /**
62
- * Sets one key, leaving every other line as it was. An existing entry keeps the
63
- * spelling of its key; a new one goes last. A file with no front matter gains
64
- * a block.
17
+ * Sets one key as `setEntry` does, and keeps a comment that followed the old
18
+ * value on its line: `wave: 2 # after the review` becomes `wave: 3 # after
19
+ * the review`. spec-core's editor writes the key and the value alone, and a
20
+ * comment beside a value is often the only record of why it was chosen. A
21
+ * value over several lines is rewritten as `setEntry` rewrites it.
65
22
  */
66
- export declare function setEntry(lines: readonly string[], frontMatter: FrontMatter | null, key: string, rendered: string): string[];
67
- /** Removes one key and its value lines; a key that is absent changes nothing. */
68
- export declare function removeEntry(lines: readonly string[], frontMatter: FrontMatter | null, key: string): string[];
23
+ export declare function setEntryKeepingComment(lines: readonly string[], frontMatter: FrontMatter | null, key: string, rendered: string): string[];
24
+ /** Front matter an edit can be written into: YAML, and closed. */
25
+ export declare function editable(frontMatter: FrontMatter): boolean;
@@ -1,311 +1,42 @@
1
1
  /**
2
- * A front-matter reader and editor for the flat subset of YAML briefs use.
2
+ * A brief's front matter: spec-core's reader and editor, copied into
3
+ * `src/vendor/spec-core/`, over a brief's lines.
3
4
  *
4
- * Supported: `key: value` at the top level; plain, single-quoted and
5
- * double-quoted scalars; inline `[a, b]` sequences; block `- item` sequences;
6
- * `#` comments. Plain scalars follow the YAML 1.2 core schema, so `yes` is a
7
- * word and `035` keeps its leading zero for whoever reads it as text.
8
- *
9
- * Anything richer - nested mappings, block scalars, anchors, tags, a value
10
- * continued onto the next line - is recognised and reported as unsupported
11
- * rather than guessed at. A YAML library would parse more, and would be the
12
- * largest dependency of a package that has none; it would also not give back
13
- * the line of every value, and an edit that must leave every other line of a
14
- * file untouched needs exactly that.
5
+ * The flat subset of YAML briefs use: `key: value` lines, plain and quoted
6
+ * scalars, inline and block lists, comments. Anything richer is reported as
7
+ * unsupported rather than guessed at, TOML between `+++` lines included, and
8
+ * every value keeps its line, so an edit leaves every other line of the file
9
+ * as it was (ADR-0001). Offsets in what it reads count in the lines joined by
10
+ * `\n`, which for a brief are its `lines`, not its `text`.
15
11
  */
16
- const OPEN = /^---[ \t]*$/;
17
- const CLOSE = /^(?:---|\.\.\.)[ \t]*$/;
18
- const KEY = /^([A-Za-z_][\w.-]*)[ \t]*:(?:[ \t]+(.*))?$/;
19
- const SEQUENCE_ITEM = /^([ \t]*)-(?:[ \t]+(.*))?$/;
20
- const BLANK_OR_COMMENT = /^[ \t]*(?:#.*)?$/;
21
- export function keyName(key) {
22
- return key.toLowerCase().replace(/[-_]/g, '');
23
- }
12
+ import { findEntry, readFrontMatter as readText, setEntry } from './vendor/spec-core/markdown/index.js';
13
+ import { textOfLines } from './text.js';
14
+ export { findEntry, isNull, keyName, parseInline, removeEntry, renderScalar, setEntry, } from './vendor/spec-core/markdown/index.js';
24
15
  /** Reads the front matter at the top of `lines`, or `null` when there is none. */
25
16
  export function readFrontMatter(lines) {
26
- if (lines.length === 0 || !OPEN.test(lines[0]))
27
- return null;
28
- let close = -1;
29
- for (let i = 1; i < lines.length; i += 1) {
30
- if (CLOSE.test(lines[i])) {
31
- close = i;
32
- break;
33
- }
34
- }
35
- if (close < 0) {
36
- return {
37
- close: -1,
38
- entries: [],
39
- problems: [{ line: 0, message: 'the front matter opened on line 1 is never closed' }],
40
- };
41
- }
42
- const entries = [];
43
- const problems = [];
44
- const seen = new Map();
45
- let i = 1;
46
- while (i < close) {
47
- const line = lines[i];
48
- if (BLANK_OR_COMMENT.test(line)) {
49
- i += 1;
50
- continue;
51
- }
52
- const match = KEY.exec(line);
53
- if (!match) {
54
- problems.push({
55
- line: i,
56
- message: /^\s/.test(line) ? 'an indented line belongs to no key' : 'not a "key: value" line',
57
- });
58
- i += 1;
59
- continue;
60
- }
61
- const key = match[1];
62
- const inline = stripLeadingComment((match[2] ?? '').trim());
63
- let end = i + 1;
64
- while (end < close && belongsToBlock(lines[end]))
65
- end += 1;
66
- while (end > i + 1 && BLANK_OR_COMMENT.test(lines[end - 1]))
67
- end -= 1;
68
- const block = lines.slice(i + 1, end);
69
- let value;
70
- if (inline.length > 0) {
71
- value = block.some((l) => !BLANK_OR_COMMENT.test(l))
72
- ? unsupported('the value continues on the next line; keep it on one line, or quote it')
73
- : parseInline(inline);
74
- }
75
- else {
76
- value = parseBlock(block);
77
- }
78
- const name = keyName(key);
79
- const previous = seen.get(name);
80
- if (previous !== undefined) {
81
- problems.push({ line: i, message: `"${key}" is declared twice (first on line ${previous + 1})` });
82
- }
83
- else {
84
- seen.set(name, i);
85
- }
86
- entries.push({ key, name, line: i, end, value });
87
- i = end;
88
- }
89
- return { close, entries, problems };
90
- }
91
- /** A line under a key is part of its value when it is indented or starts a sequence item. */
92
- function belongsToBlock(line) {
93
- return /^[ \t]/.test(line) || /^-(?:[ \t]|$)/.test(line) || line.trim() === '';
94
- }
95
- function stripLeadingComment(text) {
96
- return text.startsWith('#') ? '' : text;
97
- }
98
- function unsupported(reason) {
99
- return { kind: 'unsupported', reason };
100
- }
101
- function parseBlock(block) {
102
- const content = block.filter((l) => !BLANK_OR_COMMENT.test(l));
103
- if (content.length === 0)
104
- return { kind: 'scalar', scalar: { text: '', quoted: false } };
105
- const first = SEQUENCE_ITEM.exec(content[0]);
106
- if (!first) {
107
- return KEY.test(content[0].trim())
108
- ? unsupported('nested mappings are not supported; flatten the key')
109
- : unsupported('the value continues on the next line; keep it on one line, or quote it');
110
- }
111
- const indent = first[1].length;
112
- const items = [];
113
- for (const line of content) {
114
- const item = SEQUENCE_ITEM.exec(line);
115
- if (!item || item[1].length !== indent) {
116
- return unsupported('a list item is continued or nested; keep each item on one line');
117
- }
118
- const text = stripLeadingComment((item[2] ?? '').trim());
119
- if (text.length === 0)
120
- return unsupported('a list item is empty');
121
- const parsed = parseInline(text);
122
- if (parsed.kind !== 'scalar') {
123
- return parsed.kind === 'list' ? unsupported('nested lists are not supported') : parsed;
124
- }
125
- items.push(parsed.scalar);
126
- }
127
- return { kind: 'list', items };
128
- }
129
- /** Parses a value written on the key's own line. `text` is trimmed and non-empty. */
130
- export function parseInline(text) {
131
- const head = text.charAt(0);
132
- if (head === '"' || head === "'") {
133
- const quoted = head === '"' ? readDoubleQuoted(text) : readSingleQuoted(text);
134
- if (typeof quoted === 'string')
135
- return unsupported(quoted);
136
- return trailingIsComment(text.slice(quoted.next))
137
- ? { kind: 'scalar', scalar: { text: quoted.text, quoted: true } }
138
- : unsupported('text follows a closing quote');
139
- }
140
- if (head === '[')
141
- return parseFlowSequence(text);
142
- if (head === '{')
143
- return unsupported('inline mappings are not supported');
144
- if (head === '|' || head === '>')
145
- return unsupported('block scalars are not supported; keep the value on one line');
146
- if (head === '&' || head === '*' || head === '!')
147
- return unsupported('anchors, aliases and tags are not supported');
148
- if (head === '@' || head === '`')
149
- return unsupported(`a plain value cannot start with "${head}"; quote it`);
150
- const plain = stripTrailingComment(text);
151
- if (/:(?:\s|$)/.test(plain))
152
- return unsupported('a plain value cannot contain ": "; quote it');
153
- if (/^-(?:\s|$)/.test(plain))
154
- return unsupported('a list must start on the line after its key');
155
- return { kind: 'scalar', scalar: { text: plain, quoted: false } };
156
- }
157
- function stripTrailingComment(text) {
158
- const hash = text.search(/\s#/);
159
- return (hash < 0 ? text : text.slice(0, hash)).trim();
160
- }
161
- function trailingIsComment(rest) {
162
- return /^\s*(?:#.*)?$/.test(rest) && (rest.trim() === '' || /^\s/.test(rest));
163
- }
164
- const ESCAPES = {
165
- '"': '"',
166
- '\\': '\\',
167
- '/': '/',
168
- '0': '\0',
169
- b: '\b',
170
- f: '\f',
171
- n: '\n',
172
- r: '\r',
173
- t: '\t',
174
- };
175
- const HEX_ESCAPE_LENGTH = { x: 2, u: 4, U: 8 };
176
- /** Reads a double-quoted scalar starting at index 0, or returns why it cannot. */
177
- function readDoubleQuoted(text) {
178
- let out = '';
179
- for (let i = 1; i < text.length; i += 1) {
180
- const ch = text.charAt(i);
181
- if (ch === '"')
182
- return { text: out, next: i + 1 };
183
- if (ch !== '\\') {
184
- out += ch;
185
- continue;
186
- }
187
- const code = text.charAt(i + 1);
188
- const simple = ESCAPES[code];
189
- if (simple !== undefined) {
190
- out += simple;
191
- i += 1;
192
- continue;
193
- }
194
- const width = HEX_ESCAPE_LENGTH[code];
195
- const hex = width === undefined ? '' : text.slice(i + 2, i + 2 + width);
196
- if (width === undefined || hex.length !== width || !/^[0-9A-Fa-f]+$/.test(hex)) {
197
- return `"\\${code}" is not an escape this reader knows`;
198
- }
199
- const point = Number.parseInt(hex, 16);
200
- if (point > 0x10ffff)
201
- return `"\\${code}${hex}" is not a character`;
202
- out += String.fromCodePoint(point);
203
- i += 1 + width;
204
- }
205
- return 'a double-quoted value is never closed';
206
- }
207
- function readSingleQuoted(text) {
208
- let out = '';
209
- for (let i = 1; i < text.length; i += 1) {
210
- const ch = text.charAt(i);
211
- if (ch !== "'") {
212
- out += ch;
213
- continue;
214
- }
215
- if (text.charAt(i + 1) === "'") {
216
- out += "'";
217
- i += 1;
218
- continue;
219
- }
220
- return { text: out, next: i + 1 };
221
- }
222
- return 'a single-quoted value is never closed';
223
- }
224
- function parseFlowSequence(text) {
225
- const items = [];
226
- let i = 1;
227
- for (;;) {
228
- while (i < text.length && /\s/.test(text.charAt(i)))
229
- i += 1;
230
- if (i >= text.length)
231
- return unsupported('an inline list is never closed; keep it on one line');
232
- const ch = text.charAt(i);
233
- if (ch === ']') {
234
- return trailingIsComment(text.slice(i + 1))
235
- ? { kind: 'list', items }
236
- : unsupported('text follows the end of an inline list');
237
- }
238
- if (ch === '[' || ch === '{')
239
- return unsupported('nested lists and mappings are not supported');
240
- if (ch === ',')
241
- return unsupported('an inline list has an empty item');
242
- let item;
243
- if (ch === '"' || ch === "'") {
244
- const rest = text.slice(i);
245
- const quoted = ch === '"' ? readDoubleQuoted(rest) : readSingleQuoted(rest);
246
- if (typeof quoted === 'string')
247
- return unsupported(quoted);
248
- item = { text: quoted.text, quoted: true };
249
- i += quoted.next;
250
- }
251
- else {
252
- let j = i;
253
- while (j < text.length && !',]'.includes(text.charAt(j)))
254
- j += 1;
255
- const plain = text.slice(i, j).trim();
256
- if (/[[{]/.test(plain) || /:(?:\s|$)/.test(plain) || plain.includes(' #')) {
257
- return unsupported(`"${plain}" needs quoting inside an inline list`);
258
- }
259
- item = { text: plain, quoted: false };
260
- i = j;
261
- }
262
- items.push(item);
263
- while (i < text.length && /\s/.test(text.charAt(i)))
264
- i += 1;
265
- if (i >= text.length)
266
- return unsupported('an inline list is never closed; keep it on one line');
267
- // After a comma the next pass reads an item or, legally in YAML, the bracket.
268
- if (text.charAt(i) === ',')
269
- i += 1;
270
- else if (text.charAt(i) !== ']')
271
- return unsupported('inline list items must be separated by commas');
272
- }
273
- }
274
- /** Null in the YAML 1.2 core schema: empty, `~` or `null` in any of its three spellings. */
275
- export function isNull(scalar) {
276
- return !scalar.quoted && ['', '~', 'null', 'Null', 'NULL'].includes(scalar.text);
277
- }
278
- /** Renders a string as a scalar that reads back as the same string. */
279
- export function renderScalar(value) {
280
- const reserved = /^(?:true|false|null|yes|no|on|off|~)$/i.test(value);
281
- const plain = /^[A-Za-z][A-Za-z0-9 ._/+-]*$/.test(value) && !value.endsWith(' ');
282
- return plain && !reserved ? value : JSON.stringify(value);
283
- }
284
- export function findEntry(frontMatter, key) {
285
- const name = keyName(key);
286
- return frontMatter?.entries.find((entry) => entry.name === name);
17
+ return readText(textOfLines(lines));
287
18
  }
288
19
  /**
289
- * Sets one key, leaving every other line as it was. An existing entry keeps the
290
- * spelling of its key; a new one goes last. A file with no front matter gains
291
- * a block.
20
+ * Sets one key as `setEntry` does, and keeps a comment that followed the old
21
+ * value on its line: `wave: 2 # after the review` becomes `wave: 3 # after
22
+ * the review`. spec-core's editor writes the key and the value alone, and a
23
+ * comment beside a value is often the only record of why it was chosen. A
24
+ * value over several lines is rewritten as `setEntry` rewrites it.
292
25
  */
293
- export function setEntry(lines, frontMatter, key, rendered) {
294
- if (frontMatter === null)
295
- return ['---', `${key}: ${rendered}`, '---', ...lines];
296
- if (frontMatter.close < 0)
297
- throw new Error('cannot edit front matter that is never closed');
298
- const entry = findEntry(frontMatter, key);
299
- if (entry === undefined) {
300
- return [...lines.slice(0, frontMatter.close), `${key}: ${rendered}`, ...lines.slice(frontMatter.close)];
301
- }
302
- return [...lines.slice(0, entry.line), `${entry.key}: ${rendered}`, ...lines.slice(entry.end)];
303
- }
304
- /** Removes one key and its value lines; a key that is absent changes nothing. */
305
- export function removeEntry(lines, frontMatter, key) {
26
+ export function setEntryKeepingComment(lines, frontMatter, key, rendered) {
27
+ const edited = setEntry(lines, frontMatter, key, rendered);
306
28
  const entry = findEntry(frontMatter, key);
307
- if (entry === undefined)
308
- return [...lines];
309
- return [...lines.slice(0, entry.line), ...lines.slice(entry.end)];
29
+ if (entry === undefined || entry.end !== entry.line + 1)
30
+ return edited;
31
+ // Offsets count in the lines joined by one character each.
32
+ const lineStart = lines.slice(0, entry.line).reduce((sum, line) => sum + line.length + 1, 0);
33
+ const rest = lines[entry.line].slice(entry.valueEnd - lineStart);
34
+ if (!/^[ \t]+#/.test(rest))
35
+ return edited;
36
+ return edited.map((line, i) => (i === entry.line ? `${line}${rest}` : line));
37
+ }
38
+ /** Front matter an edit can be written into: YAML, and closed. */
39
+ export function editable(frontMatter) {
40
+ return frontMatter.kind === 'yaml' && frontMatter.close >= 0;
310
41
  }
311
42
  //# sourceMappingURL=frontmatter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A front-matter reader and editor for the flat subset of YAML briefs use.\n *\n * Supported: `key: value` at the top level; plain, single-quoted and\n * double-quoted scalars; inline `[a, b]` sequences; block `- item` sequences;\n * `#` comments. Plain scalars follow the YAML 1.2 core schema, so `yes` is a\n * word and `035` keeps its leading zero for whoever reads it as text.\n *\n * Anything richer - nested mappings, block scalars, anchors, tags, a value\n * continued onto the next line - is recognised and reported as unsupported\n * rather than guessed at. A YAML library would parse more, and would be the\n * largest dependency of a package that has none; it would also not give back\n * the line of every value, and an edit that must leave every other line of a\n * file untouched needs exactly that.\n */\n\nexport interface YamlScalar {\n readonly text: string;\n readonly quoted: boolean;\n}\n\nexport type YamlValue =\n | { readonly kind: 'scalar'; readonly scalar: YamlScalar }\n | { readonly kind: 'list'; readonly items: readonly YamlScalar[] }\n | { readonly kind: 'unsupported'; readonly reason: string };\n\nexport interface FrontMatterEntry {\n /** The key as written. */\n readonly key: string;\n /** The key compared: lower case, without `-` or `_`, so `depends-on` is `dependsOn`. */\n readonly name: string;\n /** 0-based line of the key. */\n readonly line: number;\n /** 0-based line after the entry's last line. */\n readonly end: number;\n readonly value: YamlValue;\n}\n\nexport interface FrontMatterProblem {\n readonly line: number;\n readonly message: string;\n}\n\nexport interface FrontMatter {\n /** 0-based line of the closing delimiter, or -1 when the block is never closed. */\n readonly close: number;\n readonly entries: readonly FrontMatterEntry[];\n readonly problems: readonly FrontMatterProblem[];\n}\n\nconst OPEN = /^---[ \\t]*$/;\nconst CLOSE = /^(?:---|\\.\\.\\.)[ \\t]*$/;\nconst KEY = /^([A-Za-z_][\\w.-]*)[ \\t]*:(?:[ \\t]+(.*))?$/;\nconst SEQUENCE_ITEM = /^([ \\t]*)-(?:[ \\t]+(.*))?$/;\nconst BLANK_OR_COMMENT = /^[ \\t]*(?:#.*)?$/;\n\nexport function keyName(key: string): string {\n return key.toLowerCase().replace(/[-_]/g, '');\n}\n\n/** Reads the front matter at the top of `lines`, or `null` when there is none. */\nexport function readFrontMatter(lines: readonly string[]): FrontMatter | null {\n if (lines.length === 0 || !OPEN.test(lines[0] as string)) return null;\n let close = -1;\n for (let i = 1; i < lines.length; i += 1) {\n if (CLOSE.test(lines[i] as string)) {\n close = i;\n break;\n }\n }\n if (close < 0) {\n return {\n close: -1,\n entries: [],\n problems: [{ line: 0, message: 'the front matter opened on line 1 is never closed' }],\n };\n }\n\n const entries: FrontMatterEntry[] = [];\n const problems: FrontMatterProblem[] = [];\n const seen = new Map<string, number>();\n let i = 1;\n while (i < close) {\n const line = lines[i] as string;\n if (BLANK_OR_COMMENT.test(line)) {\n i += 1;\n continue;\n }\n const match = KEY.exec(line);\n if (!match) {\n problems.push({\n line: i,\n message: /^\\s/.test(line) ? 'an indented line belongs to no key' : 'not a \"key: value\" line',\n });\n i += 1;\n continue;\n }\n const key = match[1] as string;\n const inline = stripLeadingComment((match[2] ?? '').trim());\n let end = i + 1;\n while (end < close && belongsToBlock(lines[end] as string)) end += 1;\n while (end > i + 1 && BLANK_OR_COMMENT.test(lines[end - 1] as string)) end -= 1;\n const block = lines.slice(i + 1, end);\n\n let value: YamlValue;\n if (inline.length > 0) {\n value = block.some((l) => !BLANK_OR_COMMENT.test(l))\n ? unsupported('the value continues on the next line; keep it on one line, or quote it')\n : parseInline(inline);\n } else {\n value = parseBlock(block);\n }\n\n const name = keyName(key);\n const previous = seen.get(name);\n if (previous !== undefined) {\n problems.push({ line: i, message: `\"${key}\" is declared twice (first on line ${previous + 1})` });\n } else {\n seen.set(name, i);\n }\n entries.push({ key, name, line: i, end, value });\n i = end;\n }\n return { close, entries, problems };\n}\n\n/** A line under a key is part of its value when it is indented or starts a sequence item. */\nfunction belongsToBlock(line: string): boolean {\n return /^[ \\t]/.test(line) || /^-(?:[ \\t]|$)/.test(line) || line.trim() === '';\n}\n\nfunction stripLeadingComment(text: string): string {\n return text.startsWith('#') ? '' : text;\n}\n\nfunction unsupported(reason: string): YamlValue {\n return { kind: 'unsupported', reason };\n}\n\nfunction parseBlock(block: readonly string[]): YamlValue {\n const content = block.filter((l) => !BLANK_OR_COMMENT.test(l));\n if (content.length === 0) return { kind: 'scalar', scalar: { text: '', quoted: false } };\n const first = SEQUENCE_ITEM.exec(content[0] as string);\n if (!first) {\n return KEY.test((content[0] as string).trim())\n ? unsupported('nested mappings are not supported; flatten the key')\n : unsupported('the value continues on the next line; keep it on one line, or quote it');\n }\n const indent = (first[1] as string).length;\n const items: YamlScalar[] = [];\n for (const line of content) {\n const item = SEQUENCE_ITEM.exec(line);\n if (!item || (item[1] as string).length !== indent) {\n return unsupported('a list item is continued or nested; keep each item on one line');\n }\n const text = stripLeadingComment((item[2] ?? '').trim());\n if (text.length === 0) return unsupported('a list item is empty');\n const parsed = parseInline(text);\n if (parsed.kind !== 'scalar') {\n return parsed.kind === 'list' ? unsupported('nested lists are not supported') : parsed;\n }\n items.push(parsed.scalar);\n }\n return { kind: 'list', items };\n}\n\n/** Parses a value written on the key's own line. `text` is trimmed and non-empty. */\nexport function parseInline(text: string): YamlValue {\n const head = text.charAt(0);\n if (head === '\"' || head === \"'\") {\n const quoted = head === '\"' ? readDoubleQuoted(text) : readSingleQuoted(text);\n if (typeof quoted === 'string') return unsupported(quoted);\n return trailingIsComment(text.slice(quoted.next))\n ? { kind: 'scalar', scalar: { text: quoted.text, quoted: true } }\n : unsupported('text follows a closing quote');\n }\n if (head === '[') return parseFlowSequence(text);\n if (head === '{') return unsupported('inline mappings are not supported');\n if (head === '|' || head === '>') return unsupported('block scalars are not supported; keep the value on one line');\n if (head === '&' || head === '*' || head === '!') return unsupported('anchors, aliases and tags are not supported');\n if (head === '@' || head === '`') return unsupported(`a plain value cannot start with \"${head}\"; quote it`);\n const plain = stripTrailingComment(text);\n if (/:(?:\\s|$)/.test(plain)) return unsupported('a plain value cannot contain \": \"; quote it');\n if (/^-(?:\\s|$)/.test(plain)) return unsupported('a list must start on the line after its key');\n return { kind: 'scalar', scalar: { text: plain, quoted: false } };\n}\n\nfunction stripTrailingComment(text: string): string {\n const hash = text.search(/\\s#/);\n return (hash < 0 ? text : text.slice(0, hash)).trim();\n}\n\nfunction trailingIsComment(rest: string): boolean {\n return /^\\s*(?:#.*)?$/.test(rest) && (rest.trim() === '' || /^\\s/.test(rest));\n}\n\ninterface Quoted {\n readonly text: string;\n /** Index just past the closing quote. */\n readonly next: number;\n}\n\nconst ESCAPES: Readonly<Record<string, string>> = {\n '\"': '\"',\n '\\\\': '\\\\',\n '/': '/',\n '0': '\\0',\n b: '\\b',\n f: '\\f',\n n: '\\n',\n r: '\\r',\n t: '\\t',\n};\n\nconst HEX_ESCAPE_LENGTH: Readonly<Record<string, number>> = { x: 2, u: 4, U: 8 };\n\n/** Reads a double-quoted scalar starting at index 0, or returns why it cannot. */\nfunction readDoubleQuoted(text: string): Quoted | string {\n let out = '';\n for (let i = 1; i < text.length; i += 1) {\n const ch = text.charAt(i);\n if (ch === '\"') return { text: out, next: i + 1 };\n if (ch !== '\\\\') {\n out += ch;\n continue;\n }\n const code = text.charAt(i + 1);\n const simple = ESCAPES[code];\n if (simple !== undefined) {\n out += simple;\n i += 1;\n continue;\n }\n const width = HEX_ESCAPE_LENGTH[code];\n const hex = width === undefined ? '' : text.slice(i + 2, i + 2 + width);\n if (width === undefined || hex.length !== width || !/^[0-9A-Fa-f]+$/.test(hex)) {\n return `\"\\\\${code}\" is not an escape this reader knows`;\n }\n const point = Number.parseInt(hex, 16);\n if (point > 0x10ffff) return `\"\\\\${code}${hex}\" is not a character`;\n out += String.fromCodePoint(point);\n i += 1 + width;\n }\n return 'a double-quoted value is never closed';\n}\n\nfunction readSingleQuoted(text: string): Quoted | string {\n let out = '';\n for (let i = 1; i < text.length; i += 1) {\n const ch = text.charAt(i);\n if (ch !== \"'\") {\n out += ch;\n continue;\n }\n if (text.charAt(i + 1) === \"'\") {\n out += \"'\";\n i += 1;\n continue;\n }\n return { text: out, next: i + 1 };\n }\n return 'a single-quoted value is never closed';\n}\n\nfunction parseFlowSequence(text: string): YamlValue {\n const items: YamlScalar[] = [];\n let i = 1;\n for (;;) {\n while (i < text.length && /\\s/.test(text.charAt(i))) i += 1;\n if (i >= text.length) return unsupported('an inline list is never closed; keep it on one line');\n const ch = text.charAt(i);\n if (ch === ']') {\n return trailingIsComment(text.slice(i + 1))\n ? { kind: 'list', items }\n : unsupported('text follows the end of an inline list');\n }\n if (ch === '[' || ch === '{') return unsupported('nested lists and mappings are not supported');\n if (ch === ',') return unsupported('an inline list has an empty item');\n let item: YamlScalar;\n if (ch === '\"' || ch === \"'\") {\n const rest = text.slice(i);\n const quoted = ch === '\"' ? readDoubleQuoted(rest) : readSingleQuoted(rest);\n if (typeof quoted === 'string') return unsupported(quoted);\n item = { text: quoted.text, quoted: true };\n i += quoted.next;\n } else {\n let j = i;\n while (j < text.length && !',]'.includes(text.charAt(j))) j += 1;\n const plain = text.slice(i, j).trim();\n if (/[[{]/.test(plain) || /:(?:\\s|$)/.test(plain) || plain.includes(' #')) {\n return unsupported(`\"${plain}\" needs quoting inside an inline list`);\n }\n item = { text: plain, quoted: false };\n i = j;\n }\n items.push(item);\n while (i < text.length && /\\s/.test(text.charAt(i))) i += 1;\n if (i >= text.length) return unsupported('an inline list is never closed; keep it on one line');\n // After a comma the next pass reads an item or, legally in YAML, the bracket.\n if (text.charAt(i) === ',') i += 1;\n else if (text.charAt(i) !== ']') return unsupported('inline list items must be separated by commas');\n }\n}\n\n/** Null in the YAML 1.2 core schema: empty, `~` or `null` in any of its three spellings. */\nexport function isNull(scalar: YamlScalar): boolean {\n return !scalar.quoted && ['', '~', 'null', 'Null', 'NULL'].includes(scalar.text);\n}\n\n/** Renders a string as a scalar that reads back as the same string. */\nexport function renderScalar(value: string): string {\n const reserved = /^(?:true|false|null|yes|no|on|off|~)$/i.test(value);\n const plain = /^[A-Za-z][A-Za-z0-9 ._/+-]*$/.test(value) && !value.endsWith(' ');\n return plain && !reserved ? value : JSON.stringify(value);\n}\n\nexport function findEntry(frontMatter: FrontMatter | null, key: string): FrontMatterEntry | undefined {\n const name = keyName(key);\n return frontMatter?.entries.find((entry) => entry.name === name);\n}\n\n/**\n * Sets one key, leaving every other line as it was. An existing entry keeps the\n * spelling of its key; a new one goes last. A file with no front matter gains\n * a block.\n */\nexport function setEntry(\n lines: readonly string[],\n frontMatter: FrontMatter | null,\n key: string,\n rendered: string,\n): string[] {\n if (frontMatter === null) return ['---', `${key}: ${rendered}`, '---', ...lines];\n if (frontMatter.close < 0) throw new Error('cannot edit front matter that is never closed');\n const entry = findEntry(frontMatter, key);\n if (entry === undefined) {\n return [...lines.slice(0, frontMatter.close), `${key}: ${rendered}`, ...lines.slice(frontMatter.close)];\n }\n return [...lines.slice(0, entry.line), `${entry.key}: ${rendered}`, ...lines.slice(entry.end)];\n}\n\n/** Removes one key and its value lines; a key that is absent changes nothing. */\nexport function removeEntry(lines: readonly string[], frontMatter: FrontMatter | null, key: string): string[] {\n const entry = findEntry(frontMatter, key);\n if (entry === undefined) return [...lines];\n return [...lines.slice(0, entry.line), ...lines.slice(entry.end)];\n}\n"]}
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,eAAe,IAAI,QAAQ,EAAE,QAAQ,EAAoB,MAAM,sCAAsC,CAAC;AAC1H,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EACL,SAAS,EACT,MAAM,EACN,OAAO,EACP,WAAW,EACX,WAAW,EACX,YAAY,EACZ,QAAQ,GAMT,MAAM,sCAAsC,CAAC;AAE9C,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,OAAO,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAwB,EAAE,WAA+B,EAAE,GAAW,EAAE,QAAgB;IAC7H,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAC1C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IACvE,2DAA2D;IAC3D,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7F,MAAM,IAAI,GAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;IAC7E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,QAAQ,CAAC,WAAwB;IAC/C,OAAO,WAAW,CAAC,IAAI,KAAK,MAAM,IAAI,WAAW,CAAC,KAAK,IAAI,CAAC,CAAC;AAC/D,CAAC","sourcesContent":["/**\n * A brief's front matter: spec-core's reader and editor, copied into\n * `src/vendor/spec-core/`, over a brief's lines.\n *\n * The flat subset of YAML briefs use: `key: value` lines, plain and quoted\n * scalars, inline and block lists, comments. Anything richer is reported as\n * unsupported rather than guessed at, TOML between `+++` lines included, and\n * every value keeps its line, so an edit leaves every other line of the file\n * as it was (ADR-0001). Offsets in what it reads count in the lines joined by\n * `\\n`, which for a brief are its `lines`, not its `text`.\n */\n\nimport { findEntry, readFrontMatter as readText, setEntry, type FrontMatter } from './vendor/spec-core/markdown/index.js';\nimport { textOfLines } from './text.js';\n\nexport {\n findEntry,\n isNull,\n keyName,\n parseInline,\n removeEntry,\n renderScalar,\n setEntry,\n type FrontMatter,\n type FrontMatterEntry,\n type FrontMatterProblem,\n type YamlScalar,\n type YamlValue,\n} from './vendor/spec-core/markdown/index.js';\n\n/** Reads the front matter at the top of `lines`, or `null` when there is none. */\nexport function readFrontMatter(lines: readonly string[]): FrontMatter | null {\n return readText(textOfLines(lines));\n}\n\n/**\n * Sets one key as `setEntry` does, and keeps a comment that followed the old\n * value on its line: `wave: 2 # after the review` becomes `wave: 3 # after\n * the review`. spec-core's editor writes the key and the value alone, and a\n * comment beside a value is often the only record of why it was chosen. A\n * value over several lines is rewritten as `setEntry` rewrites it.\n */\nexport function setEntryKeepingComment(lines: readonly string[], frontMatter: FrontMatter | null, key: string, rendered: string): string[] {\n const edited = setEntry(lines, frontMatter, key, rendered);\n const entry = findEntry(frontMatter, key);\n if (entry === undefined || entry.end !== entry.line + 1) return edited;\n // Offsets count in the lines joined by one character each.\n const lineStart = lines.slice(0, entry.line).reduce((sum, line) => sum + line.length + 1, 0);\n const rest = (lines[entry.line] as string).slice(entry.valueEnd - lineStart);\n if (!/^[ \\t]+#/.test(rest)) return edited;\n return edited.map((line, i) => (i === entry.line ? `${line}${rest}` : line));\n}\n\n/** Front matter an edit can be written into: YAML, and closed. */\nexport function editable(frontMatter: FrontMatter): boolean {\n return frontMatter.kind === 'yaml' && frontMatter.close >= 0;\n}\n"]}