@jterrazz/typescript 9.2.0 → 9.2.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/package.json +1 -1
- package/src/docs.js +20 -9
- package/src/docs.test.ts +57 -5
package/package.json
CHANGED
package/src/docs.js
CHANGED
|
@@ -48,8 +48,14 @@ const JOURNAL_WORDS = new Set([
|
|
|
48
48
|
/** The closed status vocabulary of a decision record. */
|
|
49
49
|
const STATUSES = new Set(['Proposed', 'Accepted', 'Deprecated']);
|
|
50
50
|
|
|
51
|
-
/**
|
|
52
|
-
|
|
51
|
+
/**
|
|
52
|
+
* The fourth status carries the record that replaced it, as a link a reader
|
|
53
|
+
* can follow — a citation is a place a human can look, not just a number.
|
|
54
|
+
*/
|
|
55
|
+
const SUPERSEDED = /^Superseded by \[ADR-\d{3}\]\([^)]+\)$/;
|
|
56
|
+
|
|
57
|
+
/** The same status named but not linked — the successor exists, the citation does not. */
|
|
58
|
+
const BARE_SUPERSEDED = /^Superseded by ADR-\d{3}$/;
|
|
53
59
|
|
|
54
60
|
/** What a chapter's file name must be: two digits, lowercase words, single hyphens. */
|
|
55
61
|
const CHAPTER_NAME = /^\d{2}-[a-z\d]+(?:-[a-z\d]+)*\.md$/;
|
|
@@ -193,12 +199,17 @@ function auditChapters(report, { chapters, ships }) {
|
|
|
193
199
|
}
|
|
194
200
|
|
|
195
201
|
const numbers = chapters.map((chapter) => chapter.number).sort((a, b) => a - b);
|
|
196
|
-
const
|
|
202
|
+
const hasOperating = numbers.includes(4);
|
|
203
|
+
// 04 is the one number the spine never requires (`docs-operating-missing`
|
|
204
|
+
// Asks for it on its own terms), so a run missing it is still contiguous —
|
|
205
|
+
// Every number from 05 on shifts down one slot to close the gap.
|
|
206
|
+
const expected = (index) => (!hasOperating && index + 1 >= 4 ? index + 2 : index + 1);
|
|
207
|
+
const contiguous = numbers.every((number, index) => number === expected(index));
|
|
197
208
|
if (numbers.length > 0 && !contiguous) {
|
|
198
209
|
report(
|
|
199
210
|
'docs-chapter-numbering',
|
|
200
211
|
'docs/',
|
|
201
|
-
`chapter numbers run ${numbers.map(padded).join(', ')}: they are contiguous from 01, one file per number`,
|
|
212
|
+
`chapter numbers run ${numbers.map(padded).join(', ')}: they are contiguous from 01, one file per number, except that 04 may be absent`,
|
|
202
213
|
);
|
|
203
214
|
}
|
|
204
215
|
|
|
@@ -284,11 +295,11 @@ function auditRecord(report, record, heads) {
|
|
|
284
295
|
|
|
285
296
|
const status = head.map((line) => DECISION_STATUS.exec(line)?.groups?.status).find(Boolean);
|
|
286
297
|
if (status === undefined || !(STATUSES.has(status) || SUPERSEDED.test(status))) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
);
|
|
298
|
+
const message =
|
|
299
|
+
status !== undefined && BARE_SUPERSEDED.test(status)
|
|
300
|
+
? `${record.path}: **Status:** names a successor but no link — write Superseded by [ADR-NNN](file.md)`
|
|
301
|
+
: `${record.path}: **Status:** is none of Proposed, Accepted, Superseded by [ADR-NNN](file.md), Deprecated`;
|
|
302
|
+
report('docs-decision-status', record.path, message);
|
|
292
303
|
}
|
|
293
304
|
}
|
|
294
305
|
|
package/src/docs.test.ts
CHANGED
|
@@ -154,7 +154,7 @@ test('names chapter numbers that skip, and numbers claimed twice', () => {
|
|
|
154
154
|
|
|
155
155
|
// Then - one sentence about the whole run
|
|
156
156
|
expect(sentence(tree, 'docs-chapter-numbering')).toBe(
|
|
157
|
-
'chapter numbers run 01, 02, 03, 05, 05: they are contiguous from 01, one file per number',
|
|
157
|
+
'chapter numbers run 01, 02, 03, 05, 05: they are contiguous from 01, one file per number, except that 04 may be absent',
|
|
158
158
|
);
|
|
159
159
|
});
|
|
160
160
|
|
|
@@ -211,6 +211,40 @@ test('never asks for 04-operating.md from a repository that ships nothing', () =
|
|
|
211
211
|
expect(rules(manual())).toEqual([]);
|
|
212
212
|
});
|
|
213
213
|
|
|
214
|
+
test('lets 05 follow 03 directly when the repository ships nothing', () => {
|
|
215
|
+
// Given - 01-03 then 05, no 04 chapter, nothing that would ask for one
|
|
216
|
+
const tree = manual({
|
|
217
|
+
files: [...manual().files, 'docs/05-building.md'],
|
|
218
|
+
links: { 'docs/README.md': [...manual().links['docs/README.md'], '05-building.md'] },
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Then - 04 is the one gap the numbering excuses
|
|
222
|
+
expect(rules(tree)).toEqual([]);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('still asks for 04-operating.md from that same shape once it ships', () => {
|
|
226
|
+
// Given - the same 01-03 + 05 shape, but an image this time
|
|
227
|
+
const tree = manual({
|
|
228
|
+
files: [...manual().files, 'docs/05-building.md'],
|
|
229
|
+
links: { 'docs/README.md': [...manual().links['docs/README.md'], '05-building.md'] },
|
|
230
|
+
ships: { dockerfile: true, infrastructure: false, publishable: false },
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Then - the numbering stays clean; only the presence test speaks
|
|
234
|
+
expect(rules(tree)).toEqual(['docs-operating-missing']);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test('refuses a gap at 05 even though 04 may be absent', () => {
|
|
238
|
+
// Given - 01-03 then 06, skipping past the one number the spine excuses
|
|
239
|
+
const tree = manual({
|
|
240
|
+
files: [...manual().files, 'docs/06-quality-checks.md'],
|
|
241
|
+
links: { 'docs/README.md': [...manual().links['docs/README.md'], '06-quality-checks.md'] },
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Then - only 04 is excused; 05 still has to be there
|
|
245
|
+
expect(rules(tree)).toEqual(['docs-chapter-numbering']);
|
|
246
|
+
});
|
|
247
|
+
|
|
214
248
|
test('names a chapter that is a journal, not a subject', () => {
|
|
215
249
|
// Given - a fourth chapter recording a design exploration
|
|
216
250
|
const tree = manual({
|
|
@@ -332,18 +366,18 @@ test('names a decision outside the status vocabulary', () => {
|
|
|
332
366
|
|
|
333
367
|
// Then - the four the vocabulary holds
|
|
334
368
|
expect(sentence(tree, 'docs-decision-status')).toBe(
|
|
335
|
-
'docs/decisions/001-the-first-call.md: **Status:** is none of Proposed, Accepted, Superseded by ADR-NNN, Deprecated',
|
|
369
|
+
'docs/decisions/001-the-first-call.md: **Status:** is none of Proposed, Accepted, Superseded by [ADR-NNN](file.md), Deprecated',
|
|
336
370
|
);
|
|
337
371
|
});
|
|
338
372
|
|
|
339
|
-
test('accepts a superseded status that
|
|
340
|
-
// Given - the one status carrying an argument
|
|
373
|
+
test('accepts a superseded status that links the record replacing it', () => {
|
|
374
|
+
// Given - the one status carrying an argument, written as a citation
|
|
341
375
|
const tree = withDecisions({
|
|
342
376
|
heads: {
|
|
343
377
|
'docs/decisions/001-the-first-call.md': [
|
|
344
378
|
'# ADR-001: The first call',
|
|
345
379
|
'',
|
|
346
|
-
'**Status:** Superseded by ADR-014',
|
|
380
|
+
'**Status:** Superseded by [ADR-014](014-the-later-call.md)',
|
|
347
381
|
],
|
|
348
382
|
},
|
|
349
383
|
});
|
|
@@ -352,6 +386,24 @@ test('accepts a superseded status that names the record replacing it', () => {
|
|
|
352
386
|
expect(rules(tree)).toEqual([]);
|
|
353
387
|
});
|
|
354
388
|
|
|
389
|
+
test('refuses a superseded status with no link naming the successor', () => {
|
|
390
|
+
// Given - the bare form: a successor is named, but not as a place to look
|
|
391
|
+
const tree = withDecisions({
|
|
392
|
+
heads: {
|
|
393
|
+
'docs/decisions/001-the-first-call.md': [
|
|
394
|
+
'# ADR-001: The first call',
|
|
395
|
+
'',
|
|
396
|
+
'**Status:** Superseded by ADR-014',
|
|
397
|
+
],
|
|
398
|
+
},
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Then - the missing link is the whole complaint
|
|
402
|
+
expect(sentence(tree, 'docs-decision-status')).toBe(
|
|
403
|
+
'docs/decisions/001-the-first-call.md: **Status:** names a successor but no link — write Superseded by [ADR-NNN](file.md)',
|
|
404
|
+
);
|
|
405
|
+
});
|
|
406
|
+
|
|
355
407
|
test('names a number two records claim', () => {
|
|
356
408
|
// Given - two records numbered 001
|
|
357
409
|
const tree = withDecisions({
|