@descent-vtt/spec-brief 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/README.md +56 -6
- package/dist/archive.js.map +1 -1
- package/dist/brief.js.map +1 -1
- package/dist/cli.d.ts +18 -1
- package/dist/cli.js +273 -55
- package/dist/cli.js.map +1 -1
- package/dist/config.js +3 -2
- package/dist/config.js.map +1 -1
- package/dist/corpus.js +1 -0
- package/dist/corpus.js.map +1 -1
- package/dist/engine.d.ts +43 -0
- package/dist/engine.js +74 -12
- package/dist/engine.js.map +1 -1
- package/dist/fs.d.ts +15 -1
- package/dist/fs.js +21 -8
- package/dist/fs.js.map +1 -1
- package/dist/git.d.ts +11 -0
- package/dist/git.js +38 -4
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lint.js.map +1 -1
- package/dist/literal.d.ts +11 -0
- package/dist/literal.js +14 -0
- package/dist/literal.js.map +1 -0
- package/dist/markdown.js.map +1 -1
- package/dist/plugins.js +2 -0
- package/dist/plugins.js.map +1 -1
- package/dist/report.js +3 -2
- package/dist/report.js.map +1 -1
- package/dist/rules.js +2 -1
- package/dist/rules.js.map +1 -1
- package/dist/schedule.js.map +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/scope.js.map +1 -1
- package/dist/text.js.map +1 -1
- package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -1
- package/dist/vendor/spec-core/markdown/headings.js.map +1 -1
- package/dist/vendor/spec-core/markdown/links.js.map +1 -1
- package/dist/vendor/spec-core/markdown/scan.js.map +1 -1
- package/dist/vendor/spec-core/pattern/automaton.js.map +1 -1
- package/dist/vendor/spec-core/pattern/charset.js.map +1 -1
- package/dist/vendor/spec-core/pattern/regex.js.map +1 -1
- package/dist/vendor/spec-core/text/lines.js.map +1 -1
- package/dist/vendor/spec-core/text/width.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,108 @@ release that can turn a run red. This is the family's policy, recorded in
|
|
|
11
11
|
releases up to 0.2.7 came before it, and several of their patches changed
|
|
12
12
|
what a run reports.
|
|
13
13
|
|
|
14
|
+
## 0.10.0
|
|
15
|
+
|
|
16
|
+
One value written two ways is taken once in three more cases, each of
|
|
17
|
+
which was refused as two values: a drive letter in either case on
|
|
18
|
+
Windows, two revisions git says name one commit, and two lists that name
|
|
19
|
+
the same briefs. Nothing that ran is refused.
|
|
20
|
+
|
|
21
|
+
`list --format json` names what its answer was read from, so that another
|
|
22
|
+
tool can give the answer again without starting spec-brief. A
|
|
23
|
+
configuration that is not a file is refused, exit 2, where a named pipe
|
|
24
|
+
under its name was read without end.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **A drive letter names its volume in either case.** On Windows
|
|
29
|
+
`--root C:\x` beside `--root c:\x`, and two `--config` values the same
|
|
30
|
+
way, were refused as two directories; each is taken once. The rest of a
|
|
31
|
+
path is compared as it resolves, so `C:\x` beside `C:\X` is still two
|
|
32
|
+
([An option given two values](README.md#an-option-given-two-values);
|
|
33
|
+
[the family contract](https://github.com/DescentVTT/spec-core/blob/main/docs/adr/0005-the-family-contract.md),
|
|
34
|
+
amended 2026-10-19).
|
|
35
|
+
- **A revision written two ways is asked of git.** `--commit HEAD` beside
|
|
36
|
+
the hash it names, or `--base main` beside the commit `main` is at, was
|
|
37
|
+
refused as two values. `archive` now asks git once what commit each
|
|
38
|
+
names, and takes two that name one as one. Two that name two commits,
|
|
39
|
+
one git cannot name, and any line with `--no-git`, `--help` or
|
|
40
|
+
`--version`, none of which asks git, are refused as they were
|
|
41
|
+
(ADR-0001, amended 2026-10-19).
|
|
42
|
+
- **`--depends-on` is read as the set of ids it names**, each as a brief's
|
|
43
|
+
id is matched: `7,8` beside `8,7`, `7` beside `007` and `7,8` beside
|
|
44
|
+
`7,8,7` are taken once, and the brief is written with the later as
|
|
45
|
+
given. A list that names another brief, or one fewer, is still two
|
|
46
|
+
values.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **`list --format json` names its inputs**, in a field `inputs`: each
|
|
51
|
+
file the answer was read from, with the SHA-256 of its bytes; each name a
|
|
52
|
+
configuration was looked for under and was not there, with `null`; each
|
|
53
|
+
directory the briefs were listed from, with the files in it, or `null`
|
|
54
|
+
where there was none, as an archive not yet made; and the version that
|
|
55
|
+
read them. `keep` is `false`, and nothing is listed, wherever that
|
|
56
|
+
cannot be named whole: a run that starts below its configuration's
|
|
57
|
+
directory, and one with no configuration file
|
|
58
|
+
([`spec-brief list`](README.md#spec-brief-list); ADR-0002, amended
|
|
59
|
+
2026-10-19). `schemaVersion` stays 2, since a field is added and none
|
|
60
|
+
changes. `list` asks git nothing where a configuration file names the
|
|
61
|
+
root, which is a process fewer.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **A configuration that is not a file is refused.** A named pipe at
|
|
66
|
+
`.spec-brief.json` or `spec-brief.json`, or named by `--config`, was read
|
|
67
|
+
without end by every command; a socket ended the run on `ENXIO` and a
|
|
68
|
+
stack, and `--config /dev/zero` on `RangeError`. Each is now exit 2 with
|
|
69
|
+
one line, `is neither a file nor a directory, not a configuration file`,
|
|
70
|
+
before it is opened, as a directory was already. A link is read as what
|
|
71
|
+
it names ([An input that names nothing](README.md#an-input-that-names-nothing);
|
|
72
|
+
ADR-0003, amended 2026-10-19). Upgrading: nothing to change for a
|
|
73
|
+
configuration that is a file; `--config <(...)`, which a shell hands as a
|
|
74
|
+
pipe, ran in `/dev/fd` and found no briefs, and now says what it was
|
|
75
|
+
handed.
|
|
76
|
+
|
|
77
|
+
## 0.9.0
|
|
78
|
+
|
|
79
|
+
An option that takes one value and is given two is refused, exit 2, where
|
|
80
|
+
the later was read and the earlier went unread. A line refused for what it
|
|
81
|
+
holds is refused with `--help` or `--version` on it, and `--help` beside
|
|
82
|
+
`--version` is refused.
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
|
|
86
|
+
- **An option that takes one value, given two, is refused.**
|
|
87
|
+
`list --root nowhere --root .` listed `.`, and
|
|
88
|
+
`lint --format json --format pretty` printed `pretty`, each exit 0 with
|
|
89
|
+
the earlier never read. Each is now exit 2 with a line that names both as
|
|
90
|
+
they were written, and writes nothing. Two values are compared as each is
|
|
91
|
+
read, so one value written two ways is taken once: `--root .` beside
|
|
92
|
+
`--root ./`, `--wave 1` beside `--wave 01`
|
|
93
|
+
([An option given two values](README.md#an-option-given-two-values);
|
|
94
|
+
[the family contract](https://github.com/DescentVTT/spec-core/blob/main/docs/adr/0005-the-family-contract.md),
|
|
95
|
+
amended 2026-10-18). Upgrading: give each option once; a shell alias or
|
|
96
|
+
a script that gives an option, and a line that gives it again to override
|
|
97
|
+
it, now stops there.
|
|
98
|
+
- **A wrong line is refused with `--help` or `--version` on it.**
|
|
99
|
+
`init --strict --help`, `lint --color --no-color -h`,
|
|
100
|
+
`list --format sarif --version`, `new T --wave two --help` and every
|
|
101
|
+
other line refused for what it holds printed the help or the version,
|
|
102
|
+
exit 0; only an option, a command or an argument spec-brief does not take,
|
|
103
|
+
and an empty value, were refused there. Each is now refused as it is
|
|
104
|
+
without them, exit 2, and a value refused for what it holds is refused
|
|
105
|
+
before the configuration is read, so a line wrong in both ways names the
|
|
106
|
+
value. What only the tree can refuse, such as a `--root` that is not
|
|
107
|
+
there, is still answered by `--help` and `--version`, and so is a
|
|
108
|
+
command without its argument, `new --help`
|
|
109
|
+
([The help on a wrong line](README.md#the-help-on-a-wrong-line)).
|
|
110
|
+
Upgrading: take the wrong part off a line that asks for the help or the
|
|
111
|
+
version.
|
|
112
|
+
- **`--help` beside `--version` is refused**, in either order and by
|
|
113
|
+
either name. The version was printed and the help went unread, exit 0;
|
|
114
|
+
it is exit 2 and a line that names both. Upgrading: give one of the two.
|
|
115
|
+
|
|
14
116
|
## 0.8.0
|
|
15
117
|
|
|
16
118
|
An option is refused, exit 2, where taking it would tell someone what is
|
package/README.md
CHANGED
|
@@ -126,7 +126,32 @@ Live briefs with their status, in the word the brief writes (`封存` where the
|
|
|
126
126
|
| --- | --- |
|
|
127
127
|
| `--ready` | Only the ready briefs, which is the question an orchestrator asks. |
|
|
128
128
|
| `--archived` | The archive as well. |
|
|
129
|
-
| `--format json` | The whole table, for an orchestrator,
|
|
129
|
+
| `--format json` | The whole table, for an orchestrator, the sections the configuration asks for, each with its `hint`, and what the answer was read from. |
|
|
130
|
+
|
|
131
|
+
**What the answer was read from.** `--format json` names, under `inputs`, every input of its answer, so that a tool that asks for the same answer again, as spec-harness does before each write it checks, can give the one it kept while every input reads as listed, without starting spec-brief ([the family contract](https://github.com/DescentVTT/spec-core/blob/main/docs/adr/0005-the-family-contract.md), amended 2026-10-19):
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
"inputs": {
|
|
135
|
+
"keep": true,
|
|
136
|
+
"tool": "0.10.0",
|
|
137
|
+
"files": [
|
|
138
|
+
{ "path": ".spec-brief.json", "sha256": "ca3d163b..." },
|
|
139
|
+
{ "path": "briefs/001_a.md", "sha256": "5ee9361a..." },
|
|
140
|
+
{ "path": "spec-brief.json", "sha256": null }
|
|
141
|
+
],
|
|
142
|
+
"directories": [
|
|
143
|
+
{ "path": "briefs", "entries": ["001_a.md", "README.md"] },
|
|
144
|
+
{ "path": "briefs/archive", "entries": null }
|
|
145
|
+
],
|
|
146
|
+
"git": null
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- **`files`**: each file read, with the SHA-256 of its bytes in hex, and each name a configuration was looked for under and was not there, with `null`: it must still not be there.
|
|
151
|
+
- **`directories`**: each directory the briefs were listed from, with the names of the regular files directly in it, sorted as JavaScript sorts strings. A link and a directory are no file here, and a file that is no brief is named though it is not read, since one renamed would be. A directory looked for and not found, as an archive not yet made, has `null`: there must still be no directory there.
|
|
152
|
+
- **`tool`**: the version that read them. **`git`**: `null`, since `list` reads nothing of git, and asks it nothing where a configuration file names the root.
|
|
153
|
+
- **Paths** are POSIX, from the root, which wherever `keep` is `true` is the directory the run started in.
|
|
154
|
+
- **`keep` is `false`**, and the lists are empty, wherever spec-brief cannot name every input: a run that starts below its configuration's directory, or names a configuration in another, and one with no configuration file, where git or the search above the root finds the root.
|
|
130
155
|
|
|
131
156
|
### `spec-brief matrix`
|
|
132
157
|
|
|
@@ -258,7 +283,7 @@ Every command takes these, except where the last column names it: an option is [
|
|
|
258
283
|
| `--no-git` | Leaves git out even inside a repository: the tree is read from disk, and `archive` records no commit. | |
|
|
259
284
|
| `--color` | Colour, whatever the environment and the terminal say. | `init` and `new`, which print none |
|
|
260
285
|
| `--no-color` | No colour, whatever they say. | |
|
|
261
|
-
| `--help`, `--version` | Do what they say,
|
|
286
|
+
| `--help`, `--version` | Do what they say, on a line that is otherwise one to run: [a line refused for what it holds](#the-help-on-a-wrong-line) is refused with either of them on it, and the two together are refused. | |
|
|
262
287
|
|
|
263
288
|
Without `--color` or `--no-color`, `NO_COLOR` set to anything turns colour off; otherwise `FORCE_COLOR` turns it on, and `FORCE_COLOR=0` or `FORCE_COLOR=false` off, on a terminal too; otherwise `TERM=dumb` turns it off; otherwise a terminal has colour and a pipe has none. `NO_COLOR` or `FORCE_COLOR` set to nothing is as unset. Only the `pretty` format has colour.
|
|
264
289
|
|
|
@@ -268,7 +293,7 @@ Without `--color` or `--no-color`, `NO_COLOR` set to anything turns colour off;
|
|
|
268
293
|
| --- | --- |
|
|
269
294
|
| `0` | Clean. |
|
|
270
295
|
| `1` | Findings, a collision, or a refused action. |
|
|
271
|
-
| `2` | The run could not be trusted, or its answer did not arrive - a bad flag, [an input that names nothing](#an-input-that-names-nothing), [an option the command does not read](#an-option-a-command-does-not-read), a configuration that does not load, a brief that does not exist, a git command that failed, a `SOURCE_DATE_EPOCH` that [cannot be read as a date](#todays-date) where one is to be written, a stdout its reader closed before all of the output was written, as a pipeline into `head` does, each said in one line on stderr, or an error spec-brief did not expect, reported on stderr as `spec-brief: unexpected error:` with its stack. |
|
|
296
|
+
| `2` | The run could not be trusted, or its answer did not arrive - a bad flag, [an input that names nothing](#an-input-that-names-nothing), [an option the command does not read](#an-option-a-command-does-not-read), [an option given two values](#an-option-given-two-values), a configuration that does not load, a brief that does not exist, a git command that failed, a `SOURCE_DATE_EPOCH` that [cannot be read as a date](#todays-date) where one is to be written, a stdout its reader closed before all of the output was written, as a pipeline into `head` does, each said in one line on stderr, or an error spec-brief did not expect, reported on stderr as `spec-brief: unexpected error:` with its stack. |
|
|
272
297
|
|
|
273
298
|
A run over a briefs directory that does not exist exits 2, because a check over nothing looks exactly like a clean one.
|
|
274
299
|
|
|
@@ -280,7 +305,7 @@ An option, an argument or a path that is given and names nothing is refused: exi
|
|
|
280
305
|
- **A list that names nothing.** `--depends-on ,` names no brief, and a brief that depends on nothing is one scaffolded without the option. A place in a list that names no brief, the comma too many in `7,8,` or the gap in `7,,8`, is refused as well: it is a brief left out, as `"$A,$B"` is with one of the two unset.
|
|
281
306
|
- **An argument a command does not take.** `init`, `list`, `matrix` and `schedule` take none and refuse one by name, with their usage. `init mydir` set up the current directory; `init --root mydir` is what sets up another.
|
|
282
307
|
- **A `--root` that is no directory.** A file, or a path that does not exist, is refused: the search for a configuration would go on from its parent, and the run would report on, or `new` write into, the tree above. A directory below the configuration's is a place to start from, as the current directory is.
|
|
283
|
-
- **A configuration that is a
|
|
308
|
+
- **A configuration that is not a file**, named by `--config` or found under the configuration's name, does not load, and is said so in a line before it is opened, as one that is not JSON is: a directory, a named pipe, which was read without end, a socket or a device. A link is read as what it names.
|
|
284
309
|
|
|
285
310
|
### An option a command does not read
|
|
286
311
|
|
|
@@ -299,7 +324,32 @@ spec-brief: init does not read --strict; it reads --root, --format, --briefs and
|
|
|
299
324
|
- **Two options of which one would go unread** are refused together, for the same reason: `--config <file>` beside `--no-config` says the file was read, where the defaults ran and it was never opened, and `--color` beside `--no-color` that colour was forced on, where it was off. Give one of the two.
|
|
300
325
|
- **An option that asks a command to leave out what it never does is taken**, since it asks for what is already so: `--no-color` by `init` and `new`, which print no colour, `--no-git` by `init`, which asks git nothing, and `--no-config` by `init`, which opens no configuration file. A script that runs every command in a tree without git, or into a log, passes such an option to each of them. `init --no-config` still writes over no configuration: where one is there, it stops as `init` does.
|
|
301
326
|
- **An option a format has nothing to read for is taken**: `--no-color` or `--color` beside `--format json` changes nothing, and a caller that asks for JSON passes `--no-color` beside it.
|
|
302
|
-
- **`--help` and `--version`
|
|
327
|
+
- **`--help` and `--version` are no way past a refusal**: `init --strict --help` is refused as `init --strict` is ([the help on a wrong line](#the-help-on-a-wrong-line)).
|
|
328
|
+
|
|
329
|
+
### An option given two values
|
|
330
|
+
|
|
331
|
+
An option that takes one value is given one. Given two that read as two, the run is refused: exit 2, one line that names both as they were written, nothing written. The later was read and the earlier went unread, with no word of it: `list --root nowhere --root .` listed `.`, and `lint --format json --format pretty` printed `pretty` to a script that had asked for JSON.
|
|
332
|
+
|
|
333
|
+
```text
|
|
334
|
+
spec-brief: --root is given "nowhere" and ".", and takes one value; give one of the two
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
- **One value given twice is taken once, however it is written.** Two values are compared as each is read: `--root` and `--config` as the paths they resolve to, so `--root .` beside `--root ./`, and on Windows with the drive letter in either case, so `C:\x` beside `c:\x`, where `C:\x` beside `C:\X` is two; `--briefs` and `--archive` as directories of the repository, so `specs` beside `./specs/`; `--wave` and `--pr` by the number their digits write, so `1` beside `01`; `--depends-on` by the set of ids it names, each as an id is matched to a brief, so `7,8` beside `8,7` or `7, 8`, and `7` beside `007`, and the brief is written with the later; `--summary` with the spaces around it taken off. Any other value is read as it is written, in its own case.
|
|
338
|
+
- **A revision written two ways is asked of git**: `archive` asks git once what commit each value of `--commit`, or of `--base`, names, and takes `HEAD` beside the hash it names as one value. Two that name two commits, or one git cannot name, are two values; so are any two beside `--no-git`, `--help` or `--version`, none of which asks git.
|
|
339
|
+
- **Every option that takes a value takes one.** `--depends-on` is a list written in one value, and no option adds to a list each time it is given. A flag given twice is that flag once.
|
|
340
|
+
- A shell alias or a script that gives an option, and a line that gives it again to override it, is refused: give the option once.
|
|
341
|
+
|
|
342
|
+
### The help on a wrong line
|
|
343
|
+
|
|
344
|
+
A line refused for what it holds is refused with `--help` or `--version` on it, before it or after it, as an option spec-brief does not know always was. `init --strict --help` printed the help and `list --format sarif --version` the version, each exit 0, and said nothing of what was wrong. `--help` beside `--version` is refused too, in either order: one of the two answers went unread.
|
|
345
|
+
|
|
346
|
+
```text
|
|
347
|
+
spec-brief: --help is given beside --version, and one of the two answers would go unread; give one of the two
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
- **What the line alone decides is refused there**: an option or a command spec-brief does not know, [an input that names nothing](#an-input-that-names-nothing), [an option the command does not read](#an-option-a-command-does-not-read) and the pairs, `--commit` or `--base` beside `--no-git`, a `--format` the command does not write, [two values](#an-option-given-two-values), a `--wave` or `--pr` that is no number it takes, a `--date` that is no date, a revision that begins with `-`, a directory for `init` outside the repository or one for both, and a second brief for `archive` or `unarchive`.
|
|
351
|
+
- **What only the tree can refuse is not asked**: a `--root` that is not there, a configuration that does not load, an id that is taken, a type the configuration does not have, a brief or a commit that is not there. `--help` and `--version` open nothing, and answer.
|
|
352
|
+
- **What a command lacks is what the help is asked about**: `new --help` and `archive --help` print the help, though `new` without a title and `archive` without a brief are refused.
|
|
303
353
|
|
|
304
354
|
### Today's date
|
|
305
355
|
|
|
@@ -311,7 +361,7 @@ spec-brief: init does not read --strict; it reads --root, --format, --briefs and
|
|
|
311
361
|
|
|
312
362
|
## Configuration
|
|
313
363
|
|
|
314
|
-
`.spec-brief.json` (or `spec-brief.json`) at the root; the nearest one above the working directory is used, and its directory is the root. It is JSON, validated against [`schema.json`](schema.json): an unknown key, a misspelt rule or a value of the wrong type stops the run with exit 2 rather than falling back to defaults and reporting on the wrong rules.
|
|
364
|
+
`.spec-brief.json` (or `spec-brief.json`) at the root; the nearest one above the working directory is used, and its directory is the root. It is a file, and JSON, validated against [`schema.json`](schema.json): an unknown key, a misspelt rule or a value of the wrong type stops the run with exit 2 rather than falling back to defaults and reporting on the wrong rules.
|
|
315
365
|
|
|
316
366
|
| Key | Default | What it says |
|
|
317
367
|
| --- | --- | --- |
|
package/dist/archive.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Archival and its reverse, planned.\n *\n * A plan is a pure function of the corpus and a request: what would be\n * refused and why, the text every touched file would hold afterwards, and the\n * operations that get there. Nothing is written here. `--dry-run` prints a\n * plan; `apply.ts` executes one as a transaction. Splitting the two is what\n * makes the ceremony testable without a disk and previewable without risk.\n */\n\nimport { BANNER_CLOSE, BANNER_OPEN, type Brief, lineOfField } from './brief.js';\nimport type { Config } from './config.js';\nimport { type Corpus, resolveDependency } from './corpus.js';\nimport { editable, type FrontMatter, readFrontMatter, removeEntry, renderScalar, setEntry } from './frontmatter.js';\nimport type { CommitInfo, FileChange } from './git.js';\nimport { type Glob, matchGlob, parseGlob } from './glob.js';\nimport { INTEGRITY_FIELD, integrityOf } from './integrity.js';\nimport { dirOf, linesLinkingTo, normalisePath, rewriteLinks } from './links.js';\nimport { configuredSeverity } from './lint.js';\nimport type { Scan } from './markdown.js';\nimport { encodeLike, fillTemplate, joinLines, labelMatches, templateHoles } from './text.js';\nimport type { Finding, Severity } from './types.js';\n\nexport interface PullRequest {\n readonly number: number;\n readonly url: string | null;\n}\n\n/**\n * Why the files a round changed are unknown. `git`: there was no git to ask.\n * `revision`: no commit was named and no base configured, so no diff was\n * read. `merged`: the commit is already in the base branch, so the diff from\n * their merge base is empty whatever the round changed - archiving on the base\n * branch after the merge.\n */\nexport type Unmeasured =\n | { readonly reason: 'git' }\n | { readonly reason: 'revision' }\n | { readonly reason: 'merged'; readonly base: string; readonly commit: string };\n\nexport interface ArchiveRequest {\n /** `YYYY-MM-DD`. */\n readonly date: string;\n readonly summary?: string | undefined;\n readonly pr?: PullRequest | undefined;\n readonly commit?: CommitInfo | undefined;\n /** The files the round changed, when they were read. */\n readonly changes?: readonly FileChange[] | undefined;\n /**\n * Why `changes` is missing, when the caller knows. Without changes the\n * scope checks have nothing to check, and a plan that said nothing would\n * read as a round that stayed in scope.\n */\n readonly unmeasured?: Unmeasured | undefined;\n /** Uncommitted paths, when the working tree was read. */\n readonly dirty?: readonly string[] | undefined;\n readonly allowDirty?: boolean | undefined;\n /** Out-of-scope changes refuse the archival instead of warning. */\n readonly strict?: boolean | undefined;\n /** The corpus's lint findings; errors on the brief refuse the archival. */\n readonly findings?: readonly Finding[] | undefined;\n}\n\nexport type FileOp =\n | {\n readonly kind: 'write';\n readonly path: string;\n readonly content: string;\n /** What the file holds when the plan is made; `null` for a file that must not exist yet. */\n readonly before: string | null;\n }\n | { readonly kind: 'remove'; readonly path: string; readonly before: string };\n\nexport interface Plan {\n readonly action: 'archive' | 'unarchive';\n readonly brief: Brief;\n readonly from: string;\n readonly to: string;\n /** The brief is already where this action would put it. */\n readonly done: boolean;\n readonly ops: readonly FileOp[];\n /** Why the action is refused; empty when it may proceed. */\n readonly blocking: readonly Finding[];\n readonly warnings: readonly Finding[];\n readonly linksRewritten: number;\n readonly inboundRewritten: readonly string[];\n /** Links archived briefs hold to the old path. They are frozen and left as they are. */\n readonly inboundFrozen: readonly { readonly file: string; readonly line: number }[];\n readonly banner: readonly string[];\n readonly changes: readonly FileChange[];\n}\n\nfunction problem(\n brief: Brief,\n rule: string,\n severity: Severity,\n line: number,\n message: string,\n hint?: string,\n): Finding {\n return { rule, severity, message, file: brief.file, line, brief: brief.id ?? undefined, hint };\n}\n\nfunction lineOf(brief: Brief, key: string): number {\n return lineOfField(brief, key) + 1;\n}\n\nfunction protectedFinding(brief: Brief, path: string): Finding {\n return {\n ...problem(brief, 'protected-file', 'error', lineOf(brief, 'protectedFiles'), `the round changed ${path}, which this brief protects`, 'revert the change, or record the departure in the brief before archiving it'),\n path,\n };\n}\n\n/**\n * The files a round changed outside its scope: one finding, since the scope\n * is one defect however many files show it - widened once, or explained once.\n */\nfunction outOfScopeFinding(brief: Brief, paths: readonly string[], strict: boolean): Finding {\n return {\n ...problem(\n brief,\n 'out-of-scope',\n strict ? 'error' : 'warning',\n lineOf(brief, 'affectedFiles'),\n `the round changed ${paths.length} file(s) outside affectedFiles: ${listed(paths)}`,\n 'widen affectedFiles if the scope was wrong, or say why in the summary',\n ),\n paths,\n };\n}\n\n/** Where an archive rule's finding goes: an error refuses, and under --strict a warning refuses as an error, as out-of-scope does. */\nfunction place(finding: Finding, strict: boolean, blocking: Finding[], warnings: Finding[]): void {\n if (finding.severity === 'error') blocking.push(finding);\n else if (strict && finding.severity === 'warning') blocking.push({ ...finding, severity: 'error' });\n else warnings.push(finding);\n}\n\nconst UNMEASURED: Readonly<Record<Unmeasured['reason'], { readonly why: string; readonly hint: string }>> = {\n git: {\n why: 'without git, the files the round changed cannot be read',\n hint: 'archive inside the git work tree without --no-git, and name the round with --commit <rev> or --base <rev>',\n },\n revision: {\n why: 'no commit or base was named, so the files the round changed were not read',\n hint: 'pass --commit <rev> for the commit the round landed as, or --base <rev> for the branch it started from, or set \"archiving.base\"',\n },\n merged: {\n why: 'the diff from their merge base is empty',\n hint: \"archive on the round's branch before it merges, or pass --base <rev> naming the commit the round started from\",\n },\n};\n\n/**\n * The finding for scope checks that had nothing to check. A brief with no\n * scope has nothing to check either way, so it gets none.\n */\nfunction unmeasuredScope(brief: Brief, request: ArchiveRequest, severity: Severity): Finding | null {\n const unmeasured = request.unmeasured ?? (request.changes === undefined ? { reason: 'revision' as const } : undefined);\n const fields = [\n ...(brief.protectedFiles.length > 0 ? ['protectedFiles'] : []),\n ...(brief.affectedFiles.length > 0 ? ['affectedFiles'] : []),\n ];\n if (unmeasured === undefined || fields.length === 0) return null;\n const { why, hint } = UNMEASURED[unmeasured.reason];\n const cause = unmeasured.reason === 'merged' ? `${unmeasured.commit.slice(0, 7)} is already in ${unmeasured.base}, so ${why}` : why;\n return problem(brief, 'scope-unmeasured', severity, lineOf(brief, fields[0] as string), `${fields.join(' and ')} went unchecked: ${cause}`, hint);\n}\n\n/**\n * Scope patterns, for matching the files a round changed. A changed path is a\n * file that exists or existed, so a literal pattern is read as either: its own\n * path, and everything beneath it. Nothing can lie beneath a file, so the\n * reading cannot invent a match, and the tree need not be asked - it has\n * changed since the scope was written, by the round itself.\n */\nfunction globs(patterns: readonly string[]): Glob[] {\n return patterns.flatMap((p) => {\n const parsed = parseGlob(p, { literal: 'either' });\n return parsed.ok ? [parsed.glob] : [];\n });\n}\n\n/** A list marker opening a line, after its indentation, and the space that makes it one. */\nconst ITEM_START = /^[ \\t]*(?:[-*+]|\\d{1,9}[.)])[ \\t]/;\n\n/** A line that ends a sentence: a stop, then only closing marks. */\nconst SENTENCE_END = /[.!?][)\\]*_\"'`]*[ \\t]*$/;\n\n/**\n * Where a note's text starts: after its indentation and a list marker, if it\n * has one. Every part is optional, so it matches at the start of any line,\n * anchored or not.\n */\nconst NOTE_START = /^[ \\t]*(?:(?:[-*+]|\\d{1,9}[.)])[ \\t]+)?/;\n\n/**\n * Whether an open box carries a note that closes it: a line under the box,\n * within its item, that starts with a disposition marker and starts a note -\n * a bullet, \"- **Delegated to** 012\", a paragraph after a blank line, or a\n * line after one that ends a sentence, \"... did not.\" over \"**Rejected** by\n * ...\", which is how notes are written where they are written most. A line\n * that continues a sentence is not one: \"- [ ] Explain why the\" over\n * \"**Rejected** designs failed\" is the box's own sentence wrapping, and an\n * open task, as a marker in the middle of the box's line is a word in it. The note belongs to the box above\n * it, so the search stops at the first nested box: a child's note does not\n * close its parent.\n *\n * Where the note starts is read from the lines as written, and the marker from\n * the masked line, so a marker in code or a comment, or one after a code span,\n * closes nothing.\n */\nfunction dispositioned(scanned: Scan, line: number, end: number, markers: readonly string[]): boolean {\n const boxes = new Set(scanned.tasks.map((t) => t.line));\n for (let i = line + 1; i < end; i += 1) {\n if (boxes.has(i)) return false;\n const written = scanned.lines[i] as string;\n const above = scanned.lines[i - 1] as string;\n const startsNote = ITEM_START.test(written) || above.trim() === '' || SENTENCE_END.test(above);\n if (!startsNote) continue;\n const start = (NOTE_START.exec(written) as RegExpExecArray)[0].length;\n const text = scanned.masked[i] as string;\n if (markers.some((marker) => text.startsWith(marker, start))) return true;\n }\n return false;\n}\n\n/** A path inside a directory that may be the root itself. */\nfunction within(directory: string, name: string): string {\n return directory === '' ? name : `${directory}/${name}`;\n}\n\n/**\n * Whether a path is a brief: a file directly in the live or archive directory\n * whose name the configuration takes for a brief. Edits to briefs are the\n * ceremony, not the round, and are left out of the scope and tree checks.\n * Nothing else in those directories is: a README beside the briefs is work.\n */\nfunction isBriefPath(path: string, config: Config): boolean {\n const directory = dirOf(path);\n if (directory !== normalisePath(config.briefs) && directory !== normalisePath(config.archive)) return false;\n const name = path.slice(path.lastIndexOf('/') + 1);\n const accept = parseGlob(config.files);\n const excluded = config.exclude.some((e) => {\n const parsed = parseGlob(e);\n return parsed.ok && matchGlob(parsed.glob, name);\n });\n return accept.ok && matchGlob(accept.glob, name) && !excluded;\n}\n\n/** Task items that must be closed before a brief can be archived. */\nexport function openTasks(brief: Brief, corpus: Corpus): Brief['tasks'] {\n const { tasks: scope, dispositions } = corpus.config.archiving;\n // A box is never on a heading's line or past the last one, so neither bound is ever met.\n const inScope =\n scope === 'all'\n ? brief.tasks\n : brief.tasks.filter((task) =>\n brief.sections.some(\n (s) => task.line > s.heading.line && task.line < s.end && scope.some((name) => labelMatches(s.heading.text, name)),\n ),\n );\n return inScope.filter((task) => !task.checked && !dispositioned(brief.scan, task.line, task.end, dispositions));\n}\n\nfunction diffstat(changes: readonly FileChange[]): string {\n const insertions = changes.reduce((sum, c) => sum + (c.insertions ?? 0), 0);\n const deletions = changes.reduce((sum, c) => sum + (c.deletions ?? 0), 0);\n const files = changes.length === 1 ? '1 file changed' : `${changes.length} files changed`;\n return `${files}, +${insertions} \\u2212${deletions}`;\n}\n\n/**\n * The banner's lines, markers included. A template line whose placeholders\n * are not all filled is left out, so a round with no pull request has no\n * pull-request sentence rather than a sentence with a hole in it. A template\n * with nothing left writes no banner at all, markers included.\n */\nexport function renderBanner(template: readonly string[], values: Readonly<Record<string, string>>): string[] {\n const kept = template\n .filter((line) => templateHoles(line).every((hole) => (values[hole] ?? '') !== ''))\n .map((line) => fillTemplate(line, values));\n if (kept.length === 0) return [];\n return [BANNER_OPEN, ...kept.map((line) => (line === '' ? '>' : `> ${line}`)), BANNER_CLOSE];\n}\n\n/**\n * Removes a banner block and the blank line written after it. The exact\n * reverse of {@link withBanner}, so reopening a brief leaves its blank lines\n * as they were.\n */\nfunction withoutBanner(lines: readonly string[], banner: Brief['banner']): string[] {\n if (banner === null) return [...lines];\n const after = lines[banner.end]?.trim() === '' ? banner.end + 1 : banner.end;\n return [...lines.slice(0, banner.start), ...lines.slice(after)];\n}\n\n/**\n * Inserts a banner under the front matter, after the blank line that usually\n * follows it, and writes one blank line after the banner. A front matter never\n * closed has no line to go under: its `close` is -1, which is the top, as for\n * a brief with none.\n */\nfunction withBanner(lines: readonly string[], banner: readonly string[]): string[] {\n const frontMatter = readFrontMatter(lines);\n let at = frontMatter === null ? 0 : frontMatter.close + 1;\n if (at > 0 && lines[at]?.trim() === '') at += 1;\n return [...lines.slice(0, at), ...banner, '', ...lines.slice(at)];\n}\n\n/**\n * Sets the integrity field to the hash of everything else. The field is put in\n * place before hashing, so the lines hashed are exactly the lines a later\n * check sees once it takes the field back out. The hash is taken without the\n * field's line, so the word that holds its place is never read.\n */\nfunction withIntegrity(lines: readonly string[]): string[] {\n const placed = setEntry(lines, readFrontMatter(lines), INTEGRITY_FIELD, 'pending');\n const hash = integrityOf(joinLines(placed, '\\n'));\n return setEntry(placed, readFrontMatter(placed), INTEGRITY_FIELD, hash);\n}\n\n/**\n * Whether a plan can write into the brief's front matter: it has none, or one\n * closed and written in YAML. One never closed, or TOML, cannot be written\n * into. The front-matter rule reports both, and a plan that `edits` the front\n * matter and is not refused by it already - the rule lowered, or a reopening,\n * which lint does not gate - is refused here. It leaves the front matter as\n * written rather than half edited.\n *\n * The front matter judged is the brief's own, or for a brief read as having\n * none, whatever block the `lines` about to be edited open with. They open\n * with one where a banner stood at the very top of the file: it hid the block\n * under it from every reader, and with the banner taken out that block is\n * what an edit would go into.\n */\nfunction writable(brief: Brief, lines: readonly string[], edits: boolean, blocking: Finding[]): boolean {\n const frontMatter = brief.frontMatter ?? readFrontMatter(lines);\n if (frontMatter === null || editable(frontMatter)) return true;\n if (edits && !blocking.some((f) => f.rule === 'front-matter')) {\n const open = frontMatter.close === -1;\n blocking.push(\n problem(\n brief,\n 'front-matter',\n 'error',\n 1,\n open ? 'the front matter is never closed, so it cannot be written into' : 'the front matter is TOML, which spec-brief does not write',\n open ? 'close the front matter with a \"---\" line' : 'write the front matter as YAML between \"---\" lines',\n ),\n );\n }\n return false;\n}\n\ninterface Place {\n readonly file: string;\n readonly line: number;\n}\n\ninterface Inbound {\n readonly ops: FileOp[];\n readonly rewritten: string[];\n readonly frozen: Place[];\n /** Links live briefs hold to it, left as they are because rewriting is off. */\n readonly stale: Place[];\n}\n\n/**\n * Links other briefs hold to a file that is moving: rewritten in live briefs,\n * reported in frozen ones. `archiving.rewriteLinks` governs these as it does\n * the moving brief's own links, so with it off a live brief is not written,\n * and the links it is left holding are reported instead.\n */\nfunction inbound(corpus: Corpus, moving: Brief, to: string): Inbound {\n const result: Inbound = { ops: [], rewritten: [], frozen: [], stale: [] };\n for (const other of corpus.briefs) {\n if (other === moving) continue;\n const directory = dirOf(other.file);\n const lines = linesLinkingTo(other.scan, directory, moving.file);\n if (lines.length === 0) continue;\n if (other.phase === 'archived' || !corpus.config.archiving.rewriteLinks) {\n const left = other.phase === 'archived' ? result.frozen : result.stale;\n for (const line of lines) left.push({ file: other.file, line: line + 1 });\n continue;\n }\n const rewritten = rewriteLinks(other.scan, directory, directory, (p) => (p === moving.file ? to : p));\n result.ops.push({ kind: 'write', path: other.file, content: encodeLike(other.source, rewritten.lines), before: other.source });\n result.rewritten.push(other.file);\n }\n return result;\n}\n\n/** Five items, and a count of the rest. */\nfunction listed(items: readonly string[]): string {\n return items.slice(0, 5).join(', ') + (items.length > 5 ? `, and ${items.length - 5} more` : '');\n}\n\n/**\n * Links live briefs will hold to nothing once the brief moves, when rewriting\n * is off: the move is what breaks them, so the move says where they are.\n */\nfunction staleLinks(corpus: Corpus, brief: Brief, stale: readonly Place[], strict: boolean, blocking: Finding[], warnings: Finding[]): void {\n const severity = configuredSeverity(corpus, 'stale-link');\n if (severity === null || stale.length === 0) return;\n const finding = problem(\n brief,\n 'stale-link',\n severity,\n 1,\n `links on ${stale.length} line(s) of other live briefs will stop resolving when it moves: ${listed(stale.map((s) => `${s.file}:${s.line}`))}`,\n 'turn \"archiving.rewriteLinks\" on to have them rewritten, or fix them by hand',\n );\n place(finding, strict, blocking, warnings);\n}\n\nfunction donePlan(action: Plan['action'], brief: Brief): Plan {\n return {\n action,\n brief,\n from: brief.file,\n to: brief.file,\n done: true,\n ops: [],\n blocking: [],\n warnings: [],\n linksRewritten: 0,\n inboundRewritten: [],\n inboundFrozen: [],\n banner: [],\n changes: [],\n };\n}\n\nexport function planArchive(corpus: Corpus, brief: Brief, request: ArchiveRequest): Plan {\n if (brief.phase === 'archived') return donePlan('archive', brief);\n const { config } = corpus;\n const archiveDir = normalisePath(config.archive);\n const to = within(archiveDir, brief.name);\n const blocking: Finding[] = [];\n const warnings: Finding[] = [];\n\n // Under --strict a warning is an error, here as in lint.\n const refuses = (finding: Finding): boolean =>\n finding.file === brief.file && (finding.severity === 'error' || (request.strict === true && finding.severity === 'warning'));\n blocking.push(...(request.findings?.filter(refuses) ?? []));\n // Only a status field can say \"draft\" or \"deferred\", so there is one to point at.\n const field = config.status.field as string;\n if (brief.status === 'draft') {\n blocking.push(\n problem(brief, 'archive-draft', 'error', lineOf(brief, field), 'is a draft, and a draft has not been executed', `set \"${field}: ${config.status.active}\" once the round runs`),\n );\n }\n if (brief.status === 'deferred') {\n blocking.push(\n problem(\n brief,\n 'archive-deferred',\n 'error',\n lineOf(brief, field),\n 'is deferred, and deferred work has not been executed',\n `set \"${field}: ${config.status.active}\" when its trigger fires and the round runs`,\n ),\n );\n }\n for (const task of openTasks(brief, corpus)) {\n blocking.push(\n problem(\n brief,\n 'open-task',\n 'error',\n task.line + 1,\n `\"${task.text === '' ? '(empty)' : task.text}\" is neither ticked nor dispositioned`,\n `tick it, or say why under it, as a bullet or as a paragraph after a blank line, starting ${config.archiving.dispositions.map((d) => `\"${d}\"`).join(', ')}`,\n ),\n );\n }\n for (const dependency of brief.dependsOn) {\n const target = resolveDependency(corpus, dependency);\n if (target !== undefined && target !== brief && target.phase === 'live') {\n blocking.push(\n problem(brief, 'dependency-open', 'error', lineOf(brief, 'dependsOn'), `depends on ${target.id ?? target.name}, which is not archived yet`, `archive ${target.id ?? target.name} first, or drop the dependency if it was never real`),\n );\n }\n }\n const bookkeeping = (path: string): boolean => isBriefPath(path, config);\n if (request.dirty !== undefined && request.allowDirty !== true) {\n const outside = request.dirty.filter((path) => !bookkeeping(path));\n if (outside.length > 0) {\n blocking.push(\n problem(brief, 'dirty-tree', 'error', 1, `the working tree has uncommitted changes outside the briefs: ${listed(outside)}`, 'commit them so the recorded commit holds the round, or pass --allow-dirty'),\n );\n }\n }\n\n const work = (request.changes ?? []).filter((change) => !bookkeeping(change.path));\n const protectedGlobs = globs(brief.protectedFiles);\n const affectedGlobs = globs(brief.affectedFiles);\n // Each protected file changed is its own defect - reverted, or ruled on,\n // one file at a time - so each is a finding that names its path.\n for (const change of work) {\n if (protectedGlobs.some((g) => matchGlob(g, change.path))) blocking.push(protectedFinding(brief, change.path));\n }\n // A protected file is reported once, as protected, and not again as out of scope.\n const unprotected = work.filter((c) => !protectedGlobs.some((g) => matchGlob(g, c.path)));\n const outside = affectedGlobs.length === 0 ? [] : unprotected.filter((c) => !affectedGlobs.some((g) => matchGlob(g, c.path)));\n if (outside.length > 0) {\n const finding = outOfScopeFinding(brief, outside.map((c) => c.path), request.strict === true);\n (request.strict === true ? blocking : warnings).push(finding);\n }\n const scopeSeverity = configuredSeverity(corpus, 'scope-unmeasured');\n const unmeasured = scopeSeverity === null ? null : unmeasuredScope(brief, request, scopeSeverity);\n if (unmeasured !== null) place(unmeasured, request.strict === true, blocking, warnings);\n if (corpus.briefs.some((b) => b.file === to)) {\n blocking.push(problem(brief, 'archive-exists', 'error', 1, `${to} already exists`, 'an archived brief is never overwritten'));\n }\n\n let lines: string[] = [...brief.lines];\n let linksRewritten = 0;\n if (config.archiving.rewriteLinks) {\n const rewritten = rewriteLinks(brief.scan, dirOf(brief.file), archiveDir, (p) => (p === brief.file ? to : p));\n lines = rewritten.lines;\n linksRewritten = rewritten.count;\n }\n lines = withoutBanner(lines, brief.banner);\n\n const pr = request.pr;\n const values: Record<string, string> = {\n date: request.date,\n summary: request.summary?.trim() ?? '',\n pr: pr === undefined ? '' : pr.url === null ? `#${pr.number}` : `[#${pr.number}](${pr.url})`,\n commit: request.commit?.sha.slice(0, 7) ?? '',\n diffstat: request.commit === undefined || request.changes === undefined ? '' : diffstat(request.changes),\n links:\n linksRewritten === 0\n ? ''\n : `Relative links were rewritten to resolve from \\`${archiveDir}/\\` (${linksRewritten}); no other word changed.`,\n id: brief.id ?? '',\n title: brief.title ?? '',\n author: request.commit?.author ?? '',\n };\n const banner = renderBanner(config.archiving.banner, values);\n if (banner.length > 0) lines = withBanner(lines, banner);\n const writes = writable(brief, lines, config.status.field !== null || config.archiving.freeze, blocking);\n if (writes && config.status.field !== null) {\n lines = setEntry(lines, readFrontMatter(lines), config.status.field, renderScalar(config.status.archived));\n }\n lines = removeEntry(lines, readFrontMatter(lines), INTEGRITY_FIELD);\n if (writes && config.archiving.freeze) lines = withIntegrity(lines);\n\n const incoming = inbound(corpus, brief, to);\n staleLinks(corpus, brief, incoming.stale, request.strict === true, blocking, warnings);\n return {\n action: 'archive',\n brief,\n from: brief.file,\n to,\n done: false,\n ops: [\n { kind: 'write', path: to, content: encodeLike(brief.source, lines), before: null },\n ...incoming.ops,\n { kind: 'remove', path: brief.file, before: brief.source },\n ],\n blocking,\n warnings,\n linksRewritten,\n inboundRewritten: incoming.rewritten,\n inboundFrozen: incoming.frozen,\n banner,\n changes: request.changes ?? [],\n };\n}\n\n/** A plugin's answer to a refusal it may lift: which rule, for which path, and why. */\nexport interface Waiver {\n readonly rule: string;\n readonly path: string;\n readonly reason: string;\n}\n\n/**\n * The refusals a plugin may lift. A tool that verifies a ruling can say a\n * protected file was allowed to change, or that a file outside the scope was;\n * whether a round is done is spec-brief's to say.\n */\nexport const WAIVABLE: readonly string[] = ['protected-file', 'out-of-scope'];\n\n/**\n * The plan with the refusals plugins waived turned into notes. A waiver\n * matches a blocking finding by rule and path: a protected-file finding is\n * replaced by the note, and an out-of-scope finding loses the path and goes\n * when none is left. A waiver that matches nothing changes nothing, and one\n * for any other rule is ignored with a warning, which refuses under --strict\n * as any warning does.\n */\nexport function applyWaivers(plan: Plan, waivers: readonly { readonly plugin: string; readonly waiver: Waiver }[], strict = false): Plan {\n const { brief } = plan;\n const blocking = [...plan.blocking];\n const warnings = [...plan.warnings];\n for (const { plugin, waiver } of waivers) {\n if (!WAIVABLE.includes(waiver.rule)) {\n const ignored = problem(\n brief,\n 'waiver-ignored',\n 'warning',\n 1,\n `${plugin} asked to waive ${waiver.rule} for ${waiver.path}; a plugin may waive only ${WAIVABLE.join(' and ')}`,\n `report it to the plugin's authors: ${waiver.rule} is spec-brief's to decide`,\n );\n place(ignored, strict, blocking, warnings);\n continue;\n }\n const at = blocking.findIndex((f) => f.rule === waiver.rule && (f.path === waiver.path || f.paths?.includes(waiver.path) === true));\n if (at < 0) continue;\n const found = blocking[at] as Finding;\n const rest = (found.paths ?? []).filter((p) => p !== waiver.path);\n blocking.splice(at, 1, ...(rest.length > 0 ? [outOfScopeFinding(brief, rest, true)] : []));\n warnings.push({\n ...problem(brief, 'waived', 'note', found.line, `${plugin} waives ${waiver.rule} for ${waiver.path}: ${waiver.reason}`, 'review the waiver with the round; it stands where the refusal was'),\n path: waiver.path,\n });\n }\n return { ...plan, blocking, warnings };\n}\n\nexport interface UnarchiveRequest {\n /** Warnings refuse the reopening, as they fail lint. */\n readonly strict?: boolean | undefined;\n}\n\n/**\n * Reopens an archived brief: the banner and the freeze come off, the status\n * goes back to the live word, and the links are rewritten for the directory\n * it returns to. What the round wrote stays in history, where it belongs.\n */\nexport function planUnarchive(corpus: Corpus, brief: Brief, request: UnarchiveRequest = {}): Plan {\n if (brief.phase === 'live') return donePlan('unarchive', brief);\n const { config } = corpus;\n const briefsDir = normalisePath(config.briefs);\n const to = within(briefsDir, brief.name);\n const blocking: Finding[] = [];\n const warnings: Finding[] = [];\n if (corpus.briefs.some((b) => b.file === to)) {\n blocking.push(problem(brief, 'unarchive-exists', 'error', 1, `${to} already exists`, 'rename one of them first'));\n }\n\n let lines: string[] = [...brief.lines];\n let linksRewritten = 0;\n if (config.archiving.rewriteLinks) {\n const rewritten = rewriteLinks(brief.scan, dirOf(brief.file), briefsDir, (p) => (p === brief.file ? to : p));\n lines = rewritten.lines;\n linksRewritten = rewritten.count;\n }\n lines = withoutBanner(lines, brief.banner);\n lines = removeEntry(lines, readFrontMatter(lines), INTEGRITY_FIELD);\n const field = config.status.field;\n if (writable(brief, lines, field !== null, blocking) && field !== null) {\n lines = setEntry(lines, readFrontMatter(lines), field, renderScalar(config.status.active));\n }\n // Archival gives a brief with no front matter a block to hold its hash.\n // A block this reopening emptied goes too, and the brief is the one that\n // was archived. One that was empty before it was archived reads the same\n // once the hash is in it, and goes with it; one empty in the archive stays.\n // No edit above reaches the opening line, so a brief that had a block has\n // one still, and only a YAML block has lost a line.\n const had = brief.frontMatter;\n const emptied = had !== null && had.close > 1 && (readFrontMatter(lines) as FrontMatter).close === 1;\n if (emptied) lines = lines.slice(2);\n\n const incoming = inbound(corpus, brief, to);\n staleLinks(corpus, brief, incoming.stale, request.strict === true, blocking, warnings);\n return {\n action: 'unarchive',\n brief,\n from: brief.file,\n to,\n done: false,\n ops: [\n { kind: 'write', path: to, content: encodeLike(brief.source, lines), before: null },\n ...incoming.ops,\n { kind: 'remove', path: brief.file, before: brief.source },\n ],\n blocking,\n warnings,\n linksRewritten,\n inboundRewritten: incoming.rewritten,\n inboundFrozen: incoming.frozen,\n banner: [],\n changes: [],\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Archival and its reverse, planned.\n *\n * A plan is a pure function of the corpus and a request: what would be\n * refused and why, the text every touched file would hold afterwards, and the\n * operations that get there. Nothing is written here. `--dry-run` prints a\n * plan; `apply.ts` executes one as a transaction. Splitting the two is what\n * makes the ceremony testable without a disk and previewable without risk.\n */\n\nimport { BANNER_CLOSE, BANNER_OPEN, type Brief, lineOfField } from './brief.js';\nimport type { Config } from './config.js';\nimport { type Corpus, resolveDependency } from './corpus.js';\nimport { editable, type FrontMatter, readFrontMatter, removeEntry, renderScalar, setEntry } from './frontmatter.js';\nimport type { CommitInfo, FileChange } from './git.js';\nimport { type Glob, matchGlob, parseGlob } from './glob.js';\nimport { INTEGRITY_FIELD, integrityOf } from './integrity.js';\nimport { dirOf, linesLinkingTo, normalisePath, rewriteLinks } from './links.js';\nimport { configuredSeverity } from './lint.js';\nimport type { Scan } from './markdown.js';\nimport { encodeLike, fillTemplate, joinLines, labelMatches, templateHoles } from './text.js';\nimport type { Finding, Severity } from './types.js';\n\nexport interface PullRequest {\n readonly number: number;\n readonly url: string | null;\n}\n\n/**\n * Why the files a round changed are unknown. `git`: there was no git to ask.\n * `revision`: no commit was named and no base configured, so no diff was\n * read. `merged`: the commit is already in the base branch, so the diff from\n * their merge base is empty whatever the round changed - archiving on the base\n * branch after the merge.\n */\nexport type Unmeasured =\n | { readonly reason: 'git' }\n | { readonly reason: 'revision' }\n | { readonly reason: 'merged'; readonly base: string; readonly commit: string };\n\nexport interface ArchiveRequest {\n /** `YYYY-MM-DD`. */\n readonly date: string;\n readonly summary?: string | undefined;\n readonly pr?: PullRequest | undefined;\n readonly commit?: CommitInfo | undefined;\n /** The files the round changed, when they were read. */\n readonly changes?: readonly FileChange[] | undefined;\n /**\n * Why `changes` is missing, when the caller knows. Without changes the\n * scope checks have nothing to check, and a plan that said nothing would\n * read as a round that stayed in scope.\n */\n readonly unmeasured?: Unmeasured | undefined;\n /** Uncommitted paths, when the working tree was read. */\n readonly dirty?: readonly string[] | undefined;\n readonly allowDirty?: boolean | undefined;\n /** Out-of-scope changes refuse the archival instead of warning. */\n readonly strict?: boolean | undefined;\n /** The corpus's lint findings; errors on the brief refuse the archival. */\n readonly findings?: readonly Finding[] | undefined;\n}\n\nexport type FileOp =\n | {\n readonly kind: 'write';\n readonly path: string;\n readonly content: string;\n /** What the file holds when the plan is made; `null` for a file that must not exist yet. */\n readonly before: string | null;\n }\n | { readonly kind: 'remove'; readonly path: string; readonly before: string };\n\nexport interface Plan {\n readonly action: 'archive' | 'unarchive';\n readonly brief: Brief;\n readonly from: string;\n readonly to: string;\n /** The brief is already where this action would put it. */\n readonly done: boolean;\n readonly ops: readonly FileOp[];\n /** Why the action is refused; empty when it may proceed. */\n readonly blocking: readonly Finding[];\n readonly warnings: readonly Finding[];\n readonly linksRewritten: number;\n readonly inboundRewritten: readonly string[];\n /** Links archived briefs hold to the old path. They are frozen and left as they are. */\n readonly inboundFrozen: readonly { readonly file: string; readonly line: number }[];\n readonly banner: readonly string[];\n readonly changes: readonly FileChange[];\n}\n\nfunction problem(\n brief: Brief,\n rule: string,\n severity: Severity,\n line: number,\n message: string,\n hint?: string,\n): Finding {\n return { rule, severity, message, file: brief.file, line, brief: brief.id ?? undefined, hint };\n}\n\nfunction lineOf(brief: Brief, key: string): number {\n return lineOfField(brief, key) + 1;\n}\n\nfunction protectedFinding(brief: Brief, path: string): Finding {\n return {\n ...problem(brief, 'protected-file', 'error', lineOf(brief, 'protectedFiles'), `the round changed ${path}, which this brief protects`, 'revert the change, or record the departure in the brief before archiving it'),\n path,\n };\n}\n\n/**\n * The files a round changed outside its scope: one finding, since the scope\n * is one defect however many files show it - widened once, or explained once.\n */\nfunction outOfScopeFinding(brief: Brief, paths: readonly string[], strict: boolean): Finding {\n return {\n ...problem(\n brief,\n 'out-of-scope',\n strict ? 'error' : 'warning',\n lineOf(brief, 'affectedFiles'),\n `the round changed ${paths.length} file(s) outside affectedFiles: ${listed(paths)}`,\n 'widen affectedFiles if the scope was wrong, or say why in the summary',\n ),\n paths,\n };\n}\n\n/** Where an archive rule's finding goes: an error refuses, and under --strict a warning refuses as an error, as out-of-scope does. */\nfunction place(finding: Finding, strict: boolean, blocking: Finding[], warnings: Finding[]): void {\n if (finding.severity === 'error') blocking.push(finding);\n else if (strict && finding.severity === 'warning') blocking.push({ ...finding, severity: 'error' });\n else warnings.push(finding);\n}\n\nconst UNMEASURED: Readonly<Record<Unmeasured['reason'], { readonly why: string; readonly hint: string }>> = {\n git: {\n why: 'without git, the files the round changed cannot be read',\n hint: 'archive inside the git work tree without --no-git, and name the round with --commit <rev> or --base <rev>',\n },\n revision: {\n why: 'no commit or base was named, so the files the round changed were not read',\n hint: 'pass --commit <rev> for the commit the round landed as, or --base <rev> for the branch it started from, or set \"archiving.base\"',\n },\n merged: {\n why: 'the diff from their merge base is empty',\n hint: \"archive on the round's branch before it merges, or pass --base <rev> naming the commit the round started from\",\n },\n};\n\n/**\n * The finding for scope checks that had nothing to check. A brief with no\n * scope has nothing to check either way, so it gets none.\n */\nfunction unmeasuredScope(brief: Brief, request: ArchiveRequest, severity: Severity): Finding | null {\n const unmeasured = request.unmeasured ?? (request.changes === undefined ? ({ reason: 'revision' } satisfies Unmeasured) : undefined);\n const fields = [\n ...(brief.protectedFiles.length > 0 ? ['protectedFiles'] : []),\n ...(brief.affectedFiles.length > 0 ? ['affectedFiles'] : []),\n ];\n if (unmeasured === undefined || fields.length === 0) return null;\n const { why, hint } = UNMEASURED[unmeasured.reason];\n const cause = unmeasured.reason === 'merged' ? `${unmeasured.commit.slice(0, 7)} is already in ${unmeasured.base}, so ${why}` : why;\n return problem(brief, 'scope-unmeasured', severity, lineOf(brief, fields[0] as string), `${fields.join(' and ')} went unchecked: ${cause}`, hint);\n}\n\n/**\n * Scope patterns, for matching the files a round changed. A changed path is a\n * file that exists or existed, so a literal pattern is read as either: its own\n * path, and everything beneath it. Nothing can lie beneath a file, so the\n * reading cannot invent a match, and the tree need not be asked - it has\n * changed since the scope was written, by the round itself.\n */\nfunction globs(patterns: readonly string[]): Glob[] {\n return patterns.flatMap((p) => {\n const parsed = parseGlob(p, { literal: 'either' });\n return parsed.ok ? [parsed.glob] : [];\n });\n}\n\n/** A list marker opening a line, after its indentation, and the space that makes it one. */\nconst ITEM_START = /^[ \\t]*(?:[-*+]|\\d{1,9}[.)])[ \\t]/;\n\n/** A line that ends a sentence: a stop, then only closing marks. */\nconst SENTENCE_END = /[.!?][)\\]*_\"'`]*[ \\t]*$/;\n\n/**\n * Where a note's text starts: after its indentation and a list marker, if it\n * has one. Every part is optional, so it matches at the start of any line,\n * anchored or not.\n */\nconst NOTE_START = /^[ \\t]*(?:(?:[-*+]|\\d{1,9}[.)])[ \\t]+)?/;\n\n/**\n * Whether an open box carries a note that closes it: a line under the box,\n * within its item, that starts with a disposition marker and starts a note -\n * a bullet, \"- **Delegated to** 012\", a paragraph after a blank line, or a\n * line after one that ends a sentence, \"... did not.\" over \"**Rejected** by\n * ...\", which is how notes are written where they are written most. A line\n * that continues a sentence is not one: \"- [ ] Explain why the\" over\n * \"**Rejected** designs failed\" is the box's own sentence wrapping, and an\n * open task, as a marker in the middle of the box's line is a word in it. The note belongs to the box above\n * it, so the search stops at the first nested box: a child's note does not\n * close its parent.\n *\n * Where the note starts is read from the lines as written, and the marker from\n * the masked line, so a marker in code or a comment, or one after a code span,\n * closes nothing.\n */\nfunction dispositioned(scanned: Scan, line: number, end: number, markers: readonly string[]): boolean {\n const boxes = new Set(scanned.tasks.map((t) => t.line));\n for (let i = line + 1; i < end; i += 1) {\n if (boxes.has(i)) return false;\n const written = scanned.lines[i] as string;\n const above = scanned.lines[i - 1]!;\n const startsNote = ITEM_START.test(written) || above.trim() === '' || SENTENCE_END.test(above);\n if (!startsNote) continue;\n const start = (NOTE_START.exec(written) as RegExpExecArray)[0].length;\n const text = scanned.masked[i] as string;\n if (markers.some((marker) => text.startsWith(marker, start))) return true;\n }\n return false;\n}\n\n/** A path inside a directory that may be the root itself. */\nfunction within(directory: string, name: string): string {\n return directory === '' ? name : `${directory}/${name}`;\n}\n\n/**\n * Whether a path is a brief: a file directly in the live or archive directory\n * whose name the configuration takes for a brief. Edits to briefs are the\n * ceremony, not the round, and are left out of the scope and tree checks.\n * Nothing else in those directories is: a README beside the briefs is work.\n */\nfunction isBriefPath(path: string, config: Config): boolean {\n const directory = dirOf(path);\n if (directory !== normalisePath(config.briefs) && directory !== normalisePath(config.archive)) return false;\n const name = path.slice(path.lastIndexOf('/') + 1);\n const accept = parseGlob(config.files);\n const excluded = config.exclude.some((e) => {\n const parsed = parseGlob(e);\n return parsed.ok && matchGlob(parsed.glob, name);\n });\n return accept.ok && matchGlob(accept.glob, name) && !excluded;\n}\n\n/** Task items that must be closed before a brief can be archived. */\nexport function openTasks(brief: Brief, corpus: Corpus): Brief['tasks'] {\n const { tasks: scope, dispositions } = corpus.config.archiving;\n // A box is never on a heading's line or past the last one, so neither bound is ever met.\n const inScope =\n scope === 'all'\n ? brief.tasks\n : brief.tasks.filter((task) =>\n brief.sections.some(\n (s) => task.line > s.heading.line && task.line < s.end && scope.some((name) => labelMatches(s.heading.text, name)),\n ),\n );\n return inScope.filter((task) => !task.checked && !dispositioned(brief.scan, task.line, task.end, dispositions));\n}\n\nfunction diffstat(changes: readonly FileChange[]): string {\n const insertions = changes.reduce((sum, c) => sum + (c.insertions ?? 0), 0);\n const deletions = changes.reduce((sum, c) => sum + (c.deletions ?? 0), 0);\n const files = changes.length === 1 ? '1 file changed' : `${changes.length} files changed`;\n return `${files}, +${insertions} \\u2212${deletions}`;\n}\n\n/**\n * The banner's lines, markers included. A template line whose placeholders\n * are not all filled is left out, so a round with no pull request has no\n * pull-request sentence rather than a sentence with a hole in it. A template\n * with nothing left writes no banner at all, markers included.\n */\nexport function renderBanner(template: readonly string[], values: Readonly<Record<string, string>>): string[] {\n const kept = template\n .filter((line) => templateHoles(line).every((hole) => (values[hole] ?? '') !== ''))\n .map((line) => fillTemplate(line, values));\n if (kept.length === 0) return [];\n return [BANNER_OPEN, ...kept.map((line) => (line === '' ? '>' : `> ${line}`)), BANNER_CLOSE];\n}\n\n/**\n * Removes a banner block and the blank line written after it. The exact\n * reverse of {@link withBanner}, so reopening a brief leaves its blank lines\n * as they were.\n */\nfunction withoutBanner(lines: readonly string[], banner: Brief['banner']): string[] {\n if (banner === null) return [...lines];\n const after = lines[banner.end]?.trim() === '' ? banner.end + 1 : banner.end;\n return [...lines.slice(0, banner.start), ...lines.slice(after)];\n}\n\n/**\n * Inserts a banner under the front matter, after the blank line that usually\n * follows it, and writes one blank line after the banner. A front matter never\n * closed has no line to go under: its `close` is -1, which is the top, as for\n * a brief with none.\n */\nfunction withBanner(lines: readonly string[], banner: readonly string[]): string[] {\n const frontMatter = readFrontMatter(lines);\n let at = frontMatter === null ? 0 : frontMatter.close + 1;\n if (at > 0 && lines[at]?.trim() === '') at += 1;\n return [...lines.slice(0, at), ...banner, '', ...lines.slice(at)];\n}\n\n/**\n * Sets the integrity field to the hash of everything else. The field is put in\n * place before hashing, so the lines hashed are exactly the lines a later\n * check sees once it takes the field back out. The hash is taken without the\n * field's line, so the word that holds its place is never read.\n */\nfunction withIntegrity(lines: readonly string[]): string[] {\n const placed = setEntry(lines, readFrontMatter(lines), INTEGRITY_FIELD, 'pending');\n const hash = integrityOf(joinLines(placed, '\\n'));\n return setEntry(placed, readFrontMatter(placed), INTEGRITY_FIELD, hash);\n}\n\n/**\n * Whether a plan can write into the brief's front matter: it has none, or one\n * closed and written in YAML. One never closed, or TOML, cannot be written\n * into. The front-matter rule reports both, and a plan that `edits` the front\n * matter and is not refused by it already - the rule lowered, or a reopening,\n * which lint does not gate - is refused here. It leaves the front matter as\n * written rather than half edited.\n *\n * The front matter judged is the brief's own, or for a brief read as having\n * none, whatever block the `lines` about to be edited open with. They open\n * with one where a banner stood at the very top of the file: it hid the block\n * under it from every reader, and with the banner taken out that block is\n * what an edit would go into.\n */\nfunction writable(brief: Brief, lines: readonly string[], edits: boolean, blocking: Finding[]): boolean {\n const frontMatter = brief.frontMatter ?? readFrontMatter(lines);\n if (frontMatter === null || editable(frontMatter)) return true;\n if (edits && !blocking.some((f) => f.rule === 'front-matter')) {\n const open = frontMatter.close === -1;\n blocking.push(\n problem(\n brief,\n 'front-matter',\n 'error',\n 1,\n open ? 'the front matter is never closed, so it cannot be written into' : 'the front matter is TOML, which spec-brief does not write',\n open ? 'close the front matter with a \"---\" line' : 'write the front matter as YAML between \"---\" lines',\n ),\n );\n }\n return false;\n}\n\ninterface Place {\n readonly file: string;\n readonly line: number;\n}\n\ninterface Inbound {\n readonly ops: FileOp[];\n readonly rewritten: string[];\n readonly frozen: Place[];\n /** Links live briefs hold to it, left as they are because rewriting is off. */\n readonly stale: Place[];\n}\n\n/**\n * Links other briefs hold to a file that is moving: rewritten in live briefs,\n * reported in frozen ones. `archiving.rewriteLinks` governs these as it does\n * the moving brief's own links, so with it off a live brief is not written,\n * and the links it is left holding are reported instead.\n */\nfunction inbound(corpus: Corpus, moving: Brief, to: string): Inbound {\n const result: Inbound = { ops: [], rewritten: [], frozen: [], stale: [] };\n for (const other of corpus.briefs) {\n if (other === moving) continue;\n const directory = dirOf(other.file);\n const lines = linesLinkingTo(other.scan, directory, moving.file);\n if (lines.length === 0) continue;\n if (other.phase === 'archived' || !corpus.config.archiving.rewriteLinks) {\n const left = other.phase === 'archived' ? result.frozen : result.stale;\n for (const line of lines) left.push({ file: other.file, line: line + 1 });\n continue;\n }\n const rewritten = rewriteLinks(other.scan, directory, directory, (p) => (p === moving.file ? to : p));\n result.ops.push({ kind: 'write', path: other.file, content: encodeLike(other.source, rewritten.lines), before: other.source });\n result.rewritten.push(other.file);\n }\n return result;\n}\n\n/** Five items, and a count of the rest. */\nfunction listed(items: readonly string[]): string {\n return items.slice(0, 5).join(', ') + (items.length > 5 ? `, and ${items.length - 5} more` : '');\n}\n\n/**\n * Links live briefs will hold to nothing once the brief moves, when rewriting\n * is off: the move is what breaks them, so the move says where they are.\n */\nfunction staleLinks(corpus: Corpus, brief: Brief, stale: readonly Place[], strict: boolean, blocking: Finding[], warnings: Finding[]): void {\n const severity = configuredSeverity(corpus, 'stale-link');\n if (severity === null || stale.length === 0) return;\n const finding = problem(\n brief,\n 'stale-link',\n severity,\n 1,\n `links on ${stale.length} line(s) of other live briefs will stop resolving when it moves: ${listed(stale.map((s) => `${s.file}:${s.line}`))}`,\n 'turn \"archiving.rewriteLinks\" on to have them rewritten, or fix them by hand',\n );\n place(finding, strict, blocking, warnings);\n}\n\nfunction donePlan(action: Plan['action'], brief: Brief): Plan {\n return {\n action,\n brief,\n from: brief.file,\n to: brief.file,\n done: true,\n ops: [],\n blocking: [],\n warnings: [],\n linksRewritten: 0,\n inboundRewritten: [],\n inboundFrozen: [],\n banner: [],\n changes: [],\n };\n}\n\nexport function planArchive(corpus: Corpus, brief: Brief, request: ArchiveRequest): Plan {\n if (brief.phase === 'archived') return donePlan('archive', brief);\n const { config } = corpus;\n const archiveDir = normalisePath(config.archive);\n const to = within(archiveDir, brief.name);\n const blocking: Finding[] = [];\n const warnings: Finding[] = [];\n\n // Under --strict a warning is an error, here as in lint.\n const refuses = (finding: Finding): boolean =>\n finding.file === brief.file && (finding.severity === 'error' || (request.strict === true && finding.severity === 'warning'));\n blocking.push(...(request.findings?.filter(refuses) ?? []));\n // Only a status field can say \"draft\" or \"deferred\", so there is one to point at.\n const field = config.status.field as string;\n if (brief.status === 'draft') {\n blocking.push(\n problem(brief, 'archive-draft', 'error', lineOf(brief, field), 'is a draft, and a draft has not been executed', `set \"${field}: ${config.status.active}\" once the round runs`),\n );\n }\n if (brief.status === 'deferred') {\n blocking.push(\n problem(\n brief,\n 'archive-deferred',\n 'error',\n lineOf(brief, field),\n 'is deferred, and deferred work has not been executed',\n `set \"${field}: ${config.status.active}\" when its trigger fires and the round runs`,\n ),\n );\n }\n for (const task of openTasks(brief, corpus)) {\n blocking.push(\n problem(\n brief,\n 'open-task',\n 'error',\n task.line + 1,\n `\"${task.text === '' ? '(empty)' : task.text}\" is neither ticked nor dispositioned`,\n `tick it, or say why under it, as a bullet or as a paragraph after a blank line, starting ${config.archiving.dispositions.map((d) => `\"${d}\"`).join(', ')}`,\n ),\n );\n }\n for (const dependency of brief.dependsOn) {\n const target = resolveDependency(corpus, dependency);\n if (target !== undefined && target !== brief && target.phase === 'live') {\n blocking.push(\n problem(brief, 'dependency-open', 'error', lineOf(brief, 'dependsOn'), `depends on ${target.id ?? target.name}, which is not archived yet`, `archive ${target.id ?? target.name} first, or drop the dependency if it was never real`),\n );\n }\n }\n const bookkeeping = (path: string): boolean => isBriefPath(path, config);\n if (request.dirty !== undefined && request.allowDirty !== true) {\n const outside = request.dirty.filter((path) => !bookkeeping(path));\n if (outside.length > 0) {\n blocking.push(\n problem(brief, 'dirty-tree', 'error', 1, `the working tree has uncommitted changes outside the briefs: ${listed(outside)}`, 'commit them so the recorded commit holds the round, or pass --allow-dirty'),\n );\n }\n }\n\n const work = (request.changes ?? []).filter((change) => !bookkeeping(change.path));\n const protectedGlobs = globs(brief.protectedFiles);\n const affectedGlobs = globs(brief.affectedFiles);\n // Each protected file changed is its own defect - reverted, or ruled on,\n // one file at a time - so each is a finding that names its path.\n for (const change of work) {\n if (protectedGlobs.some((g) => matchGlob(g, change.path))) blocking.push(protectedFinding(brief, change.path));\n }\n // A protected file is reported once, as protected, and not again as out of scope.\n const unprotected = work.filter((c) => !protectedGlobs.some((g) => matchGlob(g, c.path)));\n const outside = affectedGlobs.length === 0 ? [] : unprotected.filter((c) => !affectedGlobs.some((g) => matchGlob(g, c.path)));\n if (outside.length > 0) {\n const finding = outOfScopeFinding(brief, outside.map((c) => c.path), request.strict === true);\n (request.strict === true ? blocking : warnings).push(finding);\n }\n const scopeSeverity = configuredSeverity(corpus, 'scope-unmeasured');\n const unmeasured = scopeSeverity === null ? null : unmeasuredScope(brief, request, scopeSeverity);\n if (unmeasured !== null) place(unmeasured, request.strict === true, blocking, warnings);\n if (corpus.briefs.some((b) => b.file === to)) {\n blocking.push(problem(brief, 'archive-exists', 'error', 1, `${to} already exists`, 'an archived brief is never overwritten'));\n }\n\n let lines: string[] = [...brief.lines];\n let linksRewritten = 0;\n if (config.archiving.rewriteLinks) {\n const rewritten = rewriteLinks(brief.scan, dirOf(brief.file), archiveDir, (p) => (p === brief.file ? to : p));\n lines = rewritten.lines;\n linksRewritten = rewritten.count;\n }\n lines = withoutBanner(lines, brief.banner);\n\n const pr = request.pr;\n const values: Record<string, string> = {\n date: request.date,\n summary: request.summary?.trim() ?? '',\n pr: pr === undefined ? '' : pr.url === null ? `#${pr.number}` : `[#${pr.number}](${pr.url})`,\n commit: request.commit?.sha.slice(0, 7) ?? '',\n diffstat: request.commit === undefined || request.changes === undefined ? '' : diffstat(request.changes),\n links:\n linksRewritten === 0\n ? ''\n : `Relative links were rewritten to resolve from \\`${archiveDir}/\\` (${linksRewritten}); no other word changed.`,\n id: brief.id ?? '',\n title: brief.title ?? '',\n author: request.commit?.author ?? '',\n };\n const banner = renderBanner(config.archiving.banner, values);\n if (banner.length > 0) lines = withBanner(lines, banner);\n const writes = writable(brief, lines, config.status.field !== null || config.archiving.freeze, blocking);\n if (writes && config.status.field !== null) {\n lines = setEntry(lines, readFrontMatter(lines), config.status.field, renderScalar(config.status.archived));\n }\n lines = removeEntry(lines, readFrontMatter(lines), INTEGRITY_FIELD);\n if (writes && config.archiving.freeze) lines = withIntegrity(lines);\n\n const incoming = inbound(corpus, brief, to);\n staleLinks(corpus, brief, incoming.stale, request.strict === true, blocking, warnings);\n return {\n action: 'archive',\n brief,\n from: brief.file,\n to,\n done: false,\n ops: [\n { kind: 'write', path: to, content: encodeLike(brief.source, lines), before: null },\n ...incoming.ops,\n { kind: 'remove', path: brief.file, before: brief.source },\n ],\n blocking,\n warnings,\n linksRewritten,\n inboundRewritten: incoming.rewritten,\n inboundFrozen: incoming.frozen,\n banner,\n changes: request.changes ?? [],\n };\n}\n\n/** A plugin's answer to a refusal it may lift: which rule, for which path, and why. */\nexport interface Waiver {\n readonly rule: string;\n readonly path: string;\n readonly reason: string;\n}\n\n/**\n * The refusals a plugin may lift. A tool that verifies a ruling can say a\n * protected file was allowed to change, or that a file outside the scope was;\n * whether a round is done is spec-brief's to say.\n */\nexport const WAIVABLE: readonly string[] = ['protected-file', 'out-of-scope'];\n\n/**\n * The plan with the refusals plugins waived turned into notes. A waiver\n * matches a blocking finding by rule and path: a protected-file finding is\n * replaced by the note, and an out-of-scope finding loses the path and goes\n * when none is left. A waiver that matches nothing changes nothing, and one\n * for any other rule is ignored with a warning, which refuses under --strict\n * as any warning does.\n */\nexport function applyWaivers(plan: Plan, waivers: readonly { readonly plugin: string; readonly waiver: Waiver }[], strict = false): Plan {\n const { brief } = plan;\n const blocking = [...plan.blocking];\n const warnings = [...plan.warnings];\n for (const { plugin, waiver } of waivers) {\n if (!WAIVABLE.includes(waiver.rule)) {\n const ignored = problem(\n brief,\n 'waiver-ignored',\n 'warning',\n 1,\n `${plugin} asked to waive ${waiver.rule} for ${waiver.path}; a plugin may waive only ${WAIVABLE.join(' and ')}`,\n `report it to the plugin's authors: ${waiver.rule} is spec-brief's to decide`,\n );\n place(ignored, strict, blocking, warnings);\n continue;\n }\n const at = blocking.findIndex((f) => f.rule === waiver.rule && (f.path === waiver.path || f.paths?.includes(waiver.path) === true));\n if (at < 0) continue;\n const found = blocking[at] as Finding;\n const rest = (found.paths ?? []).filter((p) => p !== waiver.path);\n blocking.splice(at, 1, ...(rest.length > 0 ? [outOfScopeFinding(brief, rest, true)] : []));\n warnings.push({\n ...problem(brief, 'waived', 'note', found.line, `${plugin} waives ${waiver.rule} for ${waiver.path}: ${waiver.reason}`, 'review the waiver with the round; it stands where the refusal was'),\n path: waiver.path,\n });\n }\n return { ...plan, blocking, warnings };\n}\n\nexport interface UnarchiveRequest {\n /** Warnings refuse the reopening, as they fail lint. */\n readonly strict?: boolean | undefined;\n}\n\n/**\n * Reopens an archived brief: the banner and the freeze come off, the status\n * goes back to the live word, and the links are rewritten for the directory\n * it returns to. What the round wrote stays in history, where it belongs.\n */\nexport function planUnarchive(corpus: Corpus, brief: Brief, request: UnarchiveRequest = {}): Plan {\n if (brief.phase === 'live') return donePlan('unarchive', brief);\n const { config } = corpus;\n const briefsDir = normalisePath(config.briefs);\n const to = within(briefsDir, brief.name);\n const blocking: Finding[] = [];\n const warnings: Finding[] = [];\n if (corpus.briefs.some((b) => b.file === to)) {\n blocking.push(problem(brief, 'unarchive-exists', 'error', 1, `${to} already exists`, 'rename one of them first'));\n }\n\n let lines: string[] = [...brief.lines];\n let linksRewritten = 0;\n if (config.archiving.rewriteLinks) {\n const rewritten = rewriteLinks(brief.scan, dirOf(brief.file), briefsDir, (p) => (p === brief.file ? to : p));\n lines = rewritten.lines;\n linksRewritten = rewritten.count;\n }\n lines = withoutBanner(lines, brief.banner);\n lines = removeEntry(lines, readFrontMatter(lines), INTEGRITY_FIELD);\n const field = config.status.field;\n if (writable(brief, lines, field !== null, blocking) && field !== null) {\n lines = setEntry(lines, readFrontMatter(lines), field, renderScalar(config.status.active));\n }\n // Archival gives a brief with no front matter a block to hold its hash.\n // A block this reopening emptied goes too, and the brief is the one that\n // was archived. One that was empty before it was archived reads the same\n // once the hash is in it, and goes with it; one empty in the archive stays.\n // No edit above reaches the opening line, so a brief that had a block has\n // one still, and only a YAML block has lost a line.\n const had = brief.frontMatter;\n const emptied = had !== null && had.close > 1 && (readFrontMatter(lines) as FrontMatter).close === 1;\n if (emptied) lines = lines.slice(2);\n\n const incoming = inbound(corpus, brief, to);\n staleLinks(corpus, brief, incoming.stale, request.strict === true, blocking, warnings);\n return {\n action: 'unarchive',\n brief,\n from: brief.file,\n to,\n done: false,\n ops: [\n { kind: 'write', path: to, content: encodeLike(brief.source, lines), before: null },\n ...incoming.ops,\n { kind: 'remove', path: brief.file, before: brief.source },\n ],\n blocking,\n warnings,\n linksRewritten,\n inboundRewritten: incoming.rewritten,\n inboundFrozen: incoming.frozen,\n banner: [],\n changes: [],\n };\n}\n"]}
|
package/dist/brief.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brief.js","sourceRoot":"","sources":["../src/brief.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One brief, read: its identity, its front matter, its sections and its task\n * items. A pure function of a file's path and text.\n */\n\nimport type { Config } from './config.js';\nimport { findEntry, isNull, keyName, readFrontMatter, type FrontMatter, type FrontMatterEntry, type YamlValue } from './frontmatter.js';\nimport { scan, sectionsOf, titleOf, type Scan, type Section, type TaskItem } from './markdown.js';\nimport { splitLines, stripBom } from './text.js';\nimport type { Phase, Status } from './types.js';\n\nexport const BANNER_OPEN = '<!-- spec-brief:banner -->';\nexport const BANNER_CLOSE = '<!-- /spec-brief:banner -->';\n\n/** Front-matter keys spec-brief itself reads, in the spelling it documents. */\nexport const BUILT_IN_FIELDS: readonly string[] = [\n 'id',\n 'title',\n 'type',\n 'status',\n 'date',\n 'wave',\n 'dependsOn',\n 'affectedFiles',\n 'protectedFiles',\n 'trigger',\n 'integrity',\n];\n\nexport interface FieldProblem {\n readonly field: string;\n /** 0-based line. */\n readonly line: number;\n readonly message: string;\n}\n\nexport interface Brief {\n /** `null` when no id can be read, which a rule reports. */\n readonly id: string | null;\n /** Repository-relative path. */\n readonly file: string;\n /** The file name. */\n readonly name: string;\n readonly phase: Phase;\n /** The file exactly as read, byte-order mark and line endings included. */\n readonly source: string;\n /** The text parsed: the source without a byte-order mark. */\n readonly text: string;\n readonly lines: readonly string[];\n readonly frontMatter: FrontMatter | null;\n /** 0-based first line after the front matter. */\n readonly bodyStart: number;\n readonly scan: Scan;\n readonly sections: readonly Section[];\n readonly tasks: readonly TaskItem[];\n readonly title: string | null;\n readonly status: Status | null;\n readonly statusWord: string | null;\n readonly type: string | null;\n readonly wave: number | null;\n readonly dependsOn: readonly string[];\n readonly affectedFiles: readonly string[];\n readonly protectedFiles: readonly string[];\n /** For deferred work: the observable event that brings it back. */\n readonly trigger: string | null;\n readonly integrity: string | null;\n /** The frozen banner's lines, markers included, end exclusive. */\n readonly banner: { readonly start: number; readonly end: number } | null;\n readonly problems: readonly FieldProblem[];\n}\n\nfunction valueText(value: YamlValue): string | null | { readonly problem: string } {\n if (value.kind === 'unsupported') return { problem: value.reason };\n if (value.kind === 'list') return { problem: 'must be a single value, not a list' };\n return isNull(value.scalar) ? null : value.scalar.text;\n}\n\nfunction valueList(value: YamlValue): string[] | { readonly problem: string } {\n if (value.kind === 'unsupported') return { problem: value.reason };\n if (value.kind === 'scalar') return isNull(value.scalar) ? [] : [value.scalar.text];\n const empty = value.items.find((item) => isNull(item) || item.text.trim() === '');\n if (empty !== undefined) return { problem: 'must not contain an empty item' };\n return value.items.map((item) => item.text.trim());\n}\n\n/** The id a file name carries: everything before the separator, or the whole stem. */\nexport function idFromName(name: string, separator: string): string {\n const stem = name.replace(/\\.md$/i, '');\n const at = stem.indexOf(separator);\n return at > 0 ? stem.slice(0, at) : stem;\n}\n\nfunction statusFrom(word: string | null, config: Config, phase: Phase): Status | null {\n if (config.status.field === null) return phase === 'archived' ? 'archived' : 'active';\n if (word === null) return null;\n const lower = word.toLowerCase();\n if (lower === config.status.archived.toLowerCase()) return 'archived';\n if (lower === config.status.active.toLowerCase()) return 'active';\n if (config.status.draft !== null && lower === config.status.draft.toLowerCase()) return 'draft';\n if (config.status.deferred !== null && lower === config.status.deferred.toLowerCase()) return 'deferred';\n return null;\n}\n\nexport function parseBrief(file: string, text: string, config: Config, phase: Phase): Brief {\n const content = stripBom(text);\n const lines = splitLines(content);\n const frontMatter = readFrontMatter(lines);\n // A block never closed has `close` -1: the body starts at the top, as with no block.\n const bodyStart = frontMatter === null ? 0 : frontMatter.close + 1;\n const scanned = scan(lines);\n const problems: FieldProblem[] = [];\n const name = file.slice(file.lastIndexOf('/') + 1);\n\n const text1 = (field: string): string | null => {\n const entry = findEntry(frontMatter, field);\n if (entry === undefined) return null;\n const value = valueText(entry.value);\n if (value !== null && typeof value === 'object') {\n problems.push({ field, line: entry.line, message: `\"${entry.key}\" ${value.problem}` });\n return null;\n }\n return value;\n };\n const list = (field: string): string[] => {\n const entry = findEntry(frontMatter, field);\n if (entry === undefined) return [];\n const value = valueList(entry.value);\n if (!Array.isArray(value)) {\n problems.push({ field, line: entry.line, message: `\"${entry.key}\" ${value.problem}` });\n return [];\n }\n return value;\n };\n\n const waveText = text1('wave');\n let wave: number | null = null;\n if (waveText !== null) {\n // Text was read, so there is an entry, and its value is a scalar.\n const waveEntry = findEntry(frontMatter, 'wave') as FrontMatterEntry;\n const { quoted } = (waveEntry.value as Extract<YamlValue, { kind: 'scalar' }>).scalar;\n if (!quoted && /^\\d{1,9}$/.test(waveText)) wave = Number(waveText);\n else problems.push({ field: 'wave', line: waveEntry.line, message: `\"wave\" must be a whole number, not \"${waveText}\"` });\n }\n\n const statusWord = config.status.field === null ? null : text1(config.status.field);\n const frontTitle = text1('title');\n const heading = titleOf(scanned);\n const id = config.id.source === 'filename' ? idFromName(name, config.id.separator) : text1('id');\n\n // A marker is a comment on a line of its own. Quoted in a code block it is\n // text: the prose mask keeps code and blanks comments, so a real marker is\n // a line whose prose is empty.\n const marker = (line: number, text: string): boolean =>\n (lines[line] as string).trim() === text && (scanned.prose[line] as string).trim() === '';\n let banner: Brief['banner'] = null;\n const open = lines.findIndex((_, i) => i >= bodyStart && marker(i, BANNER_OPEN));\n if (open >= 0) {\n // The opening line is no closing marker, so the search could start on it and find the same.\n const close = lines.findIndex((_, i) => i > open && marker(i, BANNER_CLOSE));\n if (close !== -1) banner = { start: open, end: close + 1 };\n }\n\n return {\n id: id === null || id.trim() === '' ? null : id.trim(),\n file,\n name,\n phase,\n source: text,\n text: content,\n lines,\n frontMatter,\n bodyStart,\n scan: scanned,\n sections: sectionsOf(scanned),\n tasks: scanned.tasks,\n title: frontTitle ?? (heading === undefined || heading.text === '' ? null : heading.text),\n status: statusFrom(statusWord, config, phase),\n statusWord,\n type: text1('type'),\n wave,\n dependsOn: list('dependsOn'),\n affectedFiles: list('affectedFiles'),\n protectedFiles: list('protectedFiles'),\n trigger: text1('trigger'),\n integrity: text1('integrity'),\n banner,\n problems,\n };\n}\n\n/** The 0-based line a front-matter key is declared on, or the first line when it is absent. */\nexport function lineOfField(brief: Brief, field: string): number {\n return findEntry(brief.frontMatter, field)?.line ?? 0;\n}\n\n/** Keys spec-brief knows, compared the way front matter compares them. */\nexport function knownFields(config: Config): Set<string> {\n const names = [...BUILT_IN_FIELDS, ...config.fields];\n if (config.status.field !== null) names.push(config.status.field);\n return new Set(names.map(keyName));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"brief.js","sourceRoot":"","sources":["../src/brief.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One brief, read: its identity, its front matter, its sections and its task\n * items. A pure function of a file's path and text.\n */\n\nimport type { Config } from './config.js';\nimport { findEntry, isNull, keyName, readFrontMatter, type FrontMatter, type YamlValue } from './frontmatter.js';\nimport { scan, sectionsOf, titleOf, type Scan, type Section, type TaskItem } from './markdown.js';\nimport { splitLines, stripBom } from './text.js';\nimport type { Phase, Status } from './types.js';\n\nexport const BANNER_OPEN = '<!-- spec-brief:banner -->';\nexport const BANNER_CLOSE = '<!-- /spec-brief:banner -->';\n\n/** Front-matter keys spec-brief itself reads, in the spelling it documents. */\nexport const BUILT_IN_FIELDS: readonly string[] = [\n 'id',\n 'title',\n 'type',\n 'status',\n 'date',\n 'wave',\n 'dependsOn',\n 'affectedFiles',\n 'protectedFiles',\n 'trigger',\n 'integrity',\n];\n\nexport interface FieldProblem {\n readonly field: string;\n /** 0-based line. */\n readonly line: number;\n readonly message: string;\n}\n\nexport interface Brief {\n /** `null` when no id can be read, which a rule reports. */\n readonly id: string | null;\n /** Repository-relative path. */\n readonly file: string;\n /** The file name. */\n readonly name: string;\n readonly phase: Phase;\n /** The file exactly as read, byte-order mark and line endings included. */\n readonly source: string;\n /** The text parsed: the source without a byte-order mark. */\n readonly text: string;\n readonly lines: readonly string[];\n readonly frontMatter: FrontMatter | null;\n /** 0-based first line after the front matter. */\n readonly bodyStart: number;\n readonly scan: Scan;\n readonly sections: readonly Section[];\n readonly tasks: readonly TaskItem[];\n readonly title: string | null;\n readonly status: Status | null;\n readonly statusWord: string | null;\n readonly type: string | null;\n readonly wave: number | null;\n readonly dependsOn: readonly string[];\n readonly affectedFiles: readonly string[];\n readonly protectedFiles: readonly string[];\n /** For deferred work: the observable event that brings it back. */\n readonly trigger: string | null;\n readonly integrity: string | null;\n /** The frozen banner's lines, markers included, end exclusive. */\n readonly banner: { readonly start: number; readonly end: number } | null;\n readonly problems: readonly FieldProblem[];\n}\n\nfunction valueText(value: YamlValue): string | null | { readonly problem: string } {\n if (value.kind === 'unsupported') return { problem: value.reason };\n if (value.kind === 'list') return { problem: 'must be a single value, not a list' };\n return isNull(value.scalar) ? null : value.scalar.text;\n}\n\nfunction valueList(value: YamlValue): string[] | { readonly problem: string } {\n if (value.kind === 'unsupported') return { problem: value.reason };\n if (value.kind === 'scalar') return isNull(value.scalar) ? [] : [value.scalar.text];\n const empty = value.items.find((item) => isNull(item) || item.text.trim() === '');\n if (empty !== undefined) return { problem: 'must not contain an empty item' };\n return value.items.map((item) => item.text.trim());\n}\n\n/** The id a file name carries: everything before the separator, or the whole stem. */\nexport function idFromName(name: string, separator: string): string {\n const stem = name.replace(/\\.md$/i, '');\n const at = stem.indexOf(separator);\n return at > 0 ? stem.slice(0, at) : stem;\n}\n\nfunction statusFrom(word: string | null, config: Config, phase: Phase): Status | null {\n if (config.status.field === null) return phase === 'archived' ? 'archived' : 'active';\n if (word === null) return null;\n const lower = word.toLowerCase();\n if (lower === config.status.archived.toLowerCase()) return 'archived';\n if (lower === config.status.active.toLowerCase()) return 'active';\n if (config.status.draft !== null && lower === config.status.draft.toLowerCase()) return 'draft';\n if (config.status.deferred !== null && lower === config.status.deferred.toLowerCase()) return 'deferred';\n return null;\n}\n\nexport function parseBrief(file: string, text: string, config: Config, phase: Phase): Brief {\n const content = stripBom(text);\n const lines = splitLines(content);\n const frontMatter = readFrontMatter(lines);\n // A block never closed has `close` -1: the body starts at the top, as with no block.\n const bodyStart = frontMatter === null ? 0 : frontMatter.close + 1;\n const scanned = scan(lines);\n const problems: FieldProblem[] = [];\n const name = file.slice(file.lastIndexOf('/') + 1);\n\n const text1 = (field: string): string | null => {\n const entry = findEntry(frontMatter, field);\n if (entry === undefined) return null;\n const value = valueText(entry.value);\n if (value !== null && typeof value === 'object') {\n problems.push({ field, line: entry.line, message: `\"${entry.key}\" ${value.problem}` });\n return null;\n }\n return value;\n };\n const list = (field: string): string[] => {\n const entry = findEntry(frontMatter, field);\n if (entry === undefined) return [];\n const value = valueList(entry.value);\n if (!Array.isArray(value)) {\n problems.push({ field, line: entry.line, message: `\"${entry.key}\" ${value.problem}` });\n return [];\n }\n return value;\n };\n\n const waveText = text1('wave');\n let wave: number | null = null;\n if (waveText !== null) {\n // Text was read, so there is an entry, and its value is a scalar.\n const waveEntry = findEntry(frontMatter, 'wave')!;\n const { quoted } = (waveEntry.value as Extract<YamlValue, { kind: 'scalar' }>).scalar;\n if (!quoted && /^\\d{1,9}$/.test(waveText)) wave = Number(waveText);\n else problems.push({ field: 'wave', line: waveEntry.line, message: `\"wave\" must be a whole number, not \"${waveText}\"` });\n }\n\n const statusWord = config.status.field === null ? null : text1(config.status.field);\n const frontTitle = text1('title');\n const heading = titleOf(scanned);\n const id = config.id.source === 'filename' ? idFromName(name, config.id.separator) : text1('id');\n\n // A marker is a comment on a line of its own. Quoted in a code block it is\n // text: the prose mask keeps code and blanks comments, so a real marker is\n // a line whose prose is empty.\n const marker = (line: number, text: string): boolean =>\n (lines[line] as string).trim() === text && (scanned.prose[line] as string).trim() === '';\n let banner: Brief['banner'] = null;\n const open = lines.findIndex((_, i) => i >= bodyStart && marker(i, BANNER_OPEN));\n if (open >= 0) {\n // The opening line is no closing marker, so the search could start on it and find the same.\n const close = lines.findIndex((_, i) => i > open && marker(i, BANNER_CLOSE));\n if (close !== -1) banner = { start: open, end: close + 1 };\n }\n\n return {\n id: id === null || id.trim() === '' ? null : id.trim(),\n file,\n name,\n phase,\n source: text,\n text: content,\n lines,\n frontMatter,\n bodyStart,\n scan: scanned,\n sections: sectionsOf(scanned),\n tasks: scanned.tasks,\n title: frontTitle ?? (heading === undefined || heading.text === '' ? null : heading.text),\n status: statusFrom(statusWord, config, phase),\n statusWord,\n type: text1('type'),\n wave,\n dependsOn: list('dependsOn'),\n affectedFiles: list('affectedFiles'),\n protectedFiles: list('protectedFiles'),\n trigger: text1('trigger'),\n integrity: text1('integrity'),\n banner,\n problems,\n };\n}\n\n/** The 0-based line a front-matter key is declared on, or the first line when it is absent. */\nexport function lineOfField(brief: Brief, field: string): number {\n return findEntry(brief.frontMatter, field)?.line ?? 0;\n}\n\n/** Keys spec-brief knows, compared the way front matter compares them. */\nexport function knownFields(config: Config): Set<string> {\n const names = [...BUILT_IN_FIELDS, ...config.fields];\n if (config.status.field !== null) names.push(config.status.field);\n return new Set(names.map(keyName));\n}\n"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -24,12 +24,29 @@ export interface CliIO {
|
|
|
24
24
|
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
25
25
|
}
|
|
26
26
|
type Values = Record<string, string | boolean | undefined>;
|
|
27
|
+
/**
|
|
28
|
+
* A resolved path as two values of one option compare. On Windows a drive
|
|
29
|
+
* letter names its volume in either case, and a path resolved there starts
|
|
30
|
+
* with its drive letter or a backslash, so its first character is folded;
|
|
31
|
+
* the rest is compared as resolved (spec-core ADR-0005, amended 2026-10-19).
|
|
32
|
+
* A path written `\\?\c:\x` keeps its letter as written.
|
|
33
|
+
*/
|
|
34
|
+
export declare function onVolume(path: string, platform?: string): string;
|
|
27
35
|
export declare const HELP: string;
|
|
28
36
|
interface Parsed {
|
|
29
37
|
readonly command: string | undefined;
|
|
30
38
|
readonly values: Values;
|
|
31
39
|
readonly positionals: readonly string[];
|
|
40
|
+
/** Each option's revisions as they were written, where two are written two ways, for git to read. */
|
|
41
|
+
readonly revisions: ReadonlyMap<string, readonly string[]>;
|
|
32
42
|
}
|
|
33
|
-
|
|
43
|
+
/**
|
|
44
|
+
* The line, read and checked. Everything the line alone decides is refused
|
|
45
|
+
* here, before `--help` and `--version` are answered, as an option the
|
|
46
|
+
* parser does not know always was: a wrong line is wrong with either of them
|
|
47
|
+
* on it (spec-core ADR-0005, amended 2026-10-18). `cwd` is the directory a
|
|
48
|
+
* run without `--root` starts in, from which a `--config` is found.
|
|
49
|
+
*/
|
|
50
|
+
export declare function parse(argv: readonly string[], cwd?: string): Parsed;
|
|
34
51
|
export declare function main(argv?: readonly string[], io?: CliIO): Promise<number>;
|
|
35
52
|
export {};
|