@navbook/cli 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/complete.js +124 -0
- package/dist/commands/complete.js.map +1 -0
- package/dist/{cli/commands → commands}/compose.js +5 -3
- package/dist/commands/compose.js.map +1 -0
- package/dist/commands/doctor.js +56 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/entity.js +235 -0
- package/dist/commands/entity.js.map +1 -0
- package/dist/commands/feature.js +202 -0
- package/dist/commands/feature.js.map +1 -0
- package/dist/commands/init.js +23 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/{cli/commands → commands}/install.js +1 -2
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/issue.js +89 -0
- package/dist/commands/issue.js.map +1 -0
- package/dist/commands/policy.js +49 -0
- package/dist/commands/policy.js.map +1 -0
- package/dist/commands/pr.js +262 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/context.js +21 -0
- package/dist/context.js.map +1 -0
- package/dist/{cli/editor.js → editor.js} +1 -1
- package/dist/editor.js.map +1 -0
- package/dist/errors.js.map +1 -0
- package/dist/install/completions.js.map +1 -0
- package/dist/{cli/install → install}/hook.js +1 -1
- package/dist/install/hook.js.map +1 -0
- package/dist/{cli/main.js → main.js} +10 -0
- package/dist/main.js.map +1 -0
- package/dist/{cli/program.js → program.js} +161 -23
- package/dist/program.js.map +1 -0
- package/dist/{cli/prompt.js → prompt.js} +11 -0
- package/dist/prompt.js.map +1 -0
- package/dist/render/colors.js.map +1 -0
- package/dist/render/detail.js +197 -0
- package/dist/render/detail.js.map +1 -0
- package/dist/render/table.js.map +1 -0
- package/dist/sort.js +77 -0
- package/dist/sort.js.map +1 -0
- package/package.json +15 -21
- package/README.md +0 -165
- package/dist/cli/commands/complete.d.ts +0 -9
- package/dist/cli/commands/complete.js +0 -72
- package/dist/cli/commands/complete.js.map +0 -1
- package/dist/cli/commands/compose.d.ts +0 -27
- package/dist/cli/commands/compose.js.map +0 -1
- package/dist/cli/commands/doctor.d.ts +0 -14
- package/dist/cli/commands/doctor.js +0 -127
- package/dist/cli/commands/doctor.js.map +0 -1
- package/dist/cli/commands/entity.d.ts +0 -55
- package/dist/cli/commands/entity.js +0 -209
- package/dist/cli/commands/entity.js.map +0 -1
- package/dist/cli/commands/init.d.ts +0 -11
- package/dist/cli/commands/init.js +0 -39
- package/dist/cli/commands/init.js.map +0 -1
- package/dist/cli/commands/install.d.ts +0 -17
- package/dist/cli/commands/install.js.map +0 -1
- package/dist/cli/commands/issue.d.ts +0 -12
- package/dist/cli/commands/issue.js +0 -42
- package/dist/cli/commands/issue.js.map +0 -1
- package/dist/cli/commands/pr.d.ts +0 -64
- package/dist/cli/commands/pr.js +0 -466
- package/dist/cli/commands/pr.js.map +0 -1
- package/dist/cli/commit-flow.d.ts +0 -27
- package/dist/cli/commit-flow.js +0 -47
- package/dist/cli/commit-flow.js.map +0 -1
- package/dist/cli/context.d.ts +0 -39
- package/dist/cli/context.js +0 -93
- package/dist/cli/context.js.map +0 -1
- package/dist/cli/editor.d.ts +0 -23
- package/dist/cli/editor.js.map +0 -1
- package/dist/cli/errors.d.ts +0 -17
- package/dist/cli/errors.js.map +0 -1
- package/dist/cli/history-checks.d.ts +0 -21
- package/dist/cli/history-checks.js +0 -134
- package/dist/cli/history-checks.js.map +0 -1
- package/dist/cli/install/completions.d.ts +0 -19
- package/dist/cli/install/completions.js.map +0 -1
- package/dist/cli/install/hook.d.ts +0 -20
- package/dist/cli/install/hook.js.map +0 -1
- package/dist/cli/main.d.ts +0 -14
- package/dist/cli/main.js.map +0 -1
- package/dist/cli/program.d.ts +0 -23
- package/dist/cli/program.js.map +0 -1
- package/dist/cli/prompt.d.ts +0 -22
- package/dist/cli/prompt.js.map +0 -1
- package/dist/cli/render/colors.d.ts +0 -13
- package/dist/cli/render/colors.js.map +0 -1
- package/dist/cli/render/detail.d.ts +0 -10
- package/dist/cli/render/detail.js +0 -105
- package/dist/cli/render/detail.js.map +0 -1
- package/dist/cli/render/table.d.ts +0 -19
- package/dist/cli/render/table.js.map +0 -1
- package/dist/cli/resolve.d.ts +0 -17
- package/dist/cli/resolve.js +0 -68
- package/dist/cli/resolve.js.map +0 -1
- package/dist/cli/workspace.d.ts +0 -52
- package/dist/cli/workspace.js +0 -178
- package/dist/cli/workspace.js.map +0 -1
- package/dist/core/comments.d.ts +0 -31
- package/dist/core/comments.js +0 -80
- package/dist/core/comments.js.map +0 -1
- package/dist/core/files.d.ts +0 -88
- package/dist/core/files.js +0 -441
- package/dist/core/files.js.map +0 -1
- package/dist/core/frontmatter.d.ts +0 -63
- package/dist/core/frontmatter.js +0 -149
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/id.d.ts +0 -46
- package/dist/core/id.js +0 -66
- package/dist/core/id.js.map +0 -1
- package/dist/core/index.d.ts +0 -19
- package/dist/core/index.js +0 -20
- package/dist/core/index.js.map +0 -1
- package/dist/core/json.d.ts +0 -18
- package/dist/core/json.js +0 -51
- package/dist/core/json.js.map +0 -1
- package/dist/core/ops.d.ts +0 -92
- package/dist/core/ops.js +0 -173
- package/dist/core/ops.js.map +0 -1
- package/dist/core/person.d.ts +0 -20
- package/dist/core/person.js +0 -50
- package/dist/core/person.js.map +0 -1
- package/dist/core/query.d.ts +0 -30
- package/dist/core/query.js +0 -106
- package/dist/core/query.js.map +0 -1
- package/dist/core/refs.d.ts +0 -12
- package/dist/core/refs.js +0 -36
- package/dist/core/refs.js.map +0 -1
- package/dist/core/slug.d.ts +0 -22
- package/dist/core/slug.js +0 -40
- package/dist/core/slug.js.map +0 -1
- package/dist/core/time.d.ts +0 -14
- package/dist/core/time.js +0 -37
- package/dist/core/time.js.map +0 -1
- package/dist/core/tree.d.ts +0 -94
- package/dist/core/tree.js +0 -237
- package/dist/core/tree.js.map +0 -1
- package/dist/core/validate.d.ts +0 -55
- package/dist/core/validate.js +0 -312
- package/dist/core/validate.js.map +0 -1
- package/dist/git/config.d.ts +0 -12
- package/dist/git/config.js +0 -27
- package/dist/git/config.js.map +0 -1
- package/dist/git/exec.d.ts +0 -35
- package/dist/git/exec.js +0 -58
- package/dist/git/exec.js.map +0 -1
- package/dist/git/history.d.ts +0 -35
- package/dist/git/history.js +0 -82
- package/dist/git/history.js.map +0 -1
- package/dist/git/index-ops.d.ts +0 -20
- package/dist/git/index-ops.js +0 -45
- package/dist/git/index-ops.js.map +0 -1
- package/dist/git/merge.d.ts +0 -27
- package/dist/git/merge.js +0 -57
- package/dist/git/merge.js.map +0 -1
- package/dist/git/refscan.d.ts +0 -32
- package/dist/git/refscan.js +0 -82
- package/dist/git/refscan.js.map +0 -1
- package/dist/git/repo.d.ts +0 -45
- package/dist/git/repo.js +0 -95
- package/dist/git/repo.js.map +0 -1
- /package/dist/{cli/errors.js → errors.js} +0 -0
- /package/dist/{cli/install → install}/completions.js +0 -0
- /package/dist/{cli/render → render}/colors.js +0 -0
- /package/dist/{cli/render → render}/table.js +0 -0
package/dist/core/frontmatter.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* YAML frontmatter — spec 02 §2.4.
|
|
3
|
-
*
|
|
4
|
-
* Every Navbook file is UTF-8 Markdown that begins, at byte 0, with a `---`
|
|
5
|
-
* delimited YAML block. Unknown keys MUST be preserved when a tool rewrites a
|
|
6
|
-
* file, so this module is built on the `yaml` package's Document API (which
|
|
7
|
-
* keeps key order and comments) and additionally replays the original YAML text
|
|
8
|
-
* verbatim whenever nothing was actually changed.
|
|
9
|
-
*/
|
|
10
|
-
import { Document, isMap, isScalar, isSeq, parseDocument } from "yaml";
|
|
11
|
-
export class FrontmatterError extends Error {
|
|
12
|
-
}
|
|
13
|
-
const DELIMITER = /^---[ \t]*\r?$/;
|
|
14
|
-
/** Split a Navbook file into its YAML block and its body. */
|
|
15
|
-
export function splitFrontmatter(text) {
|
|
16
|
-
const lines = text.split("\n");
|
|
17
|
-
if (!DELIMITER.test(lines[0] ?? "")) {
|
|
18
|
-
throw new FrontmatterError("file must start with a '---' frontmatter delimiter at byte 0");
|
|
19
|
-
}
|
|
20
|
-
for (let i = 1; i < lines.length; i++) {
|
|
21
|
-
if (DELIMITER.test(lines[i])) {
|
|
22
|
-
const yaml = lines.slice(1, i).join("\n");
|
|
23
|
-
const body = lines.slice(i + 1).join("\n");
|
|
24
|
-
return { yaml: yaml === "" ? "" : `${yaml}\n`, body };
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
throw new FrontmatterError("frontmatter block is not closed by a '---' line");
|
|
28
|
-
}
|
|
29
|
-
/** Parse a Navbook file into a {@link NavDoc}. Throws only on a missing block. */
|
|
30
|
-
export function parseDoc(text) {
|
|
31
|
-
const { yaml, body } = splitFrontmatter(text);
|
|
32
|
-
const doc = parseDocument(yaml, { keepSourceTokens: false });
|
|
33
|
-
const errors = doc.errors.map((e) => e.message);
|
|
34
|
-
return { doc, rawYaml: yaml, body, dirty: false, errors };
|
|
35
|
-
}
|
|
36
|
-
/** Build a fresh document with no keys and an empty body. */
|
|
37
|
-
export function emptyDoc() {
|
|
38
|
-
const doc = new Document({});
|
|
39
|
-
return { doc, rawYaml: "", body: "", dirty: true, errors: [] };
|
|
40
|
-
}
|
|
41
|
-
/** Serialize a {@link NavDoc} back to file text. */
|
|
42
|
-
export function serializeDoc(nav) {
|
|
43
|
-
const yaml = nav.dirty ? serializeYaml(nav.doc) : nav.rawYaml;
|
|
44
|
-
return `---\n${yaml}---\n${nav.body}`;
|
|
45
|
-
}
|
|
46
|
-
function serializeYaml(doc) {
|
|
47
|
-
if (doc.errors.length > 0) {
|
|
48
|
-
// The YAML parser refuses to stringify a document it could not parse, and
|
|
49
|
-
// a caller rewriting frontmatter would otherwise get its bare message.
|
|
50
|
-
throw new FrontmatterError(`frontmatter is not valid YAML and cannot be rewritten: ${doc.errors[0]?.message ?? "parse error"}`);
|
|
51
|
-
}
|
|
52
|
-
if (doc.contents === null || doc.contents === undefined)
|
|
53
|
-
return "";
|
|
54
|
-
if (isMap(doc.contents) && doc.contents.items.length === 0)
|
|
55
|
-
return "";
|
|
56
|
-
const text = doc.toString({
|
|
57
|
-
lineWidth: 0,
|
|
58
|
-
defaultKeyType: "PLAIN",
|
|
59
|
-
flowCollectionPadding: false,
|
|
60
|
-
});
|
|
61
|
-
return text.endsWith("\n") ? text : `${text}\n`;
|
|
62
|
-
}
|
|
63
|
-
/** All frontmatter as plain JavaScript values (unknown keys included). */
|
|
64
|
-
export function toPlain(nav) {
|
|
65
|
-
const value = nav.doc.toJS({ maxAliasCount: 100 });
|
|
66
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
67
|
-
? value
|
|
68
|
-
: {};
|
|
69
|
-
}
|
|
70
|
-
const NULL_SOURCES = new Set(["", "~", "null", "Null", "NULL"]);
|
|
71
|
-
/**
|
|
72
|
-
* Read a scalar as the string the author wrote.
|
|
73
|
-
*
|
|
74
|
-
* YAML resolves some strings to other types — an all-digit commit SHA becomes a
|
|
75
|
-
* (lossy) number, `title: 42` becomes an integer. Recovering the scalar's source
|
|
76
|
-
* text keeps those hand-written files usable instead of merely diagnosable.
|
|
77
|
-
*/
|
|
78
|
-
export function stringAt(nav, path) {
|
|
79
|
-
const node = path.length === 1 ? nav.doc.get(path[0], true) : nav.doc.getIn(path, true);
|
|
80
|
-
if (node === undefined || node === null)
|
|
81
|
-
return undefined;
|
|
82
|
-
if (!isScalar(node))
|
|
83
|
-
return undefined;
|
|
84
|
-
if (typeof node.value === "string")
|
|
85
|
-
return node.value;
|
|
86
|
-
const source = node.source;
|
|
87
|
-
if (node.value === null)
|
|
88
|
-
return source !== undefined && NULL_SOURCES.has(source) ? undefined : source;
|
|
89
|
-
return source ?? String(node.value);
|
|
90
|
-
}
|
|
91
|
-
/** Number of items in a sequence at `path`, or null when it is not a sequence. */
|
|
92
|
-
export function seqLength(nav, path) {
|
|
93
|
-
const node = path.length === 1 ? nav.doc.get(path[0], true) : nav.doc.getIn(path, true);
|
|
94
|
-
return isSeq(node) ? node.items.length : null;
|
|
95
|
-
}
|
|
96
|
-
/** True when the frontmatter has the key at all (even with a null value). */
|
|
97
|
-
export function hasKey(nav, key) {
|
|
98
|
-
return isMap(nav.doc.contents) && nav.doc.has(key);
|
|
99
|
-
}
|
|
100
|
-
/** Ordered list of frontmatter keys, as they appear in the file. */
|
|
101
|
-
export function keysInOrder(nav) {
|
|
102
|
-
if (!isMap(nav.doc.contents))
|
|
103
|
-
return [];
|
|
104
|
-
return nav.doc.contents.items.map((item) => String(item.key?.value ?? ""));
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Set or delete frontmatter keys. A value of `undefined` deletes the key; new
|
|
108
|
-
* keys are appended after the existing ones so hand-authored ordering survives.
|
|
109
|
-
*/
|
|
110
|
-
export function patchDoc(nav, changes) {
|
|
111
|
-
for (const [key, value] of Object.entries(changes)) {
|
|
112
|
-
if (value === undefined) {
|
|
113
|
-
if (nav.doc.has(key)) {
|
|
114
|
-
nav.doc.delete(key);
|
|
115
|
-
nav.dirty = true;
|
|
116
|
-
}
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
nav.doc.set(key, value);
|
|
120
|
-
nav.dirty = true;
|
|
121
|
-
}
|
|
122
|
-
return nav;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Set a list of plain scalars in flow style (`labels: [bug, auth]`), matching
|
|
126
|
-
* the spec's own examples. Flow scalar sequences are inside the conservative
|
|
127
|
-
* YAML subset of spec 05 §5.3.
|
|
128
|
-
*/
|
|
129
|
-
export function setFlowList(nav, key, items) {
|
|
130
|
-
const node = nav.doc.createNode(items);
|
|
131
|
-
if (isSeq(node))
|
|
132
|
-
node.flow = true;
|
|
133
|
-
nav.doc.set(key, node);
|
|
134
|
-
nav.dirty = true;
|
|
135
|
-
return nav;
|
|
136
|
-
}
|
|
137
|
-
/** Append an item to a block-style list, creating the list if necessary. */
|
|
138
|
-
export function appendListItem(nav, key, item) {
|
|
139
|
-
const existing = nav.doc.get(key, true);
|
|
140
|
-
if (isSeq(existing)) {
|
|
141
|
-
existing.add(nav.doc.createNode(item));
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
nav.doc.set(key, nav.doc.createNode([item]));
|
|
145
|
-
}
|
|
146
|
-
nav.dirty = true;
|
|
147
|
-
return nav;
|
|
148
|
-
}
|
|
149
|
-
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/core/frontmatter.ts"],"names":[],"mappings":"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"}
|
package/dist/core/id.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Navbook identifiers — spec 02 §2.2.
|
|
3
|
-
*
|
|
4
|
-
* Grammar: exactly 8 characters, `^[a-z][a-z0-9]{7}$`, containing at least one
|
|
5
|
-
* digit. The leading letter keeps YAML from parsing an ID as a number; the
|
|
6
|
-
* mandatory digit keeps English words from being mistaken for IDs.
|
|
7
|
-
*/
|
|
8
|
-
/** Source of randomness, injected so that `core` stays pure and browser-safe. */
|
|
9
|
-
export type RandomBytes = (n: number) => Uint8Array;
|
|
10
|
-
export declare const ID_LENGTH = 8;
|
|
11
|
-
export declare const ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
12
|
-
export declare const ID_PATTERN: RegExp;
|
|
13
|
-
/** Minimum length of an ID prefix accepted wherever a CLI takes an ID (§2.2). */
|
|
14
|
-
export declare const MIN_PREFIX_LENGTH = 4;
|
|
15
|
-
/** True if `s` is a syntactically valid Navbook ID. */
|
|
16
|
-
export declare function isId(s: string): boolean;
|
|
17
|
-
/**
|
|
18
|
-
* Mint a fresh ID by rejection sampling: draw 8 uniform characters from the
|
|
19
|
-
* 36-character alphabet, discarding candidates that violate the grammar.
|
|
20
|
-
*
|
|
21
|
-
* Bytes ≥ 252 are discarded before the modulo so the character distribution is
|
|
22
|
-
* exactly uniform (252 = 7 × 36).
|
|
23
|
-
*/
|
|
24
|
-
export declare function mintId(randomBytes: RandomBytes): string;
|
|
25
|
-
export type PrefixResolution = {
|
|
26
|
-
ok: true;
|
|
27
|
-
id: string;
|
|
28
|
-
} | {
|
|
29
|
-
ok: false;
|
|
30
|
-
reason: "too-short";
|
|
31
|
-
matches: [];
|
|
32
|
-
} | {
|
|
33
|
-
ok: false;
|
|
34
|
-
reason: "not-found";
|
|
35
|
-
matches: [];
|
|
36
|
-
} | {
|
|
37
|
-
ok: false;
|
|
38
|
-
reason: "ambiguous";
|
|
39
|
-
matches: string[];
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Resolve an ID prefix against known IDs. Exact matches win outright; otherwise
|
|
43
|
-
* the prefix must be at least {@link MIN_PREFIX_LENGTH} characters and match
|
|
44
|
-
* exactly one candidate.
|
|
45
|
-
*/
|
|
46
|
-
export declare function resolvePrefix(prefix: string, candidates: readonly string[]): PrefixResolution;
|
package/dist/core/id.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Navbook identifiers — spec 02 §2.2.
|
|
3
|
-
*
|
|
4
|
-
* Grammar: exactly 8 characters, `^[a-z][a-z0-9]{7}$`, containing at least one
|
|
5
|
-
* digit. The leading letter keeps YAML from parsing an ID as a number; the
|
|
6
|
-
* mandatory digit keeps English words from being mistaken for IDs.
|
|
7
|
-
*/
|
|
8
|
-
export const ID_LENGTH = 8;
|
|
9
|
-
export const ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
10
|
-
export const ID_PATTERN = /^[a-z][a-z0-9]{7}$/;
|
|
11
|
-
/** Minimum length of an ID prefix accepted wherever a CLI takes an ID (§2.2). */
|
|
12
|
-
export const MIN_PREFIX_LENGTH = 4;
|
|
13
|
-
/** True if `s` is a syntactically valid Navbook ID. */
|
|
14
|
-
export function isId(s) {
|
|
15
|
-
return ID_PATTERN.test(s) && /[0-9]/.test(s);
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Mint a fresh ID by rejection sampling: draw 8 uniform characters from the
|
|
19
|
-
* 36-character alphabet, discarding candidates that violate the grammar.
|
|
20
|
-
*
|
|
21
|
-
* Bytes ≥ 252 are discarded before the modulo so the character distribution is
|
|
22
|
-
* exactly uniform (252 = 7 × 36).
|
|
23
|
-
*/
|
|
24
|
-
export function mintId(randomBytes) {
|
|
25
|
-
const limit = 252;
|
|
26
|
-
for (let attempt = 0; attempt < 1000; attempt++) {
|
|
27
|
-
const chars = [];
|
|
28
|
-
// Draw generously so a single call usually suffices even with rejections.
|
|
29
|
-
let pool = randomBytes(ID_LENGTH * 2);
|
|
30
|
-
let i = 0;
|
|
31
|
-
while (chars.length < ID_LENGTH) {
|
|
32
|
-
if (i >= pool.length) {
|
|
33
|
-
pool = randomBytes(ID_LENGTH * 2);
|
|
34
|
-
i = 0;
|
|
35
|
-
}
|
|
36
|
-
const byte = pool[i++];
|
|
37
|
-
if (byte >= limit)
|
|
38
|
-
continue;
|
|
39
|
-
chars.push(ID_ALPHABET[byte % ID_ALPHABET.length]);
|
|
40
|
-
}
|
|
41
|
-
const candidate = chars.join("");
|
|
42
|
-
if (isId(candidate))
|
|
43
|
-
return candidate;
|
|
44
|
-
}
|
|
45
|
-
/* c8 ignore next */
|
|
46
|
-
throw new Error("failed to mint an ID: random source is not producing usable bytes");
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Resolve an ID prefix against known IDs. Exact matches win outright; otherwise
|
|
50
|
-
* the prefix must be at least {@link MIN_PREFIX_LENGTH} characters and match
|
|
51
|
-
* exactly one candidate.
|
|
52
|
-
*/
|
|
53
|
-
export function resolvePrefix(prefix, candidates) {
|
|
54
|
-
const needle = prefix.toLowerCase();
|
|
55
|
-
if (candidates.includes(needle))
|
|
56
|
-
return { ok: true, id: needle };
|
|
57
|
-
if (needle.length < MIN_PREFIX_LENGTH)
|
|
58
|
-
return { ok: false, reason: "too-short", matches: [] };
|
|
59
|
-
const matches = candidates.filter((c) => c.startsWith(needle)).sort();
|
|
60
|
-
if (matches.length === 1)
|
|
61
|
-
return { ok: true, id: matches[0] };
|
|
62
|
-
if (matches.length === 0)
|
|
63
|
-
return { ok: false, reason: "not-found", matches: [] };
|
|
64
|
-
return { ok: false, reason: "ambiguous", matches };
|
|
65
|
-
}
|
|
66
|
-
//# sourceMappingURL=id.js.map
|
package/dist/core/id.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/core/id.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;AAC3B,MAAM,CAAC,MAAM,WAAW,GAAG,sCAAsC,CAAC;AAClE,MAAM,CAAC,MAAM,UAAU,GAAG,oBAAoB,CAAC;AAE/C,iFAAiF;AACjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC,uDAAuD;AACvD,MAAM,UAAU,IAAI,CAAC,CAAS;IAC5B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,WAAwB;IAC7C,MAAM,KAAK,GAAG,GAAG,CAAC;IAClB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;QAChD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,0EAA0E;QAC1E,IAAI,IAAI,GAAG,WAAW,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,KAAK,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACrB,IAAI,GAAG,WAAW,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;gBAClC,CAAC,GAAG,CAAC,CAAC;YACR,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,CAAW,CAAC;YACjC,IAAI,IAAI,IAAI,KAAK;gBAAE,SAAS;YAC5B,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,MAAM,CAAW,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IACxC,CAAC;IACD,oBAAoB;IACpB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;AACvF,CAAC;AAQD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,UAA6B;IACzE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACpC,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IACjE,IAAI,MAAM,CAAC,MAAM,GAAG,iBAAiB;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC9F,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACtE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAW,EAAE,CAAC;IACxE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACjF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AACrD,CAAC"}
|
package/dist/core/index.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Navbook core — pure format logic with no I/O and no git.
|
|
3
|
-
*
|
|
4
|
-
* This is the module that later runs in a browser and the one the planned Rust
|
|
5
|
-
* rewrite must reproduce function for function (spec 05 §5.2).
|
|
6
|
-
*/
|
|
7
|
-
export * from "./comments.ts";
|
|
8
|
-
export * from "./files.ts";
|
|
9
|
-
export * from "./frontmatter.ts";
|
|
10
|
-
export * from "./id.ts";
|
|
11
|
-
export * from "./json.ts";
|
|
12
|
-
export * from "./ops.ts";
|
|
13
|
-
export * from "./person.ts";
|
|
14
|
-
export * from "./query.ts";
|
|
15
|
-
export * from "./refs.ts";
|
|
16
|
-
export * from "./slug.ts";
|
|
17
|
-
export * from "./time.ts";
|
|
18
|
-
export * from "./tree.ts";
|
|
19
|
-
export * from "./validate.ts";
|
package/dist/core/index.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Navbook core — pure format logic with no I/O and no git.
|
|
3
|
-
*
|
|
4
|
-
* This is the module that later runs in a browser and the one the planned Rust
|
|
5
|
-
* rewrite must reproduce function for function (spec 05 §5.2).
|
|
6
|
-
*/
|
|
7
|
-
export * from "./comments.js";
|
|
8
|
-
export * from "./files.js";
|
|
9
|
-
export * from "./frontmatter.js";
|
|
10
|
-
export * from "./id.js";
|
|
11
|
-
export * from "./json.js";
|
|
12
|
-
export * from "./ops.js";
|
|
13
|
-
export * from "./person.js";
|
|
14
|
-
export * from "./query.js";
|
|
15
|
-
export * from "./refs.js";
|
|
16
|
-
export * from "./slug.js";
|
|
17
|
-
export * from "./time.js";
|
|
18
|
-
export * from "./tree.js";
|
|
19
|
-
export * from "./validate.js";
|
|
20
|
-
//# sourceMappingURL=index.js.map
|
package/dist/core/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
package/dist/core/json.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical machine-readable projection — spec 04 §4.2.
|
|
3
|
-
*
|
|
4
|
-
* The shape lives in `core` so every implementation emits byte-identical
|
|
5
|
-
* `--json` output and differential testing stays meaningful. Output is
|
|
6
|
-
* newline-delimited JSON: one object per entity, one object per line.
|
|
7
|
-
*
|
|
8
|
-
* `list` emits entity objects alone; `show` adds a `comments` array. No key
|
|
9
|
-
* ever changes type between commands.
|
|
10
|
-
*/
|
|
11
|
-
import type { CommentRecord, EntityRecord } from "./tree.ts";
|
|
12
|
-
export declare const NAVBOOK_ROOT = ".navbook";
|
|
13
|
-
/** One entity: identity first, then its frontmatter in file order, then body. */
|
|
14
|
-
export declare function entityJson(entity: EntityRecord, extra?: Record<string, unknown>): Record<string, unknown>;
|
|
15
|
-
/** One comment, including any review fields it carries. */
|
|
16
|
-
export declare function commentJson(comment: CommentRecord): Record<string, unknown>;
|
|
17
|
-
/** Serialize objects as newline-delimited JSON (one per line). */
|
|
18
|
-
export declare function toNdjson(objects: readonly Record<string, unknown>[]): string;
|
package/dist/core/json.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical machine-readable projection — spec 04 §4.2.
|
|
3
|
-
*
|
|
4
|
-
* The shape lives in `core` so every implementation emits byte-identical
|
|
5
|
-
* `--json` output and differential testing stays meaningful. Output is
|
|
6
|
-
* newline-delimited JSON: one object per entity, one object per line.
|
|
7
|
-
*
|
|
8
|
-
* `list` emits entity objects alone; `show` adds a `comments` array. No key
|
|
9
|
-
* ever changes type between commands.
|
|
10
|
-
*/
|
|
11
|
-
import { keysInOrder } from "./frontmatter.js";
|
|
12
|
-
export const NAVBOOK_ROOT = ".navbook";
|
|
13
|
-
/** One entity: identity first, then its frontmatter in file order, then body. */
|
|
14
|
-
export function entityJson(entity, extra = {}) {
|
|
15
|
-
const out = {
|
|
16
|
-
id: entity.id,
|
|
17
|
-
slug: entity.slug,
|
|
18
|
-
kind: entity.kind,
|
|
19
|
-
status: entity.status,
|
|
20
|
-
path: `${NAVBOOK_ROOT}/${entity.dirPath}`,
|
|
21
|
-
};
|
|
22
|
-
if (entity.archived)
|
|
23
|
-
out.archived = true;
|
|
24
|
-
for (const key of keysInOrder(entity.parsed.nav)) {
|
|
25
|
-
if (key === "" || key in out)
|
|
26
|
-
continue;
|
|
27
|
-
out[key] = entity.fm[key];
|
|
28
|
-
}
|
|
29
|
-
out.body = entity.body.trim();
|
|
30
|
-
return { ...out, ...extra };
|
|
31
|
-
}
|
|
32
|
-
/** One comment, including any review fields it carries. */
|
|
33
|
-
export function commentJson(comment) {
|
|
34
|
-
const out = {
|
|
35
|
-
id: comment.id,
|
|
36
|
-
path: `${NAVBOOK_ROOT}/${comment.path}`,
|
|
37
|
-
created: comment.stamp,
|
|
38
|
-
};
|
|
39
|
-
for (const key of keysInOrder(comment.parsed.nav)) {
|
|
40
|
-
if (key === "" || key in out)
|
|
41
|
-
continue;
|
|
42
|
-
out[key] = comment.parsed.fm[key];
|
|
43
|
-
}
|
|
44
|
-
out.body = comment.body.trim();
|
|
45
|
-
return out;
|
|
46
|
-
}
|
|
47
|
-
/** Serialize objects as newline-delimited JSON (one per line). */
|
|
48
|
-
export function toNdjson(objects) {
|
|
49
|
-
return objects.map((o) => JSON.stringify(o)).join("\n");
|
|
50
|
-
}
|
|
51
|
-
//# sourceMappingURL=json.js.map
|
package/dist/core/json.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/core/json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AAEvC,iFAAiF;AACjF,MAAM,UAAU,UAAU,CACxB,MAAoB,EACpB,QAAiC,EAAE;IAEnC,MAAM,GAAG,GAA4B;QACnC,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,GAAG,YAAY,IAAI,MAAM,CAAC,OAAO,EAAE;KAC1C,CAAC;IACF,IAAI,MAAM,CAAC,QAAQ;QAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG;YAAE,SAAS;QACvC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAC9B,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,OAAsB;IAChD,MAAM,GAAG,GAA4B;QACnC,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,GAAG,YAAY,IAAI,OAAO,CAAC,IAAI,EAAE;QACvC,OAAO,EAAE,OAAO,CAAC,KAAK;KACvB,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG;YAAE,SAAS;QACvC,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IACD,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAC/B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,QAAQ,CAAC,OAA2C;IAClE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1D,CAAC"}
|
package/dist/core/ops.d.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Operation planners.
|
|
3
|
-
*
|
|
4
|
-
* Every mutating Navbook command is a pure function from the current tree to a
|
|
5
|
-
* list of {@link FileOp}s plus a commit plan. Nothing here touches the file
|
|
6
|
-
* system or git, which keeps the whole mutation surface testable in memory and
|
|
7
|
-
* gives the future Rust rewrite a function-for-function target.
|
|
8
|
-
*/
|
|
9
|
-
import { type Revision } from "./files.ts";
|
|
10
|
-
import { type EntityKind, type EntityRecord } from "./tree.ts";
|
|
11
|
-
export type FileOp =
|
|
12
|
-
/** Create or overwrite a file, creating parent directories as needed. */
|
|
13
|
-
{
|
|
14
|
-
op: "write";
|
|
15
|
-
path: string;
|
|
16
|
-
content: string;
|
|
17
|
-
}
|
|
18
|
-
/** Rename a file or a whole directory; refuses when the destination exists. */
|
|
19
|
-
| {
|
|
20
|
-
op: "move";
|
|
21
|
-
from: string;
|
|
22
|
-
to: string;
|
|
23
|
-
};
|
|
24
|
-
export interface Trailer {
|
|
25
|
-
key: "Refs" | "Closes";
|
|
26
|
-
id: string;
|
|
27
|
-
}
|
|
28
|
-
export interface Plan {
|
|
29
|
-
ops: FileOp[];
|
|
30
|
-
message: string;
|
|
31
|
-
trailers: Trailer[];
|
|
32
|
-
}
|
|
33
|
-
/** Paths (relative to `.navbook/`) an operation may legitimately touch. */
|
|
34
|
-
export declare function planPaths(plan: Plan): string[];
|
|
35
|
-
/**
|
|
36
|
-
* Commit subject for a change to one entity, e.g. `docs(issue): close #bqlybac0`.
|
|
37
|
-
*
|
|
38
|
-
* Conventional Commits, scoped by entity kind: history readers filter Navbook's
|
|
39
|
-
* commits with the same `docs` type they already use for documentation, and the
|
|
40
|
-
* scope says at a glance whether an issue or a pull request moved (spec 03 §3.2).
|
|
41
|
-
*/
|
|
42
|
-
export declare function docsSubject(kind: EntityKind, action: string, id: string): string;
|
|
43
|
-
/** The `.navbook/` skeleton, with `.gitkeep` files so empty status dirs commit. */
|
|
44
|
-
export declare function planInit(): Plan;
|
|
45
|
-
export interface OpenResult {
|
|
46
|
-
plan: Plan;
|
|
47
|
-
id: string;
|
|
48
|
-
slug: string;
|
|
49
|
-
dirPath: string;
|
|
50
|
-
filePath: string;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Create an entity directory holding the given file text.
|
|
54
|
-
*
|
|
55
|
-
* The caller renders the file (with {@link newIssueFile}/{@link newPrFile}, or
|
|
56
|
-
* straight from an editor buffer) and passes the title that names the slug, so
|
|
57
|
-
* a title edited in the buffer still decides the directory name.
|
|
58
|
-
*/
|
|
59
|
-
export declare function planEntityOpen(kind: EntityKind, id: string, title: string, content: string): OpenResult;
|
|
60
|
-
export interface CommentResult {
|
|
61
|
-
plan: Plan;
|
|
62
|
-
id: string;
|
|
63
|
-
path: string;
|
|
64
|
-
}
|
|
65
|
-
/** Add a comment (or review) file to an entity's `comments/` directory. */
|
|
66
|
-
export declare function planComment(entity: EntityRecord, id: string, date: Date, content: string, opts?: {
|
|
67
|
-
review?: boolean;
|
|
68
|
-
}): CommentResult;
|
|
69
|
-
export interface CloseInput {
|
|
70
|
-
resolution?: string;
|
|
71
|
-
duplicateOf?: string;
|
|
72
|
-
}
|
|
73
|
-
/** Move an entity to `closed/`, optionally recording a resolution. */
|
|
74
|
-
export declare function planClose(entity: EntityRecord, input?: CloseInput): Plan;
|
|
75
|
-
/** Move an entity back to `open/`, clearing the resolution it was closed with. */
|
|
76
|
-
export declare function planReopen(entity: EntityRecord): Plan;
|
|
77
|
-
/** Move a merged pull request into `prs/merged/` (spec 03 §3.5). */
|
|
78
|
-
export declare function planArchiveMerged(entity: EntityRecord): Plan;
|
|
79
|
-
/** Apply frontmatter changes to an entity file, or null when nothing changes. */
|
|
80
|
-
export declare function rewriteFrontmatter(entity: EntityRecord, changes: Record<string, unknown>): string | null;
|
|
81
|
-
export declare class RevisionUnchangedError extends Error {
|
|
82
|
-
}
|
|
83
|
-
/** Append a revision entry; entries are append-only (§2.7). */
|
|
84
|
-
export declare function planPrUpdate(entity: EntityRecord, revision: Revision): Plan;
|
|
85
|
-
export interface MergedBlock {
|
|
86
|
-
date: string;
|
|
87
|
-
by: string;
|
|
88
|
-
/** Absent after a fast-forward, which creates no merge commit to name. */
|
|
89
|
-
commit?: string;
|
|
90
|
-
}
|
|
91
|
-
/** Record the `merged:` block after the merge commit exists (§2.7). */
|
|
92
|
-
export declare function planMergedBlock(entity: EntityRecord, merged: MergedBlock): Plan;
|
package/dist/core/ops.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Operation planners.
|
|
3
|
-
*
|
|
4
|
-
* Every mutating Navbook command is a pure function from the current tree to a
|
|
5
|
-
* list of {@link FileOp}s plus a commit plan. Nothing here touches the file
|
|
6
|
-
* system or git, which keeps the whole mutation surface testable in memory and
|
|
7
|
-
* gives the future Rust rewrite a function-for-function target.
|
|
8
|
-
*/
|
|
9
|
-
import { commentFileName } from "./comments.js";
|
|
10
|
-
import { readRevisions } from "./files.js";
|
|
11
|
-
import { appendListItem, parseDoc, patchDoc, serializeDoc } from "./frontmatter.js";
|
|
12
|
-
import { dirName as makeDirName, slugify } from "./slug.js";
|
|
13
|
-
import { statusDir } from "./tree.js";
|
|
14
|
-
/** Paths (relative to `.navbook/`) an operation may legitimately touch. */
|
|
15
|
-
export function planPaths(plan) {
|
|
16
|
-
const paths = new Set();
|
|
17
|
-
for (const op of plan.ops) {
|
|
18
|
-
if (op.op === "write")
|
|
19
|
-
paths.add(op.path);
|
|
20
|
-
else {
|
|
21
|
-
paths.add(op.from);
|
|
22
|
-
paths.add(op.to);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return [...paths];
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Commit subject for a change to one entity, e.g. `docs(issue): close #bqlybac0`.
|
|
29
|
-
*
|
|
30
|
-
* Conventional Commits, scoped by entity kind: history readers filter Navbook's
|
|
31
|
-
* commits with the same `docs` type they already use for documentation, and the
|
|
32
|
-
* scope says at a glance whether an issue or a pull request moved (spec 03 §3.2).
|
|
33
|
-
*/
|
|
34
|
-
export function docsSubject(kind, action, id) {
|
|
35
|
-
return `docs(${kind}): ${action} #${id}`;
|
|
36
|
-
}
|
|
37
|
-
/* --------------------------------------------------------------------- init */
|
|
38
|
-
/** The `.navbook/` skeleton, with `.gitkeep` files so empty status dirs commit. */
|
|
39
|
-
export function planInit() {
|
|
40
|
-
const dirs = ["issues/open", "issues/closed", "prs/open", "prs/merged", "prs/closed"];
|
|
41
|
-
return {
|
|
42
|
-
ops: dirs.map((dir) => ({ op: "write", path: `${dir}/.gitkeep`, content: "" })),
|
|
43
|
-
// No entity to scope to: init creates the whole skeleton.
|
|
44
|
-
message: "docs: initialize navbook",
|
|
45
|
-
trailers: [],
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Create an entity directory holding the given file text.
|
|
50
|
-
*
|
|
51
|
-
* The caller renders the file (with {@link newIssueFile}/{@link newPrFile}, or
|
|
52
|
-
* straight from an editor buffer) and passes the title that names the slug, so
|
|
53
|
-
* a title edited in the buffer still decides the directory name.
|
|
54
|
-
*/
|
|
55
|
-
export function planEntityOpen(kind, id, title, content) {
|
|
56
|
-
const slug = slugify(title);
|
|
57
|
-
const dirPath = `${statusDir(kind, "open")}/${makeDirName(id, slug)}`;
|
|
58
|
-
const filePath = `${dirPath}/${kind === "issue" ? "issue.md" : "pr.md"}`;
|
|
59
|
-
return {
|
|
60
|
-
plan: {
|
|
61
|
-
ops: [{ op: "write", path: filePath, content }],
|
|
62
|
-
message: docsSubject(kind, "open", id),
|
|
63
|
-
trailers: [],
|
|
64
|
-
},
|
|
65
|
-
id,
|
|
66
|
-
slug,
|
|
67
|
-
dirPath,
|
|
68
|
-
filePath,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
/** Add a comment (or review) file to an entity's `comments/` directory. */
|
|
72
|
-
export function planComment(entity, id, date, content, opts = {}) {
|
|
73
|
-
const path = `${entity.dirPath}/comments/${commentFileName(date, id)}`;
|
|
74
|
-
return {
|
|
75
|
-
plan: {
|
|
76
|
-
ops: [{ op: "write", path, content }],
|
|
77
|
-
message: docsSubject(entity.kind, opts.review ? "review" : "comment on", entity.id),
|
|
78
|
-
trailers: [{ key: "Refs", id: entity.id }],
|
|
79
|
-
},
|
|
80
|
-
id,
|
|
81
|
-
path,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
/** Move an entity to `closed/`, optionally recording a resolution. */
|
|
85
|
-
export function planClose(entity, input = {}) {
|
|
86
|
-
const resolution = input.resolution ?? (input.duplicateOf ? "duplicate" : undefined);
|
|
87
|
-
const changes = {};
|
|
88
|
-
if (resolution)
|
|
89
|
-
changes.resolution = resolution;
|
|
90
|
-
if (input.duplicateOf)
|
|
91
|
-
changes["duplicate-of"] = input.duplicateOf;
|
|
92
|
-
return {
|
|
93
|
-
ops: moveWithFrontmatter(entity, "closed", changes),
|
|
94
|
-
message: docsSubject(entity.kind, "close", entity.id),
|
|
95
|
-
trailers: [{ key: "Closes", id: entity.id }],
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/** Move an entity back to `open/`, clearing the resolution it was closed with. */
|
|
99
|
-
export function planReopen(entity) {
|
|
100
|
-
const changes = { resolution: undefined };
|
|
101
|
-
if (entity.fm.resolution === "duplicate")
|
|
102
|
-
changes["duplicate-of"] = undefined;
|
|
103
|
-
if (entity.fm.resolution === "superseded")
|
|
104
|
-
changes["superseded-by"] = undefined;
|
|
105
|
-
return {
|
|
106
|
-
ops: moveWithFrontmatter(entity, "open", changes),
|
|
107
|
-
message: docsSubject(entity.kind, "reopen", entity.id),
|
|
108
|
-
trailers: [{ key: "Refs", id: entity.id }],
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
/** Move a merged pull request into `prs/merged/` (spec 03 §3.5). */
|
|
112
|
-
export function planArchiveMerged(entity) {
|
|
113
|
-
return {
|
|
114
|
-
ops: moveWithFrontmatter(entity, "merged", {}),
|
|
115
|
-
message: docsSubject(entity.kind, "archive merged", entity.id),
|
|
116
|
-
trailers: [{ key: "Refs", id: entity.id }],
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Move an entity between status directories, applying frontmatter changes to
|
|
121
|
-
* the file at its *new* location so the ops apply in order.
|
|
122
|
-
*/
|
|
123
|
-
function moveWithFrontmatter(entity, status, changes) {
|
|
124
|
-
const ops = [];
|
|
125
|
-
const targetDir = `${statusDir(entity.kind, status)}/${entity.dirName}`;
|
|
126
|
-
const moved = targetDir !== entity.dirPath;
|
|
127
|
-
if (moved)
|
|
128
|
-
ops.push({ op: "move", from: entity.dirPath, to: targetDir });
|
|
129
|
-
const fileName = entity.kind === "issue" ? "issue.md" : "pr.md";
|
|
130
|
-
const rewritten = rewriteFrontmatter(entity, changes);
|
|
131
|
-
if (rewritten !== null) {
|
|
132
|
-
ops.push({ op: "write", path: `${targetDir}/${fileName}`, content: rewritten });
|
|
133
|
-
}
|
|
134
|
-
return ops;
|
|
135
|
-
}
|
|
136
|
-
/** Apply frontmatter changes to an entity file, or null when nothing changes. */
|
|
137
|
-
export function rewriteFrontmatter(entity, changes) {
|
|
138
|
-
const meaningful = Object.entries(changes).filter(([key, value]) => value === undefined ? entity.fm[key] !== undefined : entity.fm[key] !== value);
|
|
139
|
-
if (meaningful.length === 0)
|
|
140
|
-
return null;
|
|
141
|
-
const nav = parseDoc(serializeDoc(entity.parsed.nav));
|
|
142
|
-
patchDoc(nav, Object.fromEntries(meaningful));
|
|
143
|
-
return serializeDoc(nav);
|
|
144
|
-
}
|
|
145
|
-
/* ------------------------------------------------------------ pull requests */
|
|
146
|
-
export class RevisionUnchangedError extends Error {
|
|
147
|
-
}
|
|
148
|
-
/** Append a revision entry; entries are append-only (§2.7). */
|
|
149
|
-
export function planPrUpdate(entity, revision) {
|
|
150
|
-
const existing = readRevisions(entity.fm);
|
|
151
|
-
const last = existing[existing.length - 1];
|
|
152
|
-
if (last && last.head === revision.head) {
|
|
153
|
-
throw new RevisionUnchangedError(`HEAD ${revision.head.slice(0, 8)} is already the latest recorded revision of #${entity.id}`);
|
|
154
|
-
}
|
|
155
|
-
const nav = parseDoc(serializeDoc(entity.parsed.nav));
|
|
156
|
-
appendListItem(nav, "revisions", revision);
|
|
157
|
-
return {
|
|
158
|
-
ops: [{ op: "write", path: entity.filePath, content: serializeDoc(nav) }],
|
|
159
|
-
message: docsSubject(entity.kind, "update", entity.id),
|
|
160
|
-
trailers: [{ key: "Refs", id: entity.id }],
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
/** Record the `merged:` block after the merge commit exists (§2.7). */
|
|
164
|
-
export function planMergedBlock(entity, merged) {
|
|
165
|
-
const nav = parseDoc(serializeDoc(entity.parsed.nav));
|
|
166
|
-
patchDoc(nav, { merged });
|
|
167
|
-
return {
|
|
168
|
-
ops: [{ op: "write", path: entity.filePath, content: serializeDoc(nav) }],
|
|
169
|
-
message: docsSubject(entity.kind, "merge", entity.id),
|
|
170
|
-
trailers: [{ key: "Refs", id: entity.id }],
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
//# sourceMappingURL=ops.js.map
|