@descent-vtt/spec-graph 0.10.0 → 0.11.1
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 +30 -0
- package/README.md +33 -71
- package/dist/directives.js +1 -2
- package/dist/directives.js.map +1 -1
- package/dist/extract.d.ts +1 -14
- package/dist/extract.js +24 -68
- package/dist/extract.js.map +1 -1
- package/dist/lifecycle.d.ts +1 -11
- package/dist/lifecycle.js +31 -187
- package/dist/lifecycle.js.map +1 -1
- package/dist/sections.js +6 -7
- package/dist/sections.js.map +1 -1
- package/dist/state.d.ts +12 -0
- package/dist/state.js +20 -20
- package/dist/state.js.map +1 -1
- package/dist/yaml.js +2 -2
- package/dist/yaml.js.map +1 -1
- package/package.json +1 -1
package/dist/lifecycle.js
CHANGED
|
@@ -22,42 +22,11 @@
|
|
|
22
22
|
* A hyphenated term is found anywhere in the status, so a row needs no term
|
|
23
23
|
* another in it already finds: `replaced` reads "replaced by", `review` reads
|
|
24
24
|
* "in review" and "under review", and `in-progress` reads "work in progress".
|
|
25
|
-
*
|
|
26
|
-
* A Chinese term is the English word it translates, in Traditional and in
|
|
27
|
-
* Simplified characters, and sits in that word's row. Chinese writes no space
|
|
28
|
-
* between words, so a term in Han characters is found anywhere in the status,
|
|
29
|
-
* as a hyphenated one is, and the same economy applies: `棄用` reads `已棄用`,
|
|
30
|
-
* and `待審` reads `待審核`. The superseded forms are rules of their own, in
|
|
31
|
-
* {@link supersededInChinese}.
|
|
32
25
|
*/
|
|
33
26
|
const VOCABULARY = [
|
|
34
27
|
[
|
|
35
28
|
'retired',
|
|
36
29
|
[
|
|
37
|
-
// Read as itself, though it starts with a negation. The active row's
|
|
38
|
-
// `採納` inside it is not read, because that negation stands before it.
|
|
39
|
-
'不採納',
|
|
40
|
-
'不采纳',
|
|
41
|
-
'棄用',
|
|
42
|
-
'弃用',
|
|
43
|
-
'廢棄',
|
|
44
|
-
'废弃',
|
|
45
|
-
'已停用',
|
|
46
|
-
'已過時',
|
|
47
|
-
'已过时',
|
|
48
|
-
'否決',
|
|
49
|
-
'否决',
|
|
50
|
-
'已拒絕',
|
|
51
|
-
'已拒绝',
|
|
52
|
-
'撤回',
|
|
53
|
-
'作廢',
|
|
54
|
-
'作废',
|
|
55
|
-
'延後',
|
|
56
|
-
'延后',
|
|
57
|
-
'暫緩',
|
|
58
|
-
'暂缓',
|
|
59
|
-
'擱置',
|
|
60
|
-
'搁置',
|
|
61
30
|
'superseded',
|
|
62
31
|
// Misspelled in the wild often enough that omitting it would silently
|
|
63
32
|
// mis-classify real documents as active.
|
|
@@ -98,42 +67,18 @@ const VOCABULARY = [
|
|
|
98
67
|
// have to go somewhere (ADR-0011). After retirement, so a brief written
|
|
99
68
|
// `archived, superseded by B-0007` is still retired.
|
|
100
69
|
'record',
|
|
101
|
-
['archived', 'archive'
|
|
70
|
+
['archived', 'archive'],
|
|
102
71
|
],
|
|
103
72
|
[
|
|
104
73
|
'frozen',
|
|
105
|
-
[
|
|
106
|
-
'final',
|
|
107
|
-
'finalised',
|
|
108
|
-
'finalized',
|
|
109
|
-
'frozen',
|
|
110
|
-
'locked',
|
|
111
|
-
'ratified',
|
|
112
|
-
'immutable',
|
|
113
|
-
'sealed',
|
|
114
|
-
'standard',
|
|
115
|
-
'published',
|
|
116
|
-
'定案',
|
|
117
|
-
'已凍結',
|
|
118
|
-
'已冻结',
|
|
119
|
-
],
|
|
74
|
+
['final', 'finalised', 'finalized', 'frozen', 'locked', 'ratified', 'immutable', 'sealed', 'standard', 'published'],
|
|
120
75
|
],
|
|
121
76
|
// Ahead of `active`, whose `accepted` it contains: read after it, as the
|
|
122
|
-
// rest of the draft row is, `provisionally accepted` would be active.
|
|
123
|
-
|
|
124
|
-
['draft', ['provisionally-accepted', '暫定', '暂定']],
|
|
77
|
+
// rest of the draft row is, `provisionally accepted` would be active.
|
|
78
|
+
['draft', ['provisionally-accepted']],
|
|
125
79
|
[
|
|
126
80
|
'active',
|
|
127
81
|
[
|
|
128
|
-
'接受',
|
|
129
|
-
'採納',
|
|
130
|
-
'采纳',
|
|
131
|
-
'核准',
|
|
132
|
-
'批准',
|
|
133
|
-
'生效',
|
|
134
|
-
'已實施',
|
|
135
|
-
'已实施',
|
|
136
|
-
'已完成',
|
|
137
82
|
'accepted',
|
|
138
83
|
'active',
|
|
139
84
|
'approved',
|
|
@@ -161,19 +106,6 @@ const VOCABULARY = [
|
|
|
161
106
|
[
|
|
162
107
|
'draft',
|
|
163
108
|
[
|
|
164
|
-
'草稿',
|
|
165
|
-
'草案',
|
|
166
|
-
'提議',
|
|
167
|
-
'提议',
|
|
168
|
-
'提案',
|
|
169
|
-
'審查中',
|
|
170
|
-
'审查中',
|
|
171
|
-
'審核中',
|
|
172
|
-
'审核中',
|
|
173
|
-
'討論中',
|
|
174
|
-
'讨论中',
|
|
175
|
-
'待審',
|
|
176
|
-
'待审',
|
|
177
109
|
'draft',
|
|
178
110
|
'drafting',
|
|
179
111
|
'proposed',
|
|
@@ -216,50 +148,18 @@ const RETIRING_DIRECTORIES = new Set([
|
|
|
216
148
|
'superceded',
|
|
217
149
|
'withdrawn',
|
|
218
150
|
]);
|
|
219
|
-
/**
|
|
220
|
-
|
|
221
|
-
* Chinese key is the English one it translates, so it ranks beside it.
|
|
222
|
-
*/
|
|
223
|
-
export const STATUS_KEYS = ['status', '狀態', '状态', 'state', 'stage', 'lifecycle', 'phase', 'adr-status'];
|
|
151
|
+
/** Front-matter keys that may carry a status, in order of preference. */
|
|
152
|
+
export const STATUS_KEYS = ['status', 'state', 'stage', 'lifecycle', 'phase', 'adr-status'];
|
|
224
153
|
/** Heading names whose body declares the document status. */
|
|
225
|
-
const STATUS_HEADINGS = new Set([
|
|
226
|
-
'status',
|
|
227
|
-
'state',
|
|
228
|
-
'stage',
|
|
229
|
-
'lifecycle',
|
|
230
|
-
'current status',
|
|
231
|
-
'狀態',
|
|
232
|
-
'状态',
|
|
233
|
-
]);
|
|
234
|
-
/** A term written in Han characters, which is found anywhere in a status rather than as a word. */
|
|
235
|
-
const HAN = /\p{Script=Han}/u;
|
|
236
|
-
/**
|
|
237
|
-
* What cancels a Han term written directly after it: `未接受`, `尚未核准` and
|
|
238
|
-
* `不再生效` are not accepted, approved or in effect, and `未移交給 ADR-0002`
|
|
239
|
-
* hands nothing on. One list for status words and relation phrases alike, so
|
|
240
|
-
* the two cannot come to disagree about what a negation is. `尚未` ends in
|
|
241
|
-
* `未`, so it needs no entry of its own.
|
|
242
|
-
*/
|
|
243
|
-
const HAN_NEGATIONS = ['不', '未', '非', '沒', '没', '無', '无', '勿', '不再'];
|
|
244
|
-
/**
|
|
245
|
-
* `被 ADR-0003 取代`, and `被取代` with nothing between: superseded, in the
|
|
246
|
-
* passive, with the successor between `被` and the verb. Thirty characters
|
|
247
|
-
* leave room for a name or two and not for a clause, and the gap never runs
|
|
248
|
-
* past the end of a sentence: `被團隊接受。取代 ADR-0002 的方案另議` is no
|
|
249
|
-
* supersession of this document.
|
|
250
|
-
*/
|
|
251
|
-
const PASSIVE_SUPERSESSION = /被([^。;!?]{0,30}?)所?(?:取而代之|取代|替代)/gu;
|
|
154
|
+
const STATUS_HEADINGS = new Set(['status', 'state', 'stage', 'lifecycle', 'current status']);
|
|
252
155
|
/**
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Strips what decorates a status and keeps its punctuation: HTML, emphasis,
|
|
260
|
-
* link syntax, emoji and dates. Lower-cased, since every term is.
|
|
156
|
+
* Reduces a status string to lookup form.
|
|
157
|
+
*
|
|
158
|
+
* Strips Markdown emphasis, badge syntax, emoji and dates, so `**Accepted**`,
|
|
159
|
+
* `` `accepted` ``, `Accepted ✅` and `Accepted (2026-03-01)` all land on the
|
|
160
|
+
* same token.
|
|
261
161
|
*/
|
|
262
|
-
function
|
|
162
|
+
export function normaliseStatus(raw) {
|
|
263
163
|
// An underscore between two letters joins two words - `not_planned`,
|
|
264
164
|
// `in_progress` - where one at either end of a word is emphasis. Stripped
|
|
265
165
|
// with the emphasis, it ran the two words into one that is neither.
|
|
@@ -270,52 +170,10 @@ function undecorated(raw) {
|
|
|
270
170
|
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
271
171
|
.replace(/\p{Extended_Pictographic}/gu, ' ')
|
|
272
172
|
.replace(/\d{4}-\d{2}-\d{2}/g, ' ')
|
|
273
|
-
.toLowerCase()
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Reduces a status string to lookup form.
|
|
277
|
-
*
|
|
278
|
-
* Strips Markdown emphasis, badge syntax, emoji and dates, so `**Accepted**`,
|
|
279
|
-
* `` `accepted` ``, `Accepted ✅` and `Accepted (2026-03-01)` all land on the
|
|
280
|
-
* same token.
|
|
281
|
-
*/
|
|
282
|
-
export function normaliseStatus(raw) {
|
|
283
|
-
return undecorated(raw)
|
|
173
|
+
.toLowerCase()
|
|
284
174
|
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
|
285
175
|
.trim();
|
|
286
176
|
}
|
|
287
|
-
/** Whether a Chinese negation stands directly before the offset. */
|
|
288
|
-
export function negatedAt(text, offset) {
|
|
289
|
-
const before = text.slice(0, offset);
|
|
290
|
-
return HAN_NEGATIONS.some((negation) => before.endsWith(negation));
|
|
291
|
-
}
|
|
292
|
-
/** Whether a Han term occurs in the text with no negation directly before it. */
|
|
293
|
-
function hanTermIn(text, term) {
|
|
294
|
-
for (let at = text.indexOf(term); at !== -1; at = text.indexOf(term, at + 1)) {
|
|
295
|
-
if (!negatedAt(text, at))
|
|
296
|
-
return true;
|
|
297
|
-
}
|
|
298
|
-
return false;
|
|
299
|
-
}
|
|
300
|
-
/** The text between `被` and the verb of every passive supersession not negated. */
|
|
301
|
-
function passiveSupersessions(text) {
|
|
302
|
-
const out = [];
|
|
303
|
-
for (const match of text.matchAll(PASSIVE_SUPERSESSION)) {
|
|
304
|
-
if (!negatedAt(text, match.index))
|
|
305
|
-
out.push(match[1]);
|
|
306
|
-
}
|
|
307
|
-
return out;
|
|
308
|
-
}
|
|
309
|
-
/** Whether a status says it was superseded, in Chinese. */
|
|
310
|
-
function supersededInChinese(text) {
|
|
311
|
-
if (passiveSupersessions(text).length > 0)
|
|
312
|
-
return true;
|
|
313
|
-
for (const match of text.matchAll(SUPERSEDED_ALONE)) {
|
|
314
|
-
if (!negatedAt(text, match.index))
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
177
|
/**
|
|
320
178
|
* Maps a raw status string onto a lifecycle phase.
|
|
321
179
|
*
|
|
@@ -327,21 +185,12 @@ function supersededInChinese(text) {
|
|
|
327
185
|
export function phaseOf(raw) {
|
|
328
186
|
if (raw === null || raw === undefined)
|
|
329
187
|
return 'unknown';
|
|
330
|
-
const
|
|
331
|
-
// Retirement wins wherever it is written, so the superseded forms need no
|
|
332
|
-
// place in the table's order.
|
|
333
|
-
if (supersededInChinese(plain))
|
|
334
|
-
return 'retired';
|
|
335
|
-
const text = plain.replace(/[^\p{L}\p{N}]+/gu, ' ').trim();
|
|
188
|
+
const text = normaliseStatus(raw);
|
|
336
189
|
const words = new Set(text.split(' '));
|
|
337
190
|
const hyphenated = text.replace(/ /g, '-');
|
|
338
191
|
for (const [phase, terms] of VOCABULARY) {
|
|
339
192
|
for (const term of terms) {
|
|
340
|
-
if (
|
|
341
|
-
if (hanTermIn(plain, term))
|
|
342
|
-
return phase;
|
|
343
|
-
}
|
|
344
|
-
else if (term.includes('-')) {
|
|
193
|
+
if (term.includes('-')) {
|
|
345
194
|
if (hyphenated.includes(term))
|
|
346
195
|
return phase;
|
|
347
196
|
}
|
|
@@ -374,7 +223,7 @@ export function isRetired(phase) {
|
|
|
374
223
|
}
|
|
375
224
|
/** True when the heading names a section that declares the document status. */
|
|
376
225
|
export function isStatusHeading(text) {
|
|
377
|
-
return STATUS_HEADINGS.has(text.toLowerCase().replace(/[
|
|
226
|
+
return STATUS_HEADINGS.has(text.toLowerCase().replace(/[:*_`]/g, '').trim());
|
|
378
227
|
}
|
|
379
228
|
/**
|
|
380
229
|
* Infers retirement from where a file lives.
|
|
@@ -400,31 +249,26 @@ export function phaseFromPath(posixPath) {
|
|
|
400
249
|
* recorded, and it is written in the status field rather than as a link. Reading
|
|
401
250
|
* it here means the relation reaches the graph even in repositories that never
|
|
402
251
|
* adopted an explicit field for it.
|
|
403
|
-
*
|
|
404
|
-
* In Chinese the successor stands between `被` and the verb: `已被 ADR-0003
|
|
405
|
-
* 取代`. Left unread, a document that said so and one that said it supersedes
|
|
406
|
-
* this one disagreed, and `unreciprocated-supersession` asked for a
|
|
407
|
-
* `superseded-by` key the status had already given.
|
|
408
252
|
*/
|
|
409
253
|
export function supersessionTargetsIn(raw) {
|
|
410
254
|
const out = [];
|
|
411
|
-
const plain = raw.replace(/[`*_]/g, '');
|
|
412
255
|
// The tail runs to the end of the line, not of the string: a status that
|
|
413
256
|
// wraps onto a second line still names its successor on the first.
|
|
414
257
|
const pattern = /(?:super[sc]eded|replaced|obsoleted)\s*(?:by|with|through)?\s*[:\-–—]?\s*(.+)/i;
|
|
415
|
-
const match = pattern.exec(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
258
|
+
const match = pattern.exec(raw.replace(/[`*_]/g, ''));
|
|
259
|
+
if (!match)
|
|
260
|
+
return out;
|
|
261
|
+
const tail = match[1];
|
|
262
|
+
// A list punctuated full-width, `ADR-0003,ADR-0004`, is split as one
|
|
263
|
+
// punctuated in ASCII. Left whole it named no document, and each successor
|
|
264
|
+
// was reported as one the status never acknowledged.
|
|
265
|
+
for (const token of tail.split(/[,;、,;]|\band\b/)) {
|
|
266
|
+
const cleaned = token
|
|
267
|
+
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
268
|
+
.replace(/[()<>"'()]/g, ' ')
|
|
269
|
+
.trim();
|
|
270
|
+
if (cleaned.length > 0 && cleaned.length < 200)
|
|
271
|
+
out.push(cleaned);
|
|
428
272
|
}
|
|
429
273
|
return out;
|
|
430
274
|
}
|
package/dist/lifecycle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,GAAqD;IACnE;QACE,SAAS;QACT;YACE,qEAAqE;YACrE,sEAAsE;YACtE,KAAK;YACL,KAAK;YACL,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,KAAK;YACL,KAAK;YACL,KAAK;YACL,IAAI;YACJ,IAAI;YACJ,KAAK;YACL,KAAK;YACL,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,YAAY;YACZ,sEAAsE;YACtE,yCAAyC;YACzC,YAAY;YACZ,eAAe;YACf,UAAU;YACV,YAAY;YACZ,UAAU;YACV,WAAW;YACX,SAAS;YACT,UAAU;YACV,UAAU;YACV,WAAW;YACX,WAAW;YACX,WAAW;YACX,UAAU;YACV,SAAS;YACT,SAAS;YACT,UAAU;YACV,OAAO;YACP,YAAY;YACZ,SAAS;YACT,UAAU;YACV,MAAM;YACN,MAAM;YACN,QAAQ;YACR,WAAW;YACX,UAAU;YACV,aAAa;YACb,SAAS;SACV;KACF;IACD;QACE,4EAA4E;QAC5E,4EAA4E;QAC5E,yEAAyE;QACzE,wEAAwE;QACxE,wEAAwE;QACxE,qDAAqD;QACrD,QAAQ;QACR,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;KAC1C;IACD;QACE,QAAQ;QACR;YACE,OAAO;YACP,WAAW;YACX,WAAW;YACX,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,WAAW;YACX,QAAQ;YACR,UAAU;YACV,WAAW;YACX,IAAI;YACJ,KAAK;YACL,KAAK;SACN;KACF;IACD,yEAAyE;IACzE,2EAA2E;IAC3E,4DAA4D;IAC5D,CAAC,OAAO,EAAE,CAAC,wBAAwB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACjD;QACE,QAAQ;QACR;YACE,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,KAAK;YACL,KAAK;YACL,KAAK;YACL,UAAU;YACV,QAAQ;YACR,UAAU;YACV,SAAS;YACT,QAAQ;YACR,eAAe;YACf,aAAa;YACb,cAAc;YACd,SAAS;YACT,WAAW;YACX,WAAW;YACX,UAAU;YACV,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,SAAS;YACT,MAAM;YACN,MAAM;YACN,UAAU;YACV,WAAW;YACX,YAAY;YACZ,WAAW;SACZ;KACF;IACD;QACE,OAAO;QACP;YACE,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,IAAI;YACJ,IAAI;YACJ,OAAO;YACP,UAAU;YACV,UAAU;YACV,UAAU;YACV,aAAa;YACb,aAAa;YACb,KAAK;YACL,aAAa;YACb,QAAQ;YACR,WAAW;YACX,YAAY;YACZ,YAAY;YACZ,SAAS;YACT,MAAM;YACN,aAAa;YACb,WAAW;YACX,MAAM;YACN,KAAK;YACL,YAAY;YACZ,KAAK;YACL,cAAc;YACd,OAAO;YACP,MAAM;YACN,YAAY;SACb;KACF;CACF,CAAC;AAEF,6DAA6D;AAC7D,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAC;IACxD,SAAS;IACT,UAAU;IACV,OAAO;IACP,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,UAAU;IACV,UAAU;IACV,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,WAAW;CACZ,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAsB,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;AAE3H,6DAA6D;AAC7D,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC;IACnD,QAAQ;IACR,OAAO;IACP,OAAO;IACP,WAAW;IACX,gBAAgB;IAChB,IAAI;IACJ,IAAI;CACL,CAAC,CAAC;AAEH,mGAAmG;AACnG,MAAM,GAAG,GAAG,iBAAiB,CAAC;AAE9B;;;;;;GAMG;AACH,MAAM,aAAa,GAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;AAExF;;;;;;GAMG;AACH,MAAM,oBAAoB,GAAG,qCAAqC,CAAC;AAEnE;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,8BAA8B,CAAC;AAExD;;;GAGG;AACH,SAAS,WAAW,CAAC,GAAW;IAC9B,qEAAqE;IACrE,0EAA0E;IAC1E,oEAAoE;IACpE,OAAO,GAAG;SACP,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,sCAAsC,EAAE,GAAG,CAAC;SACpD,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC;SACvC,OAAO,CAAC,6BAA6B,EAAE,GAAG,CAAC;SAC3C,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC;SAClC,WAAW,EAAE,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,WAAW,CAAC,GAAG,CAAC;SACpB,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC;SAChC,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,iFAAiF;AACjF,SAAS,SAAS,CAAC,IAAY,EAAE,IAAY;IAC3C,KAAK,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7E,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;IACxC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,mFAAmF;AACnF,SAAS,oBAAoB,CAAC,IAAY;IACxC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAW,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,2DAA2D;AAC3D,SAAS,mBAAmB,CAAC,IAAY;IACvC,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACpD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;IACjD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,GAA8B;IACpD,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC/B,0EAA0E;IAC1E,8BAA8B;IAC9B,IAAI,mBAAmB,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACjD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAE3C,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,CAAC;QACxC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnB,IAAI,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC;oBAAE,OAAO,KAAK,CAAC;YAC3C,CAAC;iBAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9B,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,OAAO,KAAK,CAAC;YAC9C,CAAC;iBAAM,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,KAAY;IACxC,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,WAAW,CAAC;QACrB,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC;QACf,yEAAyE;QACzE,0EAA0E;QAC1E,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,SAAS,CAAC,KAAY;IACpC,OAAO,KAAK,KAAK,SAAS,CAAC;AAC7B,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpD,6EAA6E;IAC7E,2CAA2C;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAW,CAAC;YAAE,OAAO,SAAS,CAAC;IACxE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACxC,yEAAyE;IACzE,mEAAmE;IACnE,MAAM,OAAO,GAAG,gFAAgF,CAAC;IACjG,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,2EAA2E;IAC3E,iEAAiE;IACjE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAW,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC,CAAC;IACjH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC;YACtD,MAAM,OAAO,GAAG,KAAK;iBAClB,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC;iBACvC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;iBAC3B,IAAI,EAAE,CAAC;YACV,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * Status vocabulary normalisation.\n *\n * Every specification ecosystem invented its own status words, and no two agree.\n * MADR says `accepted`; Kubernetes KEPs say `implementable`; Rust RFCs say\n * `merged`; a hundred internal wikis say `Live`, `Signed off`, or `DONE ✅`.\n *\n * spec-graph refuses to care. What it needs from a status is one bit - *can this\n * document still absorb an obligation?* - and that bit is recoverable from all\n * of those vocabularies at once. The tables below are the only place in the\n * codebase that knows any ecosystem-specific word, which is what keeps the\n * engine domain-agnostic: supporting a new convention is a table entry, never a\n * rule change.\n */\n\nimport type { Phase, Receptivity } from './types.js';\n\n/**\n * Recognised status words, most terminal first.\n *\n * Order matters. A status of \"accepted, superseded by ADR-0009\" is retired, not\n * active: retirement is terminal, so a retirement word anywhere in the string\n * wins over anything else in it.\n *\n * A hyphenated term is found anywhere in the status, so a row needs no term\n * another in it already finds: `replaced` reads \"replaced by\", `review` reads\n * \"in review\" and \"under review\", and `in-progress` reads \"work in progress\".\n *\n * A Chinese term is the English word it translates, in Traditional and in\n * Simplified characters, and sits in that word's row. Chinese writes no space\n * between words, so a term in Han characters is found anywhere in the status,\n * as a hyphenated one is, and the same economy applies: `棄用` reads `已棄用`,\n * and `待審` reads `待審核`. The superseded forms are rules of their own, in\n * {@link supersededInChinese}.\n */\nconst VOCABULARY: readonly (readonly [Phase, readonly string[]])[] = [\n [\n 'retired',\n [\n // Read as itself, though it starts with a negation. The active row's\n // `採納` inside it is not read, because that negation stands before it.\n '不採納',\n '不采纳',\n '棄用',\n '弃用',\n '廢棄',\n '废弃',\n '已停用',\n '已過時',\n '已过时',\n '否決',\n '否决',\n '已拒絕',\n '已拒绝',\n '撤回',\n '作廢',\n '作废',\n '延後',\n '延后',\n '暫緩',\n '暂缓',\n '擱置',\n '搁置',\n 'superseded',\n // Misspelled in the wild often enough that omitting it would silently\n // mis-classify real documents as active.\n 'superceded',\n 'supersedes-by',\n 'replaced',\n 'deprecated',\n 'obsolete',\n 'obsoleted',\n 'retired',\n 'rejected',\n 'declined',\n 'withdrawn',\n 'abandoned',\n 'cancelled',\n 'canceled',\n 'dropped',\n 'revoked',\n 'reverted',\n 'moved',\n 'historical',\n 'defunct',\n 'inactive',\n 'dead',\n 'void',\n 'closed',\n 'postponed',\n 'deferred',\n 'not-planned',\n 'wontfix',\n ],\n ],\n [\n // A finished round of work kept as it was left: spec-brief archives a brief\n // by writing this word and moving the file. Every spec-* tool reads it as a\n // record rather than as a retired decision - depending on one is normal,\n // its unticked boxes were never going to be ticked, and its links still\n // have to go somewhere (ADR-0011). After retirement, so a brief written\n // `archived, superseded by B-0007` is still retired.\n 'record',\n ['archived', 'archive', '封存', '歸檔', '归档'],\n ],\n [\n 'frozen',\n [\n 'final',\n 'finalised',\n 'finalized',\n 'frozen',\n 'locked',\n 'ratified',\n 'immutable',\n 'sealed',\n 'standard',\n 'published',\n '定案',\n '已凍結',\n '已冻结',\n ],\n ],\n // Ahead of `active`, whose `accepted` it contains: read after it, as the\n // rest of the draft row is, `provisionally accepted` would be active. `暫定`\n // is the same word, and `暫定接受` holds the active row's `接受`.\n ['draft', ['provisionally-accepted', '暫定', '暂定']],\n [\n 'active',\n [\n '接受',\n '採納',\n '采纳',\n '核准',\n '批准',\n '生效',\n '已實施',\n '已实施',\n '已完成',\n 'accepted',\n 'active',\n 'approved',\n 'adopted',\n 'agreed',\n 'implementable',\n 'implemented',\n 'implementing',\n 'current',\n 'effective',\n 'in-effect',\n 'enforced',\n 'stable',\n 'merged',\n 'released',\n 'shipped',\n 'live',\n 'done',\n 'complete',\n 'completed',\n 'signed-off',\n 'committed',\n ],\n ],\n [\n 'draft',\n [\n '草稿',\n '草案',\n '提議',\n '提议',\n '提案',\n '審查中',\n '审查中',\n '審核中',\n '审核中',\n '討論中',\n '讨论中',\n '待審',\n '待审',\n 'draft',\n 'drafting',\n 'proposed',\n 'proposal',\n 'provisional',\n 'prospective',\n 'wip',\n 'in-progress',\n 'review',\n 'reviewing',\n 'discussion',\n 'discussing',\n 'pending',\n 'idea',\n 'exploratory',\n 'candidate',\n 'open',\n 'new',\n 'unreviewed',\n 'rfc',\n 'experimental',\n 'alpha',\n 'beta',\n 'incubating',\n ],\n ],\n];\n\n/** Path segments that retire every document beneath them. */\nconst RETIRING_DIRECTORIES: ReadonlySet<string> = new Set([\n 'archive',\n 'archived',\n 'attic',\n 'deprecated',\n 'graveyard',\n 'historical',\n 'obsolete',\n 'rejected',\n 'retired',\n 'superseded',\n 'superceded',\n 'withdrawn',\n]);\n\n/**\n * Front-matter keys that may carry a status, in order of preference. The\n * Chinese key is the English one it translates, so it ranks beside it.\n */\nexport const STATUS_KEYS: readonly string[] = ['status', '狀態', '状态', 'state', 'stage', 'lifecycle', 'phase', 'adr-status'];\n\n/** Heading names whose body declares the document status. */\nconst STATUS_HEADINGS: ReadonlySet<string> = new Set([\n 'status',\n 'state',\n 'stage',\n 'lifecycle',\n 'current status',\n '狀態',\n '状态',\n]);\n\n/** A term written in Han characters, which is found anywhere in a status rather than as a word. */\nconst HAN = /\\p{Script=Han}/u;\n\n/**\n * What cancels a Han term written directly after it: `未接受`, `尚未核准` and\n * `不再生效` are not accepted, approved or in effect, and `未移交給 ADR-0002`\n * hands nothing on. One list for status words and relation phrases alike, so\n * the two cannot come to disagree about what a negation is. `尚未` ends in\n * `未`, so it needs no entry of its own.\n */\nconst HAN_NEGATIONS: readonly string[] = ['不', '未', '非', '沒', '没', '無', '无', '勿', '不再'];\n\n/**\n * `被 ADR-0003 取代`, and `被取代` with nothing between: superseded, in the\n * passive, with the successor between `被` and the verb. Thirty characters\n * leave room for a name or two and not for a clause, and the gap never runs\n * past the end of a sentence: `被團隊接受。取代 ADR-0002 的方案另議` is no\n * supersession of this document.\n */\nconst PASSIVE_SUPERSESSION = /被([^。;!?]{0,30}?)所?(?:取而代之|取代|替代)/gu;\n\n/**\n * `已取代` said alone. Followed by a name - `已取代 ADR-0002`, `已取代舊方案`,\n * after spaces or a colon - it usually says what *this* document replaced, and\n * reading it either way would be a guess.\n */\nconst SUPERSEDED_ALONE = /已取代(?![\\s::]*[\\p{L}\\p{N}])/gu;\n\n/**\n * Strips what decorates a status and keeps its punctuation: HTML, emphasis,\n * link syntax, emoji and dates. Lower-cased, since every term is.\n */\nfunction undecorated(raw: string): string {\n // An underscore between two letters joins two words - `not_planned`,\n // `in_progress` - where one at either end of a word is emphasis. Stripped\n // with the emphasis, it ran the two words into one that is neither.\n return raw\n .replace(/<[^>]*>/g, ' ')\n .replace(/(?<=[\\p{L}\\p{N}])_(?=[\\p{L}\\p{N}])/gu, ' ')\n .replace(/[`*_~\"'#]/g, '')\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\p{Extended_Pictographic}/gu, ' ')\n .replace(/\\d{4}-\\d{2}-\\d{2}/g, ' ')\n .toLowerCase();\n}\n\n/**\n * Reduces a status string to lookup form.\n *\n * Strips Markdown emphasis, badge syntax, emoji and dates, so `**Accepted**`,\n * `` `accepted` ``, `Accepted ✅` and `Accepted (2026-03-01)` all land on the\n * same token.\n */\nexport function normaliseStatus(raw: string): string {\n return undecorated(raw)\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .trim();\n}\n\n/** Whether a Chinese negation stands directly before the offset. */\nexport function negatedAt(text: string, offset: number): boolean {\n const before = text.slice(0, offset);\n return HAN_NEGATIONS.some((negation) => before.endsWith(negation));\n}\n\n/** Whether a Han term occurs in the text with no negation directly before it. */\nfunction hanTermIn(text: string, term: string): boolean {\n for (let at = text.indexOf(term); at !== -1; at = text.indexOf(term, at + 1)) {\n if (!negatedAt(text, at)) return true;\n }\n return false;\n}\n\n/** The text between `被` and the verb of every passive supersession not negated. */\nfunction passiveSupersessions(text: string): string[] {\n const out: string[] = [];\n for (const match of text.matchAll(PASSIVE_SUPERSESSION)) {\n if (!negatedAt(text, match.index)) out.push(match[1] as string);\n }\n return out;\n}\n\n/** Whether a status says it was superseded, in Chinese. */\nfunction supersededInChinese(text: string): boolean {\n if (passiveSupersessions(text).length > 0) return true;\n for (const match of text.matchAll(SUPERSEDED_ALONE)) {\n if (!negatedAt(text, match.index)) return true;\n }\n return false;\n}\n\n/**\n * Maps a raw status string onto a lifecycle phase.\n *\n * Returns `unknown` rather than guessing when nothing matches: a document with\n * an unrecognised status is not evidence of anything, and inventing a phase for\n * it would produce exactly the confident-but-wrong findings this tool exists to\n * eliminate.\n */\nexport function phaseOf(raw: string | null | undefined): Phase {\n if (raw === null || raw === undefined) return 'unknown';\n const plain = undecorated(raw);\n // Retirement wins wherever it is written, so the superseded forms need no\n // place in the table's order.\n if (supersededInChinese(plain)) return 'retired';\n const text = plain.replace(/[^\\p{L}\\p{N}]+/gu, ' ').trim();\n const words = new Set(text.split(' '));\n const hyphenated = text.replace(/ /g, '-');\n\n for (const [phase, terms] of VOCABULARY) {\n for (const term of terms) {\n if (HAN.test(term)) {\n if (hanTermIn(plain, term)) return phase;\n } else if (term.includes('-')) {\n if (hyphenated.includes(term)) return phase;\n } else if (words.has(term)) {\n return phase;\n }\n }\n }\n return 'unknown';\n}\n\n/** Whether a document in this phase can take on a new open obligation. */\nexport function receptivityOf(phase: Phase): Receptivity {\n switch (phase) {\n case 'draft':\n case 'active':\n return 'receptive';\n case 'frozen':\n case 'retired':\n // A record was never asking for an obligation, so it cannot take one on.\n // Sealed for the same reason a retired document is, by a different route.\n case 'record':\n return 'sealed';\n case 'unknown':\n return 'unknown';\n }\n}\n\n/** True when the phase means the document no longer binds anybody. */\nexport function isRetired(phase: Phase): boolean {\n return phase === 'retired';\n}\n\n/** True when the heading names a section that declares the document status. */\nexport function isStatusHeading(text: string): boolean {\n return STATUS_HEADINGS.has(text.toLowerCase().replace(/[::*_`]/g, '').trim());\n}\n\n/**\n * Infers retirement from where a file lives.\n *\n * Moving an ADR into `docs/adr/archive/` is the most common way a team retires a\n * decision without touching its front matter, and a graph that misses it will\n * happily let obligations be delegated into the archive.\n */\nexport function phaseFromPath(posixPath: string): Phase {\n const segments = posixPath.toLowerCase().split('/');\n // The file name itself is not a directory; a document called `archive`, with\n // or without an extension, is not retired.\n for (let i = 0; i < segments.length - 1; i += 1) {\n if (RETIRING_DIRECTORIES.has(segments[i] as string)) return 'retired';\n }\n return 'unknown';\n}\n\n/**\n * Pulls a supersession target out of a status string.\n *\n * `Superseded by ADR-0009` is the single most common way a supersession is ever\n * recorded, and it is written in the status field rather than as a link. Reading\n * it here means the relation reaches the graph even in repositories that never\n * adopted an explicit field for it.\n *\n * In Chinese the successor stands between `被` and the verb: `已被 ADR-0003\n * 取代`. Left unread, a document that said so and one that said it supersedes\n * this one disagreed, and `unreciprocated-supersession` asked for a\n * `superseded-by` key the status had already given.\n */\nexport function supersessionTargetsIn(raw: string): string[] {\n const out: string[] = [];\n const plain = raw.replace(/[`*_]/g, '');\n // The tail runs to the end of the line, not of the string: a status that\n // wraps onto a second line still names its successor on the first.\n const pattern = /(?:super[sc]eded|replaced|obsoleted)\\s*(?:by|with|through)?\\s*[:\\-–—]?\\s*(.+)/i;\n const match = pattern.exec(plain);\n // A link inside the passive is read by its label, as a status is: its path\n // would run the name past the thirty characters the form allows.\n const tails = match ? [match[1] as string] : passiveSupersessions(plain.replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1'));\n for (const tail of tails) {\n for (const token of tail.split(/[,;、,;和及與与]|\\band\\b/)) {\n const cleaned = token\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/[()<>\"'()]/g, ' ')\n .trim();\n if (cleaned.length > 0 && cleaned.length < 200) out.push(cleaned);\n }\n }\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Status vocabulary normalisation.\n *\n * Every specification ecosystem invented its own status words, and no two agree.\n * MADR says `accepted`; Kubernetes KEPs say `implementable`; Rust RFCs say\n * `merged`; a hundred internal wikis say `Live`, `Signed off`, or `DONE ✅`.\n *\n * spec-graph refuses to care. What it needs from a status is one bit - *can this\n * document still absorb an obligation?* - and that bit is recoverable from all\n * of those vocabularies at once. The tables below are the only place in the\n * codebase that knows any ecosystem-specific word, which is what keeps the\n * engine domain-agnostic: supporting a new convention is a table entry, never a\n * rule change.\n */\n\nimport type { Phase, Receptivity } from './types.js';\n\n/**\n * Recognised status words, most terminal first.\n *\n * Order matters. A status of \"accepted, superseded by ADR-0009\" is retired, not\n * active: retirement is terminal, so a retirement word anywhere in the string\n * wins over anything else in it.\n *\n * A hyphenated term is found anywhere in the status, so a row needs no term\n * another in it already finds: `replaced` reads \"replaced by\", `review` reads\n * \"in review\" and \"under review\", and `in-progress` reads \"work in progress\".\n */\nconst VOCABULARY: readonly (readonly [Phase, readonly string[]])[] = [\n [\n 'retired',\n [\n 'superseded',\n // Misspelled in the wild often enough that omitting it would silently\n // mis-classify real documents as active.\n 'superceded',\n 'supersedes-by',\n 'replaced',\n 'deprecated',\n 'obsolete',\n 'obsoleted',\n 'retired',\n 'rejected',\n 'declined',\n 'withdrawn',\n 'abandoned',\n 'cancelled',\n 'canceled',\n 'dropped',\n 'revoked',\n 'reverted',\n 'moved',\n 'historical',\n 'defunct',\n 'inactive',\n 'dead',\n 'void',\n 'closed',\n 'postponed',\n 'deferred',\n 'not-planned',\n 'wontfix',\n ],\n ],\n [\n // A finished round of work kept as it was left: spec-brief archives a brief\n // by writing this word and moving the file. Every spec-* tool reads it as a\n // record rather than as a retired decision - depending on one is normal,\n // its unticked boxes were never going to be ticked, and its links still\n // have to go somewhere (ADR-0011). After retirement, so a brief written\n // `archived, superseded by B-0007` is still retired.\n 'record',\n ['archived', 'archive'],\n ],\n [\n 'frozen',\n ['final', 'finalised', 'finalized', 'frozen', 'locked', 'ratified', 'immutable', 'sealed', 'standard', 'published'],\n ],\n // Ahead of `active`, whose `accepted` it contains: read after it, as the\n // rest of the draft row is, `provisionally accepted` would be active.\n ['draft', ['provisionally-accepted']],\n [\n 'active',\n [\n 'accepted',\n 'active',\n 'approved',\n 'adopted',\n 'agreed',\n 'implementable',\n 'implemented',\n 'implementing',\n 'current',\n 'effective',\n 'in-effect',\n 'enforced',\n 'stable',\n 'merged',\n 'released',\n 'shipped',\n 'live',\n 'done',\n 'complete',\n 'completed',\n 'signed-off',\n 'committed',\n ],\n ],\n [\n 'draft',\n [\n 'draft',\n 'drafting',\n 'proposed',\n 'proposal',\n 'provisional',\n 'prospective',\n 'wip',\n 'in-progress',\n 'review',\n 'reviewing',\n 'discussion',\n 'discussing',\n 'pending',\n 'idea',\n 'exploratory',\n 'candidate',\n 'open',\n 'new',\n 'unreviewed',\n 'rfc',\n 'experimental',\n 'alpha',\n 'beta',\n 'incubating',\n ],\n ],\n];\n\n/** Path segments that retire every document beneath them. */\nconst RETIRING_DIRECTORIES: ReadonlySet<string> = new Set([\n 'archive',\n 'archived',\n 'attic',\n 'deprecated',\n 'graveyard',\n 'historical',\n 'obsolete',\n 'rejected',\n 'retired',\n 'superseded',\n 'superceded',\n 'withdrawn',\n]);\n\n/** Front-matter keys that may carry a status, in order of preference. */\nexport const STATUS_KEYS: readonly string[] = ['status', 'state', 'stage', 'lifecycle', 'phase', 'adr-status'];\n\n/** Heading names whose body declares the document status. */\nconst STATUS_HEADINGS: ReadonlySet<string> = new Set(['status', 'state', 'stage', 'lifecycle', 'current status']);\n\n/**\n * Reduces a status string to lookup form.\n *\n * Strips Markdown emphasis, badge syntax, emoji and dates, so `**Accepted**`,\n * `` `accepted` ``, `Accepted ✅` and `Accepted (2026-03-01)` all land on the\n * same token.\n */\nexport function normaliseStatus(raw: string): string {\n // An underscore between two letters joins two words - `not_planned`,\n // `in_progress` - where one at either end of a word is emphasis. Stripped\n // with the emphasis, it ran the two words into one that is neither.\n return raw\n .replace(/<[^>]*>/g, ' ')\n .replace(/(?<=[\\p{L}\\p{N}])_(?=[\\p{L}\\p{N}])/gu, ' ')\n .replace(/[`*_~\"'#]/g, '')\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\p{Extended_Pictographic}/gu, ' ')\n .replace(/\\d{4}-\\d{2}-\\d{2}/g, ' ')\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .trim();\n}\n\n/**\n * Maps a raw status string onto a lifecycle phase.\n *\n * Returns `unknown` rather than guessing when nothing matches: a document with\n * an unrecognised status is not evidence of anything, and inventing a phase for\n * it would produce exactly the confident-but-wrong findings this tool exists to\n * eliminate.\n */\nexport function phaseOf(raw: string | null | undefined): Phase {\n if (raw === null || raw === undefined) return 'unknown';\n const text = normaliseStatus(raw);\n const words = new Set(text.split(' '));\n const hyphenated = text.replace(/ /g, '-');\n\n for (const [phase, terms] of VOCABULARY) {\n for (const term of terms) {\n if (term.includes('-')) {\n if (hyphenated.includes(term)) return phase;\n } else if (words.has(term)) {\n return phase;\n }\n }\n }\n return 'unknown';\n}\n\n/** Whether a document in this phase can take on a new open obligation. */\nexport function receptivityOf(phase: Phase): Receptivity {\n switch (phase) {\n case 'draft':\n case 'active':\n return 'receptive';\n case 'frozen':\n case 'retired':\n // A record was never asking for an obligation, so it cannot take one on.\n // Sealed for the same reason a retired document is, by a different route.\n case 'record':\n return 'sealed';\n case 'unknown':\n return 'unknown';\n }\n}\n\n/** True when the phase means the document no longer binds anybody. */\nexport function isRetired(phase: Phase): boolean {\n return phase === 'retired';\n}\n\n/** True when the heading names a section that declares the document status. */\nexport function isStatusHeading(text: string): boolean {\n return STATUS_HEADINGS.has(text.toLowerCase().replace(/[:*_`]/g, '').trim());\n}\n\n/**\n * Infers retirement from where a file lives.\n *\n * Moving an ADR into `docs/adr/archive/` is the most common way a team retires a\n * decision without touching its front matter, and a graph that misses it will\n * happily let obligations be delegated into the archive.\n */\nexport function phaseFromPath(posixPath: string): Phase {\n const segments = posixPath.toLowerCase().split('/');\n // The file name itself is not a directory; a document called `archive`, with\n // or without an extension, is not retired.\n for (let i = 0; i < segments.length - 1; i += 1) {\n if (RETIRING_DIRECTORIES.has(segments[i] as string)) return 'retired';\n }\n return 'unknown';\n}\n\n/**\n * Pulls a supersession target out of a status string.\n *\n * `Superseded by ADR-0009` is the single most common way a supersession is ever\n * recorded, and it is written in the status field rather than as a link. Reading\n * it here means the relation reaches the graph even in repositories that never\n * adopted an explicit field for it.\n */\nexport function supersessionTargetsIn(raw: string): string[] {\n const out: string[] = [];\n // The tail runs to the end of the line, not of the string: a status that\n // wraps onto a second line still names its successor on the first.\n const pattern = /(?:super[sc]eded|replaced|obsoleted)\\s*(?:by|with|through)?\\s*[:\\-–—]?\\s*(.+)/i;\n const match = pattern.exec(raw.replace(/[`*_]/g, ''));\n if (!match) return out;\n const tail = match[1] as string;\n // A list punctuated full-width, `ADR-0003,ADR-0004`, is split as one\n // punctuated in ASCII. Left whole it named no document, and each successor\n // was reported as one the status never acknowledged.\n for (const token of tail.split(/[,;、,;]|\\band\\b/)) {\n const cleaned = token\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/[()<>\"'()]/g, ' ')\n .trim();\n if (cleaned.length > 0 && cleaned.length < 200) out.push(cleaned);\n }\n return out;\n}\n"]}
|
package/dist/sections.js
CHANGED
|
@@ -65,8 +65,8 @@ const MARKDOWN_LINK = /!?\[([^\]]*)\]\(([^)]*)\)/g;
|
|
|
65
65
|
const EMPTY_CELL = /^(?:-+|—|–|n\/?a|none|nil|tbd|\.|_+)$/i;
|
|
66
66
|
/** `## ADR-0007: Sharding` - an identifier at the very start of a heading. */
|
|
67
67
|
const HEADING_ID = /^\s*([A-Za-z]{1,15}[\s._-]?\d{1,6})\b/;
|
|
68
|
-
/** `**Status:** Accepted`, `Status: Accepted`, `*Status* : Accepted
|
|
69
|
-
const INLINE_STATUS = /^[ \t>]*[*_]{0,2}\s*
|
|
68
|
+
/** `**Status:** Accepted`, `Status: Accepted`, `*Status* : Accepted`. */
|
|
69
|
+
const INLINE_STATUS = /^[ \t>]*[*_]{0,2}\s*status\s*[*_]{0,2}\s*:\s*(.+?)\s*$/im;
|
|
70
70
|
/**
|
|
71
71
|
* Finds every specification in a file.
|
|
72
72
|
*
|
|
@@ -280,12 +280,11 @@ function splitTargets(cell) {
|
|
|
280
280
|
// Links are taken out whole rather than flattened with everything else: a
|
|
281
281
|
// path would otherwise be cut in half by its own slash, and its underscores
|
|
282
282
|
// stripped as emphasis.
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
// and never terminates.
|
|
286
|
-
const links = new RegExp(MARKDOWN_LINK.source, 'g');
|
|
283
|
+
// `matchAll` scans a copy of the pattern. `prose` calls `flatten`, which
|
|
284
|
+
// drives the shared one, and one /g regex advanced from inside its own scan
|
|
285
|
+
// resets its cursor and never terminates.
|
|
287
286
|
let last = 0;
|
|
288
|
-
for (
|
|
287
|
+
for (const match of cell.text.matchAll(MARKDOWN_LINK)) {
|
|
289
288
|
prose(cell.text.slice(last, match.index));
|
|
290
289
|
// Both groups always take part in a match, so the `?? ''` below and in the
|
|
291
290
|
// label are for the type.
|
package/dist/sections.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../src/sections.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Specification regions: the part of a file that one specification occupies.\n *\n * `spec-graph` began by assuming one specification per file, because that is\n * how MADR, KEPs and Rust RFCs are laid out. Plenty of organisations do not\n * work that way. A register, a whitepaper or a living architecture document\n * holds dozens of decisions in one file, each with its own identifier, its own\n * status and its own dependencies - and to an engine that binds a document to a\n * file, every one of them is invisible.\n *\n * The fix is small once stated: **a specification is a region of a file, not a\n * file.** A file yields at least one region - itself - and may yield more.\n * Everything downstream is unchanged, because a region produces exactly the\n * same `DocumentNode` a whole file produced.\n *\n * What this module decides is where those regions begin and end, and it is\n * deliberately hard to convince. A heading has to carry an identifier *and* the\n * section has to declare a status before it counts. One signal is not enough:\n * `## Q3 2026 Roadmap` parses as family `Q`, number 3, and `## v1.2.0` in a\n * changelog parses as family `v`, number 1. Neither is a specification, and\n * neither declares a status.\n */\n\nimport { attr, type Directive } from './directives.js';\nimport { HAS_LETTER_OR_DIGIT, isExternal, parsePrefixedRef } from './identity.js';\nimport { isStatusHeading } from './lifecycle.js';\nimport {\n isMarkdownLine,\n isOnlyComment,\n type Heading,\n type Range,\n type ScannedDocument,\n type Table,\n type TableCell,\n type TableRow,\n} from './markdown.js';\nimport type { EdgeKind } from './types.js';\n\n/** A status as written, and where it was written. */\nexport interface RegionStatus {\n readonly text: string;\n readonly start: number;\n readonly end: number;\n}\n\n/** A relation read from a table column rather than from prose. */\nexport interface TableRelation {\n readonly kind: EdgeKind;\n readonly inverted: boolean;\n readonly target: string;\n readonly start: number;\n readonly end: number;\n /** The column header that gave it its meaning, for the diagnostic. */\n readonly column: string;\n}\n\nexport interface SpecificationRegion {\n /** The heading that opens the region, or `null` for the file or a table row. */\n readonly heading: Heading | null;\n /** The table row that is the region, when it is one. */\n readonly row: TableRow | null;\n /** Offset the region starts at. */\n readonly start: number;\n /** Offset just past the region. */\n readonly end: number;\n /** Identifier read from the heading or the identifier column. */\n readonly declaredId: string | null;\n readonly title: string | null;\n readonly status: RegionStatus | null;\n /** A `@spec-node` directive inside the region, when there is one. */\n readonly directive: Directive | null;\n /** Relations declared by column, empty for a heading region. */\n readonly relations: readonly TableRelation[];\n /**\n * Cells whose content is already accounted for as a typed relation.\n *\n * Prose scanning skips these, so a link in a `Depends on` column produces one\n * typed edge rather than a typed edge and a neutral citation beside it.\n */\n readonly claimed: readonly Range[];\n}\n\n/** Column headers that name the row's identifier. */\nconst ID_COLUMNS = /^(?:id|ids|ref|reference|key|no|number|#|adr|rfc|kep|oi|decision|spec|specification)$/;\n\n/** Column headers that name the row's status. */\nconst STATUS_COLUMNS = /^(?:status|state|stage|lifecycle|phase)$/;\n\n/** Column headers that name the row's title. */\nconst TITLE_COLUMNS = /^(?:title|name|summary|description|subject|decision|topic)$/;\n\n/**\n * Column headers that declare a relation.\n *\n * Written the way a header is written - \"Depends on\", \"Superseded by\" - rather\n * than the way a front-matter key is, because that is what an author types at\n * the top of a column.\n */\nconst RELATION_COLUMNS: Readonly<Record<string, { kind: EdgeKind; inverted: boolean }>> = {\n 'depends on': { kind: 'depends-on', inverted: false },\n 'depends-on': { kind: 'depends-on', inverted: false },\n dependencies: { kind: 'depends-on', inverted: false },\n requires: { kind: 'depends-on', inverted: false },\n supersedes: { kind: 'supersedes', inverted: false },\n replaces: { kind: 'supersedes', inverted: false },\n 'superseded by': { kind: 'supersedes', inverted: true },\n 'replaced by': { kind: 'supersedes', inverted: true },\n 'blocked by': { kind: 'blocked-by', inverted: false },\n 'blocked on': { kind: 'blocked-by', inverted: false },\n blocks: { kind: 'blocked-by', inverted: true },\n amends: { kind: 'amends', inverted: false },\n extends: { kind: 'amends', inverted: false },\n assumes: { kind: 'assumes', inverted: false },\n 'delegates to': { kind: 'delegates-to', inverted: false },\n 'delegated to': { kind: 'delegates-to', inverted: false },\n 'tracked in': { kind: 'delegates-to', inverted: false },\n related: { kind: 'relates-to', inverted: false },\n 'related to': { kind: 'relates-to', inverted: false },\n 'see also': { kind: 'relates-to', inverted: false },\n references: { kind: 'references', inverted: false },\n};\n\n/** Cell values that mean \"nothing here\". */\nconst MARKDOWN_LINK = /!?\\[([^\\]]*)\\]\\(([^)]*)\\)/g;\nconst EMPTY_CELL = /^(?:-+|—|–|n\\/?a|none|nil|tbd|\\.|_+)$/i;\n\n/** `## ADR-0007: Sharding` - an identifier at the very start of a heading. */\nconst HEADING_ID = /^\\s*([A-Za-z]{1,15}[\\s._-]?\\d{1,6})\\b/;\n\n/** `**Status:** Accepted`, `Status: Accepted`, `*Status* : Accepted`, `**狀態:** 已接受`. */\nconst INLINE_STATUS = /^[ \\t>]*[*_]{0,2}\\s*(?:status|狀態|状态)\\s*[*_]{0,2}\\s*[::]\\s*(.+?)\\s*$/im;\n\n/**\n * Finds every specification in a file.\n *\n * The first entry is always the file itself, so a caller that ignores the rest\n * behaves exactly as it did before regions existed.\n */\nexport function findSpecificationRegions(\n scanned: ScannedDocument,\n directives: readonly Directive[],\n /** The file's own identifier, so its title heading is not read as a sub-region. */\n fileId: string,\n): SpecificationRegion[] {\n // The file's own relations come from its front matter and prose, never from\n // here, and it claims no cell: nothing reads either list off this region.\n const whole: SpecificationRegion = {\n heading: null,\n row: null,\n start: scanned.bodyStart,\n end: scanned.text.length,\n declaredId: null,\n title: null,\n status: null,\n directive: null,\n relations: [],\n claimed: [],\n };\n\n const regions: SpecificationRegion[] = [];\n const folded = fold(fileId);\n const fileRef = parsePrefixedRef(fileId);\n\n for (let i = 0; i < scanned.headings.length; i += 1) {\n const heading = scanned.headings[i] as Heading;\n const declaredId = HEADING_ID.exec(heading.text)?.[1];\n if (declaredId === undefined) continue;\n // The file's own title heading names the file, not a region inside it.\n if (fold(declaredId) === folded) continue;\n // Padding is not part of an identity anywhere else - `ADR-40`, `ADR-040`\n // and `ADR-0040` all resolve to one document - so a heading that spells the\n // number differently from the file name is still that file's own title.\n // Comparing the text alone made `# ADR-040` inside `0040-enforce.md` a\n // region within the file it names: one decision, two nodes, and a citation\n // arriving at whichever spelling it happened to use.\n // `HEADING_ID` captures only what `PREFIXED_ID` parses, so `ref` is never\n // null here; the check is for the type.\n const ref = parsePrefixedRef(declaredId);\n if (ref !== null && fileRef !== null && ref.family === fileRef.family && ref.number === fileRef.number) continue;\n\n const end = regionEnd(scanned, i);\n const directive = directiveIn(directives, heading.end, end);\n const status = readRegionStatus(scanned, heading.end, end);\n\n // Two independent signals are required. An identifier alone matches\n // `## Q3 2026 Roadmap` and `## v1.2.0`; a status alone matches every\n // ordinary `## Status` section in a normal ADR.\n if (status === null && directive === null) continue;\n\n // A directive's id wins, but only if it is a name. One that is not - the\n // lone backslash `id=\\\"ADR-9\\\"` parses to, written inside a string - would\n // be discarded when the region is identified, and a region with nothing\n // to go by falls back to the file's own name: the file then contained\n // itself, and the section vanished. The heading's id is the one to keep.\n const directiveId = directive ? attr(directive, 'id')?.value : undefined;\n\n regions.push({\n heading,\n row: null,\n start: heading.start,\n end,\n declaredId: directiveId !== undefined && HAS_LETTER_OR_DIGIT.test(directiveId) ? directiveId : declaredId,\n title: heading.text,\n status,\n directive,\n relations: [],\n // Prose inside a section is prose: a heading region claims no cell.\n claimed: [],\n });\n }\n\n return [whole, ...regions, ...findTableRegions(scanned)];\n}\n\n/* -------------------------------------------------------------------------- */\n/* Registers kept as tables */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Reads a table whose columns describe specifications.\n *\n * A table qualifies when it has an identifier column *and* either a status\n * column or at least one relation column. Two signals again, for the same\n * reason: a table of identifiers and prose is a citation list, and promoting\n * every row of it to a specification would invent a register nobody wrote.\n */\nexport function findTableRegions(scanned: ScannedDocument): SpecificationRegion[] {\n const out: SpecificationRegion[] = [];\n\n for (const table of scanned.tables) {\n const schema = readSchema(table);\n if (schema === null) continue;\n\n for (const row of table.rows) {\n const idCell = row.cells[schema.id];\n if (!idCell) continue;\n const id = flatten(idCell.text);\n // A row is named by its id cell or not at all. An empty one, a\n // placeholder, or punctuation alone - `?` for a row nobody has numbered\n // yet - names nothing, and a region with no name fell back to the file's:\n // the register then contained itself, and the row vanished.\n if (!HAS_LETTER_OR_DIGIT.test(id) || EMPTY_CELL.test(id)) continue;\n\n // `row.cells[null]` is undefined too, so the null checks on the optional\n // columns are for the type; and `statusText` is read only beside a cell.\n const statusCell = schema.status === null ? undefined : row.cells[schema.status];\n const statusText = statusCell ? flatten(statusCell.text) : '';\n const status: RegionStatus | null =\n statusCell && statusText.length > 0 && !EMPTY_CELL.test(statusText)\n ? { text: statusText, start: statusCell.start, end: statusCell.end }\n : null;\n\n const titleCell = schema.title === null ? undefined : row.cells[schema.title];\n const title = titleCell ? flatten(titleCell.text) : null;\n\n const relations: TableRelation[] = [];\n // The status cell is left to prose, as a status line under a heading is:\n // `Superseded by ADR-0002` there names the row's successor, and claimed\n // it named nothing at all.\n const claimed: Range[] = [{ start: idCell.start, end: idCell.end }];\n\n for (const [column, relation] of schema.relations) {\n const cell = row.cells[column];\n if (!cell) continue;\n claimed.push({ start: cell.start, end: cell.end });\n for (const target of splitTargets(cell)) {\n relations.push({\n kind: relation.kind,\n inverted: relation.inverted,\n target: target.text,\n start: target.start,\n end: target.end,\n column: (table.headers[column] as TableCell).text,\n });\n }\n }\n\n out.push({\n heading: null,\n row,\n start: row.start,\n end: row.end,\n declaredId: id,\n title: title !== null && title.length > 0 ? title : null,\n status,\n directive: null,\n relations,\n claimed,\n });\n }\n }\n\n return out;\n}\n\n/**\n * Whether spec-graph reads a table as a register: an identifier column, and a\n * status column or a relation column beside it. Such a table's status column\n * describes its rows, never the document holding it.\n */\nexport function isRegisterTable(table: Table): boolean {\n return readSchema(table) !== null;\n}\n\ninterface TableSchema {\n readonly id: number;\n readonly status: number | null;\n readonly title: number | null;\n readonly relations: readonly (readonly [number, { kind: EdgeKind; inverted: boolean }])[];\n}\n\nfunction readSchema(table: Table): TableSchema | null {\n let id: number | null = null;\n let status: number | null = null;\n let title: number | null = null;\n const relations: [number, { kind: EdgeKind; inverted: boolean }][] = [];\n\n table.headers.forEach((header, column) => {\n const name = normaliseHeader(header.text);\n if (id === null && ID_COLUMNS.test(name)) {\n id = column;\n return;\n }\n if (status === null && STATUS_COLUMNS.test(name)) {\n status = column;\n return;\n }\n const relation = RELATION_COLUMNS[name];\n if (relation) {\n relations.push([column, relation]);\n return;\n }\n if (title === null && TITLE_COLUMNS.test(name)) title = column;\n });\n\n // Without an id column every row would be skipped for want of an id cell;\n // this says so before reading any of them.\n if (id === null) return null;\n if (status === null && relations.length === 0) return null;\n return { id, status, title, relations };\n}\n\nfunction normaliseHeader(text: string): string {\n return flatten(text)\n .toLowerCase()\n .replace(/[^a-z0-9/#\\s-]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/** Splits a cell into the identifiers it lists, keeping each one's offset. */\nfunction splitTargets(cell: TableCell): { text: string; start: number; end: number }[] {\n const out: { text: string; start: number; end: number }[] = [];\n // Every target is reported at the cell's span. A cell is short, and an offset\n // recovered back through a flattening is an offset that can drift.\n const push = (raw: string): void => {\n const target = raw.trim();\n if (target.length === 0 || EMPTY_CELL.test(target)) return;\n out.push({ text: target, start: cell.start, end: cell.end });\n };\n const prose = (segment: string): void => {\n for (const piece of flatten(segment).split(/\\s*(?:[,;]|\\band\\b)\\s*/i)) push(piece);\n };\n\n // Links are taken out whole rather than flattened with everything else: a\n // path would otherwise be cut in half by its own slash, and its underscores\n // stripped as emphasis.\n // A fresh matcher per cell. `prose` calls `flatten`, which drives the shared\n // pattern; one /g regex advanced from inside its own scan resets its cursor\n // and never terminates.\n const links = new RegExp(MARKDOWN_LINK.source, 'g');\n let last = 0;\n for (let match = links.exec(cell.text); match !== null; match = links.exec(cell.text)) {\n prose(cell.text.slice(last, match.index));\n // Both groups always take part in a match, so the `?? ''` below and in the\n // label are for the type.\n const destination = (match[2] ?? '').trim();\n // A link states where its target lives; its label states only what the\n // target is called (ADR-0008). In a column the author has already typed,\n // the destination is the claim - `[see](adr/0050.md)` is a dependency on\n // that file, not on the word \"see\". An external or in-page destination\n // names no document here, so the label is what is left to try.\n const local = destination.length > 0 && !destination.startsWith('#') && !isExternal(destination);\n push(local ? destination : (match[1] ?? ''));\n last = match.index + match[0].length;\n }\n prose(cell.text.slice(last));\n return out;\n}\n\n/** Reduces a cell to its text: link labels rather than link syntax. */\nfunction flatten(text: string): string {\n return text\n .replace(MARKDOWN_LINK, '$1')\n .replace(/\\[\\[(?:[^\\]|]*\\|)?([^\\]]*)\\]\\]/g, '$1')\n .replace(/[`*_~]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/** Where a heading's section ends: the next heading at the same level or above. */\nfunction regionEnd(scanned: ScannedDocument, index: number): number {\n const heading = scanned.headings[index] as Heading;\n for (let i = index + 1; i < scanned.headings.length; i += 1) {\n const next = scanned.headings[i] as Heading;\n if (next.level <= heading.level) return next.start;\n }\n return scanned.text.length;\n}\n\n/**\n * Reads a status declared inside a region.\n *\n * Two forms, both common: a labelled line (`**Status:** Accepted`) and a\n * sub-heading (`### Status` with the value beneath it). Only the region is\n * searched, so one decision in a register cannot inherit its neighbour's.\n */\nexport function readRegionStatus(scanned: ScannedDocument, start: number, end: number): RegionStatus | null {\n const labelled = readLabelledStatus(scanned, start, end);\n if (labelled) return labelled;\n return readHeadedStatus(scanned, start, end);\n}\n\nfunction readLabelledStatus(scanned: ScannedDocument, start: number, end: number): RegionStatus | null {\n for (const line of scanned.lines) {\n if (line.contentStart < start) continue;\n if (line.contentStart >= end) break;\n // A template's commented-out `Status: proposed | accepted` is a hint to\n // whoever fills it in, not a status the region declares, and one in code or\n // a <pre> block is an example.\n if (!isMarkdownLine(line) || line.blank || line.comment) continue;\n const match = INLINE_STATUS.exec(line.content);\n if (!match) continue;\n // `**Status:** Accepted` closes its emphasis *after* the colon, so the\n // closing marker lands in the captured value. Strip it rather than let it\n // reach the report as part of the status a reader is shown.\n const value = (match[1] as string).replace(/^[*_\\s]+/, '').replace(/[*_\\s]+$/, '');\n if (value.length === 0) continue;\n const offset = line.contentStart + line.content.lastIndexOf(value);\n return { text: value, start: offset, end: offset + value.length };\n }\n return null;\n}\n\nfunction readHeadedStatus(scanned: ScannedDocument, start: number, end: number): RegionStatus | null {\n // The upper bound decides nothing on its own: under a heading at or past\n // `end` there is no line before `end`, and the loop below stops there.\n const heading = scanned.headings.find((h) => h.start >= start && h.start < end && isStatusHeading(h.text));\n if (!heading) return null;\n\n for (const line of scanned.lines) {\n if (line.line <= heading.line) continue;\n if (line.contentStart >= end) break;\n if (line.blank || isOnlyComment(scanned, line)) continue;\n if (!isMarkdownLine(line)) return null;\n if (opensHeading(scanned, line.line)) return null;\n const trimmed = line.content.trim();\n // A bullet list under Status is a status history; the first entry is current.\n const cleaned = trimmed.replace(/^[-*+]\\s+/, '');\n const offset = line.contentStart + line.content.indexOf(trimmed) + (trimmed.length - cleaned.length);\n return { text: cleaned, start: offset, end: offset + cleaned.length };\n }\n return null;\n}\n\n/**\n * Whether a heading begins on this line, which ends a status section's search\n * for its value.\n *\n * Asked of the scanner rather than of the line's first character, because a\n * setext heading's text line starts with no `#`: under `### Status` it read as\n * the status, and a register took the next decision's title for its own.\n */\nexport function opensHeading(scanned: ScannedDocument, line: number): boolean {\n return scanned.headings.some((heading) => heading.line === line);\n}\n\n/**\n * The last `@spec-node` directive inside a region: the one written last, which\n * is the one a reader sees as the final word.\n *\n * Directives arrive in the order they were written, so each candidate starts\n * after the one before it and the comparison below only restates that. And\n * `start` is where a heading's line ends, a comment written on it included,\n * so no directive begins exactly there and `<` against `<=` decides nothing.\n */\nfunction directiveIn(directives: readonly Directive[], start: number, end: number): Directive | null {\n let found: Directive | null = null;\n for (const directive of directives) {\n if (directive.name !== 'spec-node') continue;\n if (directive.start < start || directive.end > end) continue;\n if (found === null || directive.start > found.start) found = directive;\n }\n return found;\n}\n\n/**\n * Case- and separator-insensitive comparison, matching reference folding.\n *\n * Applied to both sides of one comparison, so which case it folds to does not\n * matter; the separators take every space with them, so the trim does not\n * either; and `+` only saves work.\n */\nfunction fold(value: string): string {\n return value.trim().toLowerCase().replace(/[\\s._-]+/g, '');\n}\n\n/** The region containing an offset, innermost first. `null` when only the file does. */\nexport function regionAt(regions: readonly SpecificationRegion[], offset: number): SpecificationRegion | null {\n let best: SpecificationRegion | null = null;\n for (const region of regions) {\n // The whole-file region owns nothing in particular; it is the fallback.\n if (region.heading === null && region.row === null) continue;\n if (offset < region.start || offset >= region.end) continue;\n // No two regions of one file open at the same offset, so `>` and `>=`\n // agree here.\n if (best === null || region.start > best.start) best = region;\n }\n return best;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../src/sections.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Specification regions: the part of a file that one specification occupies.\n *\n * `spec-graph` began by assuming one specification per file, because that is\n * how MADR, KEPs and Rust RFCs are laid out. Plenty of organisations do not\n * work that way. A register, a whitepaper or a living architecture document\n * holds dozens of decisions in one file, each with its own identifier, its own\n * status and its own dependencies - and to an engine that binds a document to a\n * file, every one of them is invisible.\n *\n * The fix is small once stated: **a specification is a region of a file, not a\n * file.** A file yields at least one region - itself - and may yield more.\n * Everything downstream is unchanged, because a region produces exactly the\n * same `DocumentNode` a whole file produced.\n *\n * What this module decides is where those regions begin and end, and it is\n * deliberately hard to convince. A heading has to carry an identifier *and* the\n * section has to declare a status before it counts. One signal is not enough:\n * `## Q3 2026 Roadmap` parses as family `Q`, number 3, and `## v1.2.0` in a\n * changelog parses as family `v`, number 1. Neither is a specification, and\n * neither declares a status.\n */\n\nimport { attr, type Directive } from './directives.js';\nimport { HAS_LETTER_OR_DIGIT, isExternal, parsePrefixedRef } from './identity.js';\nimport { isStatusHeading } from './lifecycle.js';\nimport {\n isMarkdownLine,\n isOnlyComment,\n type Heading,\n type Range,\n type ScannedDocument,\n type Table,\n type TableCell,\n type TableRow,\n} from './markdown.js';\nimport type { EdgeKind } from './types.js';\n\n/** A status as written, and where it was written. */\nexport interface RegionStatus {\n readonly text: string;\n readonly start: number;\n readonly end: number;\n}\n\n/** A relation read from a table column rather than from prose. */\nexport interface TableRelation {\n readonly kind: EdgeKind;\n readonly inverted: boolean;\n readonly target: string;\n readonly start: number;\n readonly end: number;\n /** The column header that gave it its meaning, for the diagnostic. */\n readonly column: string;\n}\n\nexport interface SpecificationRegion {\n /** The heading that opens the region, or `null` for the file or a table row. */\n readonly heading: Heading | null;\n /** The table row that is the region, when it is one. */\n readonly row: TableRow | null;\n /** Offset the region starts at. */\n readonly start: number;\n /** Offset just past the region. */\n readonly end: number;\n /** Identifier read from the heading or the identifier column. */\n readonly declaredId: string | null;\n readonly title: string | null;\n readonly status: RegionStatus | null;\n /** A `@spec-node` directive inside the region, when there is one. */\n readonly directive: Directive | null;\n /** Relations declared by column, empty for a heading region. */\n readonly relations: readonly TableRelation[];\n /**\n * Cells whose content is already accounted for as a typed relation.\n *\n * Prose scanning skips these, so a link in a `Depends on` column produces one\n * typed edge rather than a typed edge and a neutral citation beside it.\n */\n readonly claimed: readonly Range[];\n}\n\n/** Column headers that name the row's identifier. */\nconst ID_COLUMNS = /^(?:id|ids|ref|reference|key|no|number|#|adr|rfc|kep|oi|decision|spec|specification)$/;\n\n/** Column headers that name the row's status. */\nconst STATUS_COLUMNS = /^(?:status|state|stage|lifecycle|phase)$/;\n\n/** Column headers that name the row's title. */\nconst TITLE_COLUMNS = /^(?:title|name|summary|description|subject|decision|topic)$/;\n\n/**\n * Column headers that declare a relation.\n *\n * Written the way a header is written - \"Depends on\", \"Superseded by\" - rather\n * than the way a front-matter key is, because that is what an author types at\n * the top of a column.\n */\nconst RELATION_COLUMNS: Readonly<Record<string, { kind: EdgeKind; inverted: boolean }>> = {\n 'depends on': { kind: 'depends-on', inverted: false },\n 'depends-on': { kind: 'depends-on', inverted: false },\n dependencies: { kind: 'depends-on', inverted: false },\n requires: { kind: 'depends-on', inverted: false },\n supersedes: { kind: 'supersedes', inverted: false },\n replaces: { kind: 'supersedes', inverted: false },\n 'superseded by': { kind: 'supersedes', inverted: true },\n 'replaced by': { kind: 'supersedes', inverted: true },\n 'blocked by': { kind: 'blocked-by', inverted: false },\n 'blocked on': { kind: 'blocked-by', inverted: false },\n blocks: { kind: 'blocked-by', inverted: true },\n amends: { kind: 'amends', inverted: false },\n extends: { kind: 'amends', inverted: false },\n assumes: { kind: 'assumes', inverted: false },\n 'delegates to': { kind: 'delegates-to', inverted: false },\n 'delegated to': { kind: 'delegates-to', inverted: false },\n 'tracked in': { kind: 'delegates-to', inverted: false },\n related: { kind: 'relates-to', inverted: false },\n 'related to': { kind: 'relates-to', inverted: false },\n 'see also': { kind: 'relates-to', inverted: false },\n references: { kind: 'references', inverted: false },\n};\n\n/** Cell values that mean \"nothing here\". */\nconst MARKDOWN_LINK = /!?\\[([^\\]]*)\\]\\(([^)]*)\\)/g;\nconst EMPTY_CELL = /^(?:-+|—|–|n\\/?a|none|nil|tbd|\\.|_+)$/i;\n\n/** `## ADR-0007: Sharding` - an identifier at the very start of a heading. */\nconst HEADING_ID = /^\\s*([A-Za-z]{1,15}[\\s._-]?\\d{1,6})\\b/;\n\n/** `**Status:** Accepted`, `Status: Accepted`, `*Status* : Accepted`. */\nconst INLINE_STATUS = /^[ \\t>]*[*_]{0,2}\\s*status\\s*[*_]{0,2}\\s*:\\s*(.+?)\\s*$/im;\n\n/**\n * Finds every specification in a file.\n *\n * The first entry is always the file itself, so a caller that ignores the rest\n * behaves exactly as it did before regions existed.\n */\nexport function findSpecificationRegions(\n scanned: ScannedDocument,\n directives: readonly Directive[],\n /** The file's own identifier, so its title heading is not read as a sub-region. */\n fileId: string,\n): SpecificationRegion[] {\n // The file's own relations come from its front matter and prose, never from\n // here, and it claims no cell: nothing reads either list off this region.\n const whole: SpecificationRegion = {\n heading: null,\n row: null,\n start: scanned.bodyStart,\n end: scanned.text.length,\n declaredId: null,\n title: null,\n status: null,\n directive: null,\n relations: [],\n claimed: [],\n };\n\n const regions: SpecificationRegion[] = [];\n const folded = fold(fileId);\n const fileRef = parsePrefixedRef(fileId);\n\n for (let i = 0; i < scanned.headings.length; i += 1) {\n const heading = scanned.headings[i] as Heading;\n const declaredId = HEADING_ID.exec(heading.text)?.[1];\n if (declaredId === undefined) continue;\n // The file's own title heading names the file, not a region inside it.\n if (fold(declaredId) === folded) continue;\n // Padding is not part of an identity anywhere else - `ADR-40`, `ADR-040`\n // and `ADR-0040` all resolve to one document - so a heading that spells the\n // number differently from the file name is still that file's own title.\n // Comparing the text alone made `# ADR-040` inside `0040-enforce.md` a\n // region within the file it names: one decision, two nodes, and a citation\n // arriving at whichever spelling it happened to use.\n // `HEADING_ID` captures only what `PREFIXED_ID` parses, so `ref` is never\n // null here; the check is for the type.\n const ref = parsePrefixedRef(declaredId);\n if (ref !== null && fileRef !== null && ref.family === fileRef.family && ref.number === fileRef.number) continue;\n\n const end = regionEnd(scanned, i);\n const directive = directiveIn(directives, heading.end, end);\n const status = readRegionStatus(scanned, heading.end, end);\n\n // Two independent signals are required. An identifier alone matches\n // `## Q3 2026 Roadmap` and `## v1.2.0`; a status alone matches every\n // ordinary `## Status` section in a normal ADR.\n if (status === null && directive === null) continue;\n\n // A directive's id wins, but only if it is a name. One that is not - the\n // lone backslash `id=\\\"ADR-9\\\"` parses to, written inside a string - would\n // be discarded when the region is identified, and a region with nothing\n // to go by falls back to the file's own name: the file then contained\n // itself, and the section vanished. The heading's id is the one to keep.\n const directiveId = directive ? attr(directive, 'id')?.value : undefined;\n\n regions.push({\n heading,\n row: null,\n start: heading.start,\n end,\n declaredId: directiveId !== undefined && HAS_LETTER_OR_DIGIT.test(directiveId) ? directiveId : declaredId,\n title: heading.text,\n status,\n directive,\n relations: [],\n // Prose inside a section is prose: a heading region claims no cell.\n claimed: [],\n });\n }\n\n return [whole, ...regions, ...findTableRegions(scanned)];\n}\n\n/* -------------------------------------------------------------------------- */\n/* Registers kept as tables */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Reads a table whose columns describe specifications.\n *\n * A table qualifies when it has an identifier column *and* either a status\n * column or at least one relation column. Two signals again, for the same\n * reason: a table of identifiers and prose is a citation list, and promoting\n * every row of it to a specification would invent a register nobody wrote.\n */\nexport function findTableRegions(scanned: ScannedDocument): SpecificationRegion[] {\n const out: SpecificationRegion[] = [];\n\n for (const table of scanned.tables) {\n const schema = readSchema(table);\n if (schema === null) continue;\n\n for (const row of table.rows) {\n const idCell = row.cells[schema.id];\n if (!idCell) continue;\n const id = flatten(idCell.text);\n // A row is named by its id cell or not at all. An empty one, a\n // placeholder, or punctuation alone - `?` for a row nobody has numbered\n // yet - names nothing, and a region with no name fell back to the file's:\n // the register then contained itself, and the row vanished.\n if (!HAS_LETTER_OR_DIGIT.test(id) || EMPTY_CELL.test(id)) continue;\n\n // `row.cells[null]` is undefined too, so the null checks on the optional\n // columns are for the type; and `statusText` is read only beside a cell.\n const statusCell = schema.status === null ? undefined : row.cells[schema.status];\n const statusText = statusCell ? flatten(statusCell.text) : '';\n const status: RegionStatus | null =\n statusCell && statusText.length > 0 && !EMPTY_CELL.test(statusText)\n ? { text: statusText, start: statusCell.start, end: statusCell.end }\n : null;\n\n const titleCell = schema.title === null ? undefined : row.cells[schema.title];\n const title = titleCell ? flatten(titleCell.text) : null;\n\n const relations: TableRelation[] = [];\n // The status cell is left to prose, as a status line under a heading is:\n // `Superseded by ADR-0002` there names the row's successor, and claimed\n // it named nothing at all.\n const claimed: Range[] = [{ start: idCell.start, end: idCell.end }];\n\n for (const [column, relation] of schema.relations) {\n const cell = row.cells[column];\n if (!cell) continue;\n claimed.push({ start: cell.start, end: cell.end });\n for (const target of splitTargets(cell)) {\n relations.push({\n kind: relation.kind,\n inverted: relation.inverted,\n target: target.text,\n start: target.start,\n end: target.end,\n column: (table.headers[column] as TableCell).text,\n });\n }\n }\n\n out.push({\n heading: null,\n row,\n start: row.start,\n end: row.end,\n declaredId: id,\n title: title !== null && title.length > 0 ? title : null,\n status,\n directive: null,\n relations,\n claimed,\n });\n }\n }\n\n return out;\n}\n\n/**\n * Whether spec-graph reads a table as a register: an identifier column, and a\n * status column or a relation column beside it. Such a table's status column\n * describes its rows, never the document holding it.\n */\nexport function isRegisterTable(table: Table): boolean {\n return readSchema(table) !== null;\n}\n\ninterface TableSchema {\n readonly id: number;\n readonly status: number | null;\n readonly title: number | null;\n readonly relations: readonly (readonly [number, { kind: EdgeKind; inverted: boolean }])[];\n}\n\nfunction readSchema(table: Table): TableSchema | null {\n let id: number | null = null;\n let status: number | null = null;\n let title: number | null = null;\n const relations: [number, { kind: EdgeKind; inverted: boolean }][] = [];\n\n table.headers.forEach((header, column) => {\n const name = normaliseHeader(header.text);\n if (id === null && ID_COLUMNS.test(name)) {\n id = column;\n return;\n }\n if (status === null && STATUS_COLUMNS.test(name)) {\n status = column;\n return;\n }\n const relation = RELATION_COLUMNS[name];\n if (relation) {\n relations.push([column, relation]);\n return;\n }\n if (title === null && TITLE_COLUMNS.test(name)) title = column;\n });\n\n // Without an id column every row would be skipped for want of an id cell;\n // this says so before reading any of them.\n if (id === null) return null;\n if (status === null && relations.length === 0) return null;\n return { id, status, title, relations };\n}\n\nfunction normaliseHeader(text: string): string {\n return flatten(text)\n .toLowerCase()\n .replace(/[^a-z0-9/#\\s-]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/** Splits a cell into the identifiers it lists, keeping each one's offset. */\nfunction splitTargets(cell: TableCell): { text: string; start: number; end: number }[] {\n const out: { text: string; start: number; end: number }[] = [];\n // Every target is reported at the cell's span. A cell is short, and an offset\n // recovered back through a flattening is an offset that can drift.\n const push = (raw: string): void => {\n const target = raw.trim();\n if (target.length === 0 || EMPTY_CELL.test(target)) return;\n out.push({ text: target, start: cell.start, end: cell.end });\n };\n const prose = (segment: string): void => {\n for (const piece of flatten(segment).split(/\\s*(?:[,;]|\\band\\b)\\s*/i)) push(piece);\n };\n\n // Links are taken out whole rather than flattened with everything else: a\n // path would otherwise be cut in half by its own slash, and its underscores\n // stripped as emphasis.\n // `matchAll` scans a copy of the pattern. `prose` calls `flatten`, which\n // drives the shared one, and one /g regex advanced from inside its own scan\n // resets its cursor and never terminates.\n let last = 0;\n for (const match of cell.text.matchAll(MARKDOWN_LINK)) {\n prose(cell.text.slice(last, match.index));\n // Both groups always take part in a match, so the `?? ''` below and in the\n // label are for the type.\n const destination = (match[2] ?? '').trim();\n // A link states where its target lives; its label states only what the\n // target is called (ADR-0008). In a column the author has already typed,\n // the destination is the claim - `[see](adr/0050.md)` is a dependency on\n // that file, not on the word \"see\". An external or in-page destination\n // names no document here, so the label is what is left to try.\n const local = destination.length > 0 && !destination.startsWith('#') && !isExternal(destination);\n push(local ? destination : (match[1] ?? ''));\n last = match.index + match[0].length;\n }\n prose(cell.text.slice(last));\n return out;\n}\n\n/** Reduces a cell to its text: link labels rather than link syntax. */\nfunction flatten(text: string): string {\n return text\n .replace(MARKDOWN_LINK, '$1')\n .replace(/\\[\\[(?:[^\\]|]*\\|)?([^\\]]*)\\]\\]/g, '$1')\n .replace(/[`*_~]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/** Where a heading's section ends: the next heading at the same level or above. */\nfunction regionEnd(scanned: ScannedDocument, index: number): number {\n const heading = scanned.headings[index] as Heading;\n for (let i = index + 1; i < scanned.headings.length; i += 1) {\n const next = scanned.headings[i] as Heading;\n if (next.level <= heading.level) return next.start;\n }\n return scanned.text.length;\n}\n\n/**\n * Reads a status declared inside a region.\n *\n * Two forms, both common: a labelled line (`**Status:** Accepted`) and a\n * sub-heading (`### Status` with the value beneath it). Only the region is\n * searched, so one decision in a register cannot inherit its neighbour's.\n */\nexport function readRegionStatus(scanned: ScannedDocument, start: number, end: number): RegionStatus | null {\n const labelled = readLabelledStatus(scanned, start, end);\n if (labelled) return labelled;\n return readHeadedStatus(scanned, start, end);\n}\n\nfunction readLabelledStatus(scanned: ScannedDocument, start: number, end: number): RegionStatus | null {\n for (const line of scanned.lines) {\n if (line.contentStart < start) continue;\n if (line.contentStart >= end) break;\n // A template's commented-out `Status: proposed | accepted` is a hint to\n // whoever fills it in, not a status the region declares, and one in code or\n // a <pre> block is an example.\n if (!isMarkdownLine(line) || line.blank || line.comment) continue;\n const match = INLINE_STATUS.exec(line.content);\n if (!match) continue;\n // `**Status:** Accepted` closes its emphasis *after* the colon, so the\n // closing marker lands in the captured value. Strip it rather than let it\n // reach the report as part of the status a reader is shown.\n const value = (match[1] as string).replace(/^[*_\\s]+/, '').replace(/[*_\\s]+$/, '');\n if (value.length === 0) continue;\n const offset = line.contentStart + line.content.lastIndexOf(value);\n return { text: value, start: offset, end: offset + value.length };\n }\n return null;\n}\n\nfunction readHeadedStatus(scanned: ScannedDocument, start: number, end: number): RegionStatus | null {\n // The upper bound decides nothing on its own: under a heading at or past\n // `end` there is no line before `end`, and the loop below stops there.\n const heading = scanned.headings.find((h) => h.start >= start && h.start < end && isStatusHeading(h.text));\n if (!heading) return null;\n\n for (const line of scanned.lines) {\n if (line.line <= heading.line) continue;\n if (line.contentStart >= end) break;\n if (line.blank || isOnlyComment(scanned, line)) continue;\n if (!isMarkdownLine(line)) return null;\n if (opensHeading(scanned, line.line)) return null;\n const trimmed = line.content.trim();\n // A bullet list under Status is a status history; the first entry is current.\n const cleaned = trimmed.replace(/^[-*+]\\s+/, '');\n const offset = line.contentStart + line.content.indexOf(trimmed) + (trimmed.length - cleaned.length);\n return { text: cleaned, start: offset, end: offset + cleaned.length };\n }\n return null;\n}\n\n/**\n * Whether a heading begins on this line, which ends a status section's search\n * for its value.\n *\n * Asked of the scanner rather than of the line's first character, because a\n * setext heading's text line starts with no `#`: under `### Status` it read as\n * the status, and a register took the next decision's title for its own.\n */\nexport function opensHeading(scanned: ScannedDocument, line: number): boolean {\n return scanned.headings.some((heading) => heading.line === line);\n}\n\n/**\n * The last `@spec-node` directive inside a region: the one written last, which\n * is the one a reader sees as the final word.\n *\n * Directives arrive in the order they were written, so each candidate starts\n * after the one before it and the comparison below only restates that. And\n * `start` is where a heading's line ends, a comment written on it included,\n * so no directive begins exactly there and `<` against `<=` decides nothing.\n */\nfunction directiveIn(directives: readonly Directive[], start: number, end: number): Directive | null {\n let found: Directive | null = null;\n for (const directive of directives) {\n if (directive.name !== 'spec-node') continue;\n if (directive.start < start || directive.end > end) continue;\n if (found === null || directive.start > found.start) found = directive;\n }\n return found;\n}\n\n/**\n * Case- and separator-insensitive comparison, matching reference folding.\n *\n * Applied to both sides of one comparison, so which case it folds to does not\n * matter; the separators take every space with them, so the trim does not\n * either; and `+` only saves work.\n */\nfunction fold(value: string): string {\n return value.trim().toLowerCase().replace(/[\\s._-]+/g, '');\n}\n\n/** The region containing an offset, innermost first. `null` when only the file does. */\nexport function regionAt(regions: readonly SpecificationRegion[], offset: number): SpecificationRegion | null {\n let best: SpecificationRegion | null = null;\n for (const region of regions) {\n // The whole-file region owns nothing in particular; it is the fallback.\n if (region.heading === null && region.row === null) continue;\n if (offset < region.start || offset >= region.end) continue;\n // No two regions of one file open at the same offset, so `>` and `>=`\n // agree here.\n if (best === null || region.start > best.start) best = region;\n }\n return best;\n}\n"]}
|
package/dist/state.d.ts
CHANGED
|
@@ -41,5 +41,17 @@ export interface ResolvedState {
|
|
|
41
41
|
}
|
|
42
42
|
/** Collects every state signal on an item and decides between them. */
|
|
43
43
|
export declare function resolveItemState(input: StateInput): ResolvedState;
|
|
44
|
+
/**
|
|
45
|
+
* `exec` from past where the last match began.
|
|
46
|
+
*
|
|
47
|
+
* The other scans over a /g pattern use `matchAll`, which steps past an empty
|
|
48
|
+
* match. This one cannot: it resumes inside its match, on the stop a marker's
|
|
49
|
+
* qualifier took, so that the stop can start the next statement. No marker is
|
|
50
|
+
* empty, so no match is, and the resume is always past where its match began.
|
|
51
|
+
* A marker emptied by mistake would match empty at the start of every line,
|
|
52
|
+
* and `exec` would find it there for ever; this steps past it, and the marker
|
|
53
|
+
* tests fail instead.
|
|
54
|
+
*/
|
|
55
|
+
export declare function execPast(pattern: RegExp, text: string, index: number): RegExpExecArray | null;
|
|
44
56
|
/** Exposed for the query language, which lets users filter on these names. */
|
|
45
57
|
export declare const KNOWN_STATE_WORDS: readonly string[];
|