@navbook/cli 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/dist/commands/complete.js +124 -0
  2. package/dist/commands/complete.js.map +1 -0
  3. package/dist/{cli/commands → commands}/compose.js +5 -3
  4. package/dist/commands/compose.js.map +1 -0
  5. package/dist/commands/doctor.js +56 -0
  6. package/dist/commands/doctor.js.map +1 -0
  7. package/dist/commands/entity.js +235 -0
  8. package/dist/commands/entity.js.map +1 -0
  9. package/dist/commands/feature.js +202 -0
  10. package/dist/commands/feature.js.map +1 -0
  11. package/dist/commands/init.js +23 -0
  12. package/dist/commands/init.js.map +1 -0
  13. package/dist/{cli/commands → commands}/install.js +1 -2
  14. package/dist/commands/install.js.map +1 -0
  15. package/dist/commands/issue.js +89 -0
  16. package/dist/commands/issue.js.map +1 -0
  17. package/dist/commands/policy.js +49 -0
  18. package/dist/commands/policy.js.map +1 -0
  19. package/dist/commands/pr.js +262 -0
  20. package/dist/commands/pr.js.map +1 -0
  21. package/dist/context.js +21 -0
  22. package/dist/context.js.map +1 -0
  23. package/dist/{cli/editor.js → editor.js} +1 -1
  24. package/dist/editor.js.map +1 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/install/completions.js.map +1 -0
  27. package/dist/{cli/install → install}/hook.js +1 -1
  28. package/dist/install/hook.js.map +1 -0
  29. package/dist/{cli/main.js → main.js} +10 -0
  30. package/dist/main.js.map +1 -0
  31. package/dist/program.js +356 -0
  32. package/dist/program.js.map +1 -0
  33. package/dist/{cli/prompt.js → prompt.js} +11 -0
  34. package/dist/prompt.js.map +1 -0
  35. package/dist/render/colors.js.map +1 -0
  36. package/dist/render/detail.js +197 -0
  37. package/dist/render/detail.js.map +1 -0
  38. package/dist/render/table.js.map +1 -0
  39. package/dist/sort.js +77 -0
  40. package/dist/sort.js.map +1 -0
  41. package/package.json +15 -21
  42. package/README.md +0 -165
  43. package/dist/cli/commands/complete.d.ts +0 -9
  44. package/dist/cli/commands/complete.js +0 -72
  45. package/dist/cli/commands/complete.js.map +0 -1
  46. package/dist/cli/commands/compose.d.ts +0 -27
  47. package/dist/cli/commands/compose.js.map +0 -1
  48. package/dist/cli/commands/doctor.d.ts +0 -14
  49. package/dist/cli/commands/doctor.js +0 -127
  50. package/dist/cli/commands/doctor.js.map +0 -1
  51. package/dist/cli/commands/entity.d.ts +0 -55
  52. package/dist/cli/commands/entity.js +0 -209
  53. package/dist/cli/commands/entity.js.map +0 -1
  54. package/dist/cli/commands/init.d.ts +0 -11
  55. package/dist/cli/commands/init.js +0 -39
  56. package/dist/cli/commands/init.js.map +0 -1
  57. package/dist/cli/commands/install.d.ts +0 -17
  58. package/dist/cli/commands/install.js.map +0 -1
  59. package/dist/cli/commands/issue.d.ts +0 -12
  60. package/dist/cli/commands/issue.js +0 -42
  61. package/dist/cli/commands/issue.js.map +0 -1
  62. package/dist/cli/commands/pr.d.ts +0 -64
  63. package/dist/cli/commands/pr.js +0 -466
  64. package/dist/cli/commands/pr.js.map +0 -1
  65. package/dist/cli/commit-flow.d.ts +0 -27
  66. package/dist/cli/commit-flow.js +0 -47
  67. package/dist/cli/commit-flow.js.map +0 -1
  68. package/dist/cli/context.d.ts +0 -39
  69. package/dist/cli/context.js +0 -93
  70. package/dist/cli/context.js.map +0 -1
  71. package/dist/cli/editor.d.ts +0 -23
  72. package/dist/cli/editor.js.map +0 -1
  73. package/dist/cli/errors.d.ts +0 -17
  74. package/dist/cli/errors.js.map +0 -1
  75. package/dist/cli/history-checks.d.ts +0 -21
  76. package/dist/cli/history-checks.js +0 -134
  77. package/dist/cli/history-checks.js.map +0 -1
  78. package/dist/cli/install/completions.d.ts +0 -19
  79. package/dist/cli/install/completions.js.map +0 -1
  80. package/dist/cli/install/hook.d.ts +0 -20
  81. package/dist/cli/install/hook.js.map +0 -1
  82. package/dist/cli/main.d.ts +0 -14
  83. package/dist/cli/main.js.map +0 -1
  84. package/dist/cli/program.d.ts +0 -23
  85. package/dist/cli/program.js +0 -204
  86. package/dist/cli/program.js.map +0 -1
  87. package/dist/cli/prompt.d.ts +0 -22
  88. package/dist/cli/prompt.js.map +0 -1
  89. package/dist/cli/render/colors.d.ts +0 -13
  90. package/dist/cli/render/colors.js.map +0 -1
  91. package/dist/cli/render/detail.d.ts +0 -10
  92. package/dist/cli/render/detail.js +0 -105
  93. package/dist/cli/render/detail.js.map +0 -1
  94. package/dist/cli/render/table.d.ts +0 -19
  95. package/dist/cli/render/table.js.map +0 -1
  96. package/dist/cli/resolve.d.ts +0 -17
  97. package/dist/cli/resolve.js +0 -68
  98. package/dist/cli/resolve.js.map +0 -1
  99. package/dist/cli/workspace.d.ts +0 -52
  100. package/dist/cli/workspace.js +0 -178
  101. package/dist/cli/workspace.js.map +0 -1
  102. package/dist/core/comments.d.ts +0 -31
  103. package/dist/core/comments.js +0 -80
  104. package/dist/core/comments.js.map +0 -1
  105. package/dist/core/files.d.ts +0 -88
  106. package/dist/core/files.js +0 -441
  107. package/dist/core/files.js.map +0 -1
  108. package/dist/core/frontmatter.d.ts +0 -63
  109. package/dist/core/frontmatter.js +0 -149
  110. package/dist/core/frontmatter.js.map +0 -1
  111. package/dist/core/id.d.ts +0 -46
  112. package/dist/core/id.js +0 -66
  113. package/dist/core/id.js.map +0 -1
  114. package/dist/core/index.d.ts +0 -19
  115. package/dist/core/index.js +0 -20
  116. package/dist/core/index.js.map +0 -1
  117. package/dist/core/json.d.ts +0 -18
  118. package/dist/core/json.js +0 -51
  119. package/dist/core/json.js.map +0 -1
  120. package/dist/core/ops.d.ts +0 -92
  121. package/dist/core/ops.js +0 -173
  122. package/dist/core/ops.js.map +0 -1
  123. package/dist/core/person.d.ts +0 -20
  124. package/dist/core/person.js +0 -50
  125. package/dist/core/person.js.map +0 -1
  126. package/dist/core/query.d.ts +0 -30
  127. package/dist/core/query.js +0 -106
  128. package/dist/core/query.js.map +0 -1
  129. package/dist/core/refs.d.ts +0 -12
  130. package/dist/core/refs.js +0 -36
  131. package/dist/core/refs.js.map +0 -1
  132. package/dist/core/slug.d.ts +0 -22
  133. package/dist/core/slug.js +0 -40
  134. package/dist/core/slug.js.map +0 -1
  135. package/dist/core/time.d.ts +0 -14
  136. package/dist/core/time.js +0 -37
  137. package/dist/core/time.js.map +0 -1
  138. package/dist/core/tree.d.ts +0 -94
  139. package/dist/core/tree.js +0 -237
  140. package/dist/core/tree.js.map +0 -1
  141. package/dist/core/validate.d.ts +0 -55
  142. package/dist/core/validate.js +0 -312
  143. package/dist/core/validate.js.map +0 -1
  144. package/dist/git/config.d.ts +0 -12
  145. package/dist/git/config.js +0 -27
  146. package/dist/git/config.js.map +0 -1
  147. package/dist/git/exec.d.ts +0 -35
  148. package/dist/git/exec.js +0 -58
  149. package/dist/git/exec.js.map +0 -1
  150. package/dist/git/history.d.ts +0 -35
  151. package/dist/git/history.js +0 -82
  152. package/dist/git/history.js.map +0 -1
  153. package/dist/git/index-ops.d.ts +0 -20
  154. package/dist/git/index-ops.js +0 -45
  155. package/dist/git/index-ops.js.map +0 -1
  156. package/dist/git/merge.d.ts +0 -27
  157. package/dist/git/merge.js +0 -57
  158. package/dist/git/merge.js.map +0 -1
  159. package/dist/git/refscan.d.ts +0 -32
  160. package/dist/git/refscan.js +0 -82
  161. package/dist/git/refscan.js.map +0 -1
  162. package/dist/git/repo.d.ts +0 -45
  163. package/dist/git/repo.js +0 -95
  164. package/dist/git/repo.js.map +0 -1
  165. /package/dist/{cli/errors.js → errors.js} +0 -0
  166. /package/dist/{cli/install → install}/completions.js +0 -0
  167. /package/dist/{cli/render → render}/colors.js +0 -0
  168. /package/dist/{cli/render → render}/table.js +0 -0
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"ops.js","sourceRoot":"","sources":["../../src/core/ops.ts"],"names":[],"mappings":"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"}
@@ -1,20 +0,0 @@
1
- /**
2
- * People — spec 02 §2.4. RFC 5322 addresses, display name optional. The email
3
- * address is the identity key and is compared case-insensitively.
4
- */
5
- export interface Person {
6
- name?: string;
7
- email: string;
8
- }
9
- /** Parse `alice@example.com` or `Alice Smith <alice@example.com>`. */
10
- export declare function parsePerson(input: string): Person | null;
11
- /** Render a person back to its RFC 5322 form. */
12
- export declare function formatPerson(person: Person): string;
13
- /** Compare two addresses case-insensitively (§2.4). */
14
- export declare function sameEmail(a: string, b: string): boolean;
15
- /**
16
- * Match a person against an `author:`/`assignee:` query value: the full address
17
- * matches case-insensitively, and a bare domain fragment matches as a substring
18
- * of the part after `@` (spec 04, query grammar).
19
- */
20
- export declare function personMatches(queryValue: string, personField: string): boolean;
@@ -1,50 +0,0 @@
1
- /**
2
- * People — spec 02 §2.4. RFC 5322 addresses, display name optional. The email
3
- * address is the identity key and is compared case-insensitively.
4
- */
5
- const ADDRESS_PATTERN = /^[^\s<>@,;]+@[^\s<>@,;]+\.[^\s<>@,;]+$/;
6
- const NAMED_PATTERN = /^(.*?)\s*<([^<>]+)>$/;
7
- /** Parse `alice@example.com` or `Alice Smith <alice@example.com>`. */
8
- export function parsePerson(input) {
9
- const text = input.trim();
10
- if (text === "")
11
- return null;
12
- const named = NAMED_PATTERN.exec(text);
13
- if (named) {
14
- const email = named[2].trim();
15
- if (!ADDRESS_PATTERN.test(email))
16
- return null;
17
- const name = named[1].replace(/^"|"$/g, "").trim();
18
- return name === "" ? { email } : { name, email };
19
- }
20
- if (!ADDRESS_PATTERN.test(text))
21
- return null;
22
- return { email: text };
23
- }
24
- /** Render a person back to its RFC 5322 form. */
25
- export function formatPerson(person) {
26
- return person.name ? `${person.name} <${person.email}>` : person.email;
27
- }
28
- /** Compare two addresses case-insensitively (§2.4). */
29
- export function sameEmail(a, b) {
30
- return a.trim().toLowerCase() === b.trim().toLowerCase();
31
- }
32
- /**
33
- * Match a person against an `author:`/`assignee:` query value: the full address
34
- * matches case-insensitively, and a bare domain fragment matches as a substring
35
- * of the part after `@` (spec 04, query grammar).
36
- */
37
- export function personMatches(queryValue, personField) {
38
- const needle = queryValue.trim().toLowerCase();
39
- if (needle === "")
40
- return false;
41
- const person = parsePerson(personField);
42
- const email = (person?.email ?? personField).trim().toLowerCase();
43
- if (email === needle)
44
- return true;
45
- if (needle.includes("@"))
46
- return false;
47
- const domain = email.slice(email.indexOf("@") + 1);
48
- return domain.includes(needle);
49
- }
50
- //# sourceMappingURL=person.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"person.js","sourceRoot":"","sources":["../../src/core/person.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,eAAe,GAAG,wCAAwC,CAAC;AACjE,MAAM,aAAa,GAAG,sBAAsB,CAAC;AAE7C,sEAAsE;AACtE,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,GAAI,KAAK,CAAC,CAAC,CAAY,CAAC,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9C,MAAM,IAAI,GAAI,KAAK,CAAC,CAAC,CAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/D,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACzE,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,CAAS;IAC5C,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,WAAmB;IACnE,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/C,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,KAAK,IAAI,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClE,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC"}
@@ -1,30 +0,0 @@
1
- /**
2
- * Query grammar for `nav issue list` / `nav pr list` — spec 04.
3
- *
4
- * Terms AND together. Within a single key the semantics follow the field:
5
- * single-valued fields (`status`, `author`, `milestone`) OR their terms, since
6
- * requiring two different values at once could never match; multi-valued fields
7
- * (`label`, `assignee`) AND theirs, matching forge convention.
8
- */
9
- import type { EntityKind, EntityRecord, Status } from "./tree.ts";
10
- export interface Query {
11
- status: string[];
12
- labels: string[];
13
- assignees: string[];
14
- authors: string[];
15
- milestones: string[];
16
- text: string[];
17
- }
18
- export interface QueryError {
19
- message: string;
20
- }
21
- export declare function emptyQuery(): Query;
22
- /** Statuses a `list` command defaults to when the query names none. */
23
- export declare function defaultStatuses(): Status[];
24
- /** Parse query terms. Unknown `key:value` shapes are treated as free text. */
25
- export declare function parseQuery(terms: readonly string[], kind: EntityKind): Query | QueryError;
26
- export declare function isQueryError(value: Query | QueryError): value is QueryError;
27
- /** True when evaluating the query requires reading comment bodies. */
28
- export declare function needsComments(query: Query): boolean;
29
- /** Evaluate a query against one entity. */
30
- export declare function matchesQuery(query: Query, entity: EntityRecord): boolean;
@@ -1,106 +0,0 @@
1
- /**
2
- * Query grammar for `nav issue list` / `nav pr list` — spec 04.
3
- *
4
- * Terms AND together. Within a single key the semantics follow the field:
5
- * single-valued fields (`status`, `author`, `milestone`) OR their terms, since
6
- * requiring two different values at once could never match; multi-valued fields
7
- * (`label`, `assignee`) AND theirs, matching forge convention.
8
- */
9
- import { readAssignees, readLabels } from "./files.js";
10
- import { personMatches } from "./person.js";
11
- const KEYED_TERM = /^(status|label|assignee|author|milestone):(.*)$/;
12
- export function emptyQuery() {
13
- return { status: [], labels: [], assignees: [], authors: [], milestones: [], text: [] };
14
- }
15
- /** Statuses a `list` command defaults to when the query names none. */
16
- export function defaultStatuses() {
17
- return ["open"];
18
- }
19
- /** Parse query terms. Unknown `key:value` shapes are treated as free text. */
20
- export function parseQuery(terms, kind) {
21
- const query = emptyQuery();
22
- for (const term of terms) {
23
- if (term.trim() === "")
24
- continue;
25
- const match = KEYED_TERM.exec(term);
26
- if (!match) {
27
- query.text.push(term);
28
- continue;
29
- }
30
- const key = match[1];
31
- const value = match[2].trim();
32
- if (value === "")
33
- return { message: `query term '${term}' is missing a value` };
34
- switch (key) {
35
- case "status": {
36
- const allowed = kind === "issue" ? ["open", "closed"] : ["open", "merged", "closed"];
37
- if (!allowed.includes(value)) {
38
- return {
39
- message: `unknown status '${value}' for ${kind === "issue" ? "issues" : "pull requests"} (expected ${allowed.join(", ")})`,
40
- };
41
- }
42
- query.status.push(value);
43
- break;
44
- }
45
- case "label":
46
- query.labels.push(value);
47
- break;
48
- case "assignee":
49
- query.assignees.push(value);
50
- break;
51
- case "author":
52
- query.authors.push(value);
53
- break;
54
- default:
55
- query.milestones.push(value);
56
- break;
57
- }
58
- }
59
- return query;
60
- }
61
- export function isQueryError(value) {
62
- return value.message !== undefined;
63
- }
64
- /** True when evaluating the query requires reading comment bodies. */
65
- export function needsComments(query) {
66
- return query.text.length > 0;
67
- }
68
- /** Evaluate a query against one entity. */
69
- export function matchesQuery(query, entity) {
70
- const statuses = query.status.length > 0 ? query.status : defaultStatuses();
71
- if (!statuses.includes(entity.status))
72
- return false;
73
- const labels = readLabels(entity.fm).map((l) => l.toLowerCase());
74
- for (const wanted of query.labels) {
75
- if (!labels.includes(wanted.toLowerCase()))
76
- return false;
77
- }
78
- const assignees = readAssignees(entity.fm);
79
- for (const wanted of query.assignees) {
80
- if (!assignees.some((a) => personMatches(wanted, a)))
81
- return false;
82
- }
83
- if (query.authors.length > 0) {
84
- const author = typeof entity.fm.author === "string" ? entity.fm.author : "";
85
- if (!query.authors.some((wanted) => personMatches(wanted, author)))
86
- return false;
87
- }
88
- if (query.milestones.length > 0) {
89
- const milestone = typeof entity.fm.milestone === "string" ? entity.fm.milestone : "";
90
- if (!query.milestones.some((wanted) => wanted === milestone))
91
- return false;
92
- }
93
- for (const needle of query.text) {
94
- if (!matchesText(needle.toLowerCase(), entity))
95
- return false;
96
- }
97
- return true;
98
- }
99
- function matchesText(needle, entity) {
100
- if (entity.title.toLowerCase().includes(needle))
101
- return true;
102
- if (entity.body.toLowerCase().includes(needle))
103
- return true;
104
- return entity.comments.some((comment) => comment.body.toLowerCase().includes(needle));
105
- }
106
- //# sourceMappingURL=query.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/core/query.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgB5C,MAAM,UAAU,GAAG,iDAAiD,CAAC;AAErE,MAAM,UAAU,UAAU;IACxB,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AAC1F,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,UAAU,CAAC,KAAwB,EAAE,IAAgB;IACnE,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,SAAS;QACjC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QAC/B,MAAM,KAAK,GAAI,KAAK,CAAC,CAAC,CAAY,CAAC,IAAI,EAAE,CAAC;QAC1C,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,eAAe,IAAI,sBAAsB,EAAE,CAAC;QAChF,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,OAAO,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBACrF,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7B,OAAO;wBACL,OAAO,EAAE,mBAAmB,KAAK,SAAS,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,cAAc,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;qBAC3H,CAAC;gBACJ,CAAC;gBACD,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACzB,MAAM;YACR,CAAC;YACD,KAAK,OAAO;gBACV,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,UAAU;gBACb,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC5B,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC1B,MAAM;YACR;gBACE,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC7B,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAyB;IACpD,OAAQ,KAAoB,CAAC,OAAO,KAAK,SAAS,CAAC;AACrD,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,KAAY;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,YAAY,CAAC,KAAY,EAAE,MAAoB;IAC7D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IAC5E,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAEpD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACjE,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;IAC3D,CAAC;IAED,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACrC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACrE,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACnF,CAAC;IAED,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,OAAO,MAAM,CAAC,EAAE,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;IAC7E,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;IAC/D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,MAAc,EAAE,MAAoB;IACvD,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5D,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACxF,CAAC"}
@@ -1,12 +0,0 @@
1
- /**
2
- * References — spec 02 §2.9. `#<id>` in prose, `Refs:`/`Closes:` git trailers in
3
- * commit messages. Mentions never change state; they only document intent.
4
- */
5
- /** Extract `#id` references from Markdown prose, ignoring English words. */
6
- export declare function extractProseRefs(markdown: string): string[];
7
- export interface TrailerRefs {
8
- refs: string[];
9
- closes: string[];
10
- }
11
- /** Extract `Refs:` and `Closes:` trailers from a commit message. */
12
- export declare function extractTrailerRefs(message: string): TrailerRefs;
package/dist/core/refs.js DELETED
@@ -1,36 +0,0 @@
1
- /**
2
- * References — spec 02 §2.9. `#<id>` in prose, `Refs:`/`Closes:` git trailers in
3
- * commit messages. Mentions never change state; they only document intent.
4
- */
5
- import { isId } from "./id.js";
6
- const PROSE_REF = /(^|[^\w#/`])#([a-z][a-z0-9]{7})\b/g;
7
- const TRAILER_LINE = /^(Refs|Closes):[ \t]*(.+?)[ \t]*$/gim;
8
- /** Extract `#id` references from Markdown prose, ignoring English words. */
9
- export function extractProseRefs(markdown) {
10
- const out = new Set();
11
- for (const match of markdown.matchAll(PROSE_REF)) {
12
- const id = match[2];
13
- if (isId(id))
14
- out.add(id);
15
- }
16
- return [...out];
17
- }
18
- /** Extract `Refs:` and `Closes:` trailers from a commit message. */
19
- export function extractTrailerRefs(message) {
20
- const refs = new Set();
21
- const closes = new Set();
22
- for (const match of message.matchAll(TRAILER_LINE)) {
23
- const kind = match[1].toLowerCase();
24
- for (const token of match[2].split(/[\s,]+/)) {
25
- const id = token.replace(/^#/, "");
26
- if (!isId(id))
27
- continue;
28
- if (kind === "closes")
29
- closes.add(id);
30
- else
31
- refs.add(id);
32
- }
33
- }
34
- return { refs: [...refs], closes: [...closes] };
35
- }
36
- //# sourceMappingURL=refs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/core/refs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,SAAS,GAAG,oCAAoC,CAAC;AACvD,MAAM,YAAY,GAAG,sCAAsC,CAAC;AAE5D,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACjD,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QAC9B,IAAI,IAAI,CAAC,EAAE,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAClB,CAAC;AAOD,oEAAoE;AACpE,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAI,KAAK,CAAC,CAAC,CAAY,CAAC,WAAW,EAAE,CAAC;QAChD,KAAK,MAAM,KAAK,IAAK,KAAK,CAAC,CAAC,CAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,SAAS;YACxB,IAAI,IAAI,KAAK,QAAQ;gBAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;;gBACjC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;AAClD,CAAC"}
@@ -1,22 +0,0 @@
1
- /**
2
- * Entity directory names — spec 02 §2.3: `<id>-<slug>`.
3
- */
4
- export declare const MAX_SLUG_LENGTH = 50;
5
- export declare const SLUG_FALLBACK = "untitled";
6
- export declare const DIR_NAME_PATTERN: RegExp;
7
- export declare const SLUG_PATTERN: RegExp;
8
- /**
9
- * Derive a display slug from a title: fold accents, lowercase, collapse every
10
- * run of non-alphanumerics to a single hyphen, cap at 50 characters.
11
- *
12
- * Titles with no ASCII-representable alphanumerics (CJK, emoji, punctuation
13
- * only) slug to {@link SLUG_FALLBACK}, since §2.3 requires at least one segment.
14
- */
15
- export declare function slugify(title: string): string;
16
- /** Compose an entity directory name. */
17
- export declare function dirName(id: string, slug: string): string;
18
- /** Split an entity directory name, or return null if it violates the grammar. */
19
- export declare function parseDirName(name: string): {
20
- id: string;
21
- slug: string;
22
- } | null;
package/dist/core/slug.js DELETED
@@ -1,40 +0,0 @@
1
- /**
2
- * Entity directory names — spec 02 §2.3: `<id>-<slug>`.
3
- */
4
- import { isId } from "./id.js";
5
- export const MAX_SLUG_LENGTH = 50;
6
- export const SLUG_FALLBACK = "untitled";
7
- export const DIR_NAME_PATTERN = /^[a-z][a-z0-9]{7}-[a-z0-9]+(-[a-z0-9]+)*$/;
8
- export const SLUG_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
9
- /**
10
- * Derive a display slug from a title: fold accents, lowercase, collapse every
11
- * run of non-alphanumerics to a single hyphen, cap at 50 characters.
12
- *
13
- * Titles with no ASCII-representable alphanumerics (CJK, emoji, punctuation
14
- * only) slug to {@link SLUG_FALLBACK}, since §2.3 requires at least one segment.
15
- */
16
- export function slugify(title) {
17
- const folded = title.normalize("NFKD").replace(/\p{M}/gu, "");
18
- let slug = folded
19
- .toLowerCase()
20
- .replace(/[^a-z0-9]+/g, "-")
21
- .replace(/^-+|-+$/g, "");
22
- if (slug.length > MAX_SLUG_LENGTH) {
23
- slug = slug.slice(0, MAX_SLUG_LENGTH).replace(/-+$/, "");
24
- }
25
- return slug === "" ? SLUG_FALLBACK : slug;
26
- }
27
- /** Compose an entity directory name. */
28
- export function dirName(id, slug) {
29
- return `${id}-${slug}`;
30
- }
31
- /** Split an entity directory name, or return null if it violates the grammar. */
32
- export function parseDirName(name) {
33
- if (!DIR_NAME_PATTERN.test(name))
34
- return null;
35
- const id = name.slice(0, 8);
36
- if (!isId(id))
37
- return null;
38
- return { id, slug: name.slice(9) };
39
- }
40
- //# sourceMappingURL=slug.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/core/slug.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AACxC,MAAM,CAAC,MAAM,gBAAgB,GAAG,2CAA2C,CAAC;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC9D,IAAI,IAAI,GAAG,MAAM;SACd,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QAClC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,OAAO,CAAC,EAAU,EAAE,IAAY;IAC9C,OAAO,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACrC,CAAC"}
@@ -1,14 +0,0 @@
1
- /**
2
- * Timestamp helpers — spec 02 §2.4 (ISO 8601, UTC recommended).
3
- *
4
- * Frontmatter timestamps are display data; git history is authoritative
5
- * wherever ordering or authority matters.
6
- */
7
- /** Normalize an instant to `YYYY-MM-DDTHH:MM:SSZ` (no sub-second precision). */
8
- export declare function toIsoSeconds(date: Date): string;
9
- /** Compact UTC stamp used in comment filenames: `YYYY-MM-DDTHHMMSSZ` (§2.6). */
10
- export declare function toCompactStamp(date: Date): string;
11
- /** Parse an ISO 8601 timestamp, returning null when it is not a valid instant. */
12
- export declare function parseIso(value: string): Date | null;
13
- /** Expand a compact comment-filename stamp into an ISO 8601 timestamp. */
14
- export declare function fromCompactStamp(stamp: string): Date | null;
package/dist/core/time.js DELETED
@@ -1,37 +0,0 @@
1
- /**
2
- * Timestamp helpers — spec 02 §2.4 (ISO 8601, UTC recommended).
3
- *
4
- * Frontmatter timestamps are display data; git history is authoritative
5
- * wherever ordering or authority matters.
6
- */
7
- /** Normalize an instant to `YYYY-MM-DDTHH:MM:SSZ` (no sub-second precision). */
8
- export function toIsoSeconds(date) {
9
- return `${date.toISOString().slice(0, 19)}Z`;
10
- }
11
- /** Compact UTC stamp used in comment filenames: `YYYY-MM-DDTHHMMSSZ` (§2.6). */
12
- export function toCompactStamp(date) {
13
- const iso = date.toISOString();
14
- return `${iso.slice(0, 10)}T${iso.slice(11, 13)}${iso.slice(14, 16)}${iso.slice(17, 19)}Z`;
15
- }
16
- /** Parse an ISO 8601 timestamp, returning null when it is not a valid instant. */
17
- export function parseIso(value) {
18
- const trimmed = value.trim();
19
- if (!/^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/.test(trimmed)) {
20
- return null;
21
- }
22
- const date = new Date(trimmed);
23
- return Number.isNaN(date.getTime()) ? null : date;
24
- }
25
- /** Expand a compact comment-filename stamp into an ISO 8601 timestamp. */
26
- export function fromCompactStamp(stamp) {
27
- const match = /^(\d{4}-\d{2}-\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(stamp);
28
- if (!match)
29
- return null;
30
- const iso = `${match[1]}T${match[2]}:${match[3]}:${match[4]}Z`;
31
- const date = new Date(iso);
32
- if (Number.isNaN(date.getTime()))
33
- return null;
34
- // Reject values that rolled over (e.g. month 13, day 32, hour 25).
35
- return toCompactStamp(date) === stamp ? date : null;
36
- }
37
- //# sourceMappingURL=time.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/core/time.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC;AAC/C,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC/B,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC;AAC7F,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IACE,CAAC,6EAA6E,CAAC,IAAI,CAAC,OAAO,CAAC,EAC5F,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,KAAK,GAAG,8CAA8C,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IAC/D,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,mEAAmE;IACnE,OAAO,cAAc,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC"}