@deskwork/core 0.9.5

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 (188) hide show
  1. package/dist/body-state.d.ts +27 -0
  2. package/dist/body-state.d.ts.map +1 -0
  3. package/dist/body-state.js +62 -0
  4. package/dist/body-state.js.map +1 -0
  5. package/dist/calendar-mutations.d.ts +124 -0
  6. package/dist/calendar-mutations.d.ts.map +1 -0
  7. package/dist/calendar-mutations.js +305 -0
  8. package/dist/calendar-mutations.js.map +1 -0
  9. package/dist/calendar.d.ts +54 -0
  10. package/dist/calendar.d.ts.map +1 -0
  11. package/dist/calendar.js +430 -0
  12. package/dist/calendar.js.map +1 -0
  13. package/dist/cli.d.ts +38 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +72 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/config.d.ts +91 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/config.js +216 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/content-index.d.ts +74 -0
  22. package/dist/content-index.d.ts.map +1 -0
  23. package/dist/content-index.js +205 -0
  24. package/dist/content-index.js.map +1 -0
  25. package/dist/content-tree-fs-walk.d.ts +54 -0
  26. package/dist/content-tree-fs-walk.d.ts.map +1 -0
  27. package/dist/content-tree-fs-walk.js +112 -0
  28. package/dist/content-tree-fs-walk.js.map +1 -0
  29. package/dist/content-tree-helpers.d.ts +52 -0
  30. package/dist/content-tree-helpers.d.ts.map +1 -0
  31. package/dist/content-tree-helpers.js +116 -0
  32. package/dist/content-tree-helpers.js.map +1 -0
  33. package/dist/content-tree-types.d.ts +175 -0
  34. package/dist/content-tree-types.d.ts.map +1 -0
  35. package/dist/content-tree-types.js +10 -0
  36. package/dist/content-tree-types.js.map +1 -0
  37. package/dist/content-tree.d.ts +93 -0
  38. package/dist/content-tree.d.ts.map +1 -0
  39. package/dist/content-tree.js +385 -0
  40. package/dist/content-tree.js.map +1 -0
  41. package/dist/doctor/index.d.ts +11 -0
  42. package/dist/doctor/index.d.ts.map +1 -0
  43. package/dist/doctor/index.js +10 -0
  44. package/dist/doctor/index.js.map +1 -0
  45. package/dist/doctor/project-rules.d.ts +59 -0
  46. package/dist/doctor/project-rules.d.ts.map +1 -0
  47. package/dist/doctor/project-rules.js +143 -0
  48. package/dist/doctor/project-rules.js.map +1 -0
  49. package/dist/doctor/rules/calendar-uuid-missing.d.ts +19 -0
  50. package/dist/doctor/rules/calendar-uuid-missing.d.ts.map +1 -0
  51. package/dist/doctor/rules/calendar-uuid-missing.js +176 -0
  52. package/dist/doctor/rules/calendar-uuid-missing.js.map +1 -0
  53. package/dist/doctor/rules/duplicate-id.d.ts +27 -0
  54. package/dist/doctor/rules/duplicate-id.d.ts.map +1 -0
  55. package/dist/doctor/rules/duplicate-id.js +157 -0
  56. package/dist/doctor/rules/duplicate-id.js.map +1 -0
  57. package/dist/doctor/rules/legacy-top-level-id-migration.d.ts +40 -0
  58. package/dist/doctor/rules/legacy-top-level-id-migration.d.ts.map +1 -0
  59. package/dist/doctor/rules/legacy-top-level-id-migration.js +232 -0
  60. package/dist/doctor/rules/legacy-top-level-id-migration.js.map +1 -0
  61. package/dist/doctor/rules/missing-frontmatter-id.d.ts +45 -0
  62. package/dist/doctor/rules/missing-frontmatter-id.d.ts.map +1 -0
  63. package/dist/doctor/rules/missing-frontmatter-id.js +283 -0
  64. package/dist/doctor/rules/missing-frontmatter-id.js.map +1 -0
  65. package/dist/doctor/rules/orphan-frontmatter-id.d.ts +18 -0
  66. package/dist/doctor/rules/orphan-frontmatter-id.d.ts.map +1 -0
  67. package/dist/doctor/rules/orphan-frontmatter-id.js +154 -0
  68. package/dist/doctor/rules/orphan-frontmatter-id.js.map +1 -0
  69. package/dist/doctor/rules/schema-rejected.d.ts +20 -0
  70. package/dist/doctor/rules/schema-rejected.d.ts.map +1 -0
  71. package/dist/doctor/rules/schema-rejected.js +44 -0
  72. package/dist/doctor/rules/schema-rejected.js.map +1 -0
  73. package/dist/doctor/rules/slug-collision.d.ts +18 -0
  74. package/dist/doctor/rules/slug-collision.d.ts.map +1 -0
  75. package/dist/doctor/rules/slug-collision.js +65 -0
  76. package/dist/doctor/rules/slug-collision.js.map +1 -0
  77. package/dist/doctor/rules/workflow-stale.d.ts +20 -0
  78. package/dist/doctor/rules/workflow-stale.d.ts.map +1 -0
  79. package/dist/doctor/rules/workflow-stale.js +136 -0
  80. package/dist/doctor/rules/workflow-stale.js.map +1 -0
  81. package/dist/doctor/runner.d.ts +75 -0
  82. package/dist/doctor/runner.d.ts.map +1 -0
  83. package/dist/doctor/runner.js +289 -0
  84. package/dist/doctor/runner.js.map +1 -0
  85. package/dist/doctor/schema-patch.d.ts +21 -0
  86. package/dist/doctor/schema-patch.d.ts.map +1 -0
  87. package/dist/doctor/schema-patch.js +92 -0
  88. package/dist/doctor/schema-patch.js.map +1 -0
  89. package/dist/doctor/types.d.ts +185 -0
  90. package/dist/doctor/types.d.ts.map +1 -0
  91. package/dist/doctor/types.js +13 -0
  92. package/dist/doctor/types.js.map +1 -0
  93. package/dist/frontmatter.d.ts +103 -0
  94. package/dist/frontmatter.d.ts.map +1 -0
  95. package/dist/frontmatter.js +306 -0
  96. package/dist/frontmatter.js.map +1 -0
  97. package/dist/index.d.ts +27 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +27 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/ingest-derive.d.ts +79 -0
  102. package/dist/ingest-derive.d.ts.map +1 -0
  103. package/dist/ingest-derive.js +299 -0
  104. package/dist/ingest-derive.js.map +1 -0
  105. package/dist/ingest-paths.d.ts +37 -0
  106. package/dist/ingest-paths.d.ts.map +1 -0
  107. package/dist/ingest-paths.js +176 -0
  108. package/dist/ingest-paths.js.map +1 -0
  109. package/dist/ingest.d.ts +162 -0
  110. package/dist/ingest.d.ts.map +1 -0
  111. package/dist/ingest.js +269 -0
  112. package/dist/ingest.js.map +1 -0
  113. package/dist/journal.d.ts +49 -0
  114. package/dist/journal.d.ts.map +1 -0
  115. package/dist/journal.js +113 -0
  116. package/dist/journal.js.map +1 -0
  117. package/dist/outline-split.d.ts +38 -0
  118. package/dist/outline-split.d.ts.map +1 -0
  119. package/dist/outline-split.js +84 -0
  120. package/dist/outline-split.js.map +1 -0
  121. package/dist/overrides.d.ts +83 -0
  122. package/dist/overrides.d.ts.map +1 -0
  123. package/dist/overrides.js +88 -0
  124. package/dist/overrides.js.map +1 -0
  125. package/dist/paths.d.ts +183 -0
  126. package/dist/paths.d.ts.map +1 -0
  127. package/dist/paths.js +266 -0
  128. package/dist/paths.js.map +1 -0
  129. package/dist/remark-image-figure.mjs +77 -0
  130. package/dist/remark-strip-first-h1.mjs +26 -0
  131. package/dist/remark-strip-outline.mjs +44 -0
  132. package/dist/rename-slug.d.ts +49 -0
  133. package/dist/rename-slug.d.ts.map +1 -0
  134. package/dist/rename-slug.js +161 -0
  135. package/dist/rename-slug.js.map +1 -0
  136. package/dist/review/handlers.d.ts +55 -0
  137. package/dist/review/handlers.d.ts.map +1 -0
  138. package/dist/review/handlers.js +307 -0
  139. package/dist/review/handlers.js.map +1 -0
  140. package/dist/review/index.d.ts +14 -0
  141. package/dist/review/index.d.ts.map +1 -0
  142. package/dist/review/index.js +13 -0
  143. package/dist/review/index.js.map +1 -0
  144. package/dist/review/journal-mappers.d.ts +35 -0
  145. package/dist/review/journal-mappers.d.ts.map +1 -0
  146. package/dist/review/journal-mappers.js +48 -0
  147. package/dist/review/journal-mappers.js.map +1 -0
  148. package/dist/review/pipeline.d.ts +79 -0
  149. package/dist/review/pipeline.d.ts.map +1 -0
  150. package/dist/review/pipeline.js +234 -0
  151. package/dist/review/pipeline.js.map +1 -0
  152. package/dist/review/render.d.ts +27 -0
  153. package/dist/review/render.d.ts.map +1 -0
  154. package/dist/review/render.js +42 -0
  155. package/dist/review/render.js.map +1 -0
  156. package/dist/review/report.d.ts +50 -0
  157. package/dist/review/report.d.ts.map +1 -0
  158. package/dist/review/report.js +164 -0
  159. package/dist/review/report.js.map +1 -0
  160. package/dist/review/result.d.ts +12 -0
  161. package/dist/review/result.d.ts.map +1 -0
  162. package/dist/review/result.js +12 -0
  163. package/dist/review/result.js.map +1 -0
  164. package/dist/review/start-handlers.d.ts +62 -0
  165. package/dist/review/start-handlers.d.ts.map +1 -0
  166. package/dist/review/start-handlers.js +223 -0
  167. package/dist/review/start-handlers.js.map +1 -0
  168. package/dist/review/types.d.ts +169 -0
  169. package/dist/review/types.d.ts.map +1 -0
  170. package/dist/review/types.js +26 -0
  171. package/dist/review/types.js.map +1 -0
  172. package/dist/review/workflow-paths.d.ts +68 -0
  173. package/dist/review/workflow-paths.d.ts.map +1 -0
  174. package/dist/review/workflow-paths.js +112 -0
  175. package/dist/review/workflow-paths.js.map +1 -0
  176. package/dist/scaffold.d.ts +67 -0
  177. package/dist/scaffold.d.ts.map +1 -0
  178. package/dist/scaffold.js +122 -0
  179. package/dist/scaffold.js.map +1 -0
  180. package/dist/scrapbook.d.ts +229 -0
  181. package/dist/scrapbook.d.ts.map +1 -0
  182. package/dist/scrapbook.js +500 -0
  183. package/dist/scrapbook.js.map +1 -0
  184. package/dist/types.d.ts +197 -0
  185. package/dist/types.d.ts.map +1 -0
  186. package/dist/types.js +120 -0
  187. package/dist/types.js.map +1 -0
  188. package/package.json +160 -0
@@ -0,0 +1,299 @@
1
+ /**
2
+ * ingest-derive.ts — slug / state / date / title derivation for ingest.
3
+ *
4
+ * Each `derive*` function takes the file's absolute path, its discovery
5
+ * root (for path-based slug derivation), the parsed frontmatter, the
6
+ * effective field-name table, and the operator's options. It returns a
7
+ * `<thing>Derivation` record that records both the derived value AND
8
+ * where it came from — the dry-run plan surfaces these sources so the
9
+ * operator can sanity-check before committing.
10
+ */
11
+ import { readdirSync, statSync } from 'node:fs';
12
+ import { join, relative, sep } from 'node:path';
13
+ import { isStage } from "./types.js";
14
+ import { MARKDOWN_EXTENSIONS } from "./ingest-paths.js";
15
+ const JEKYLL_RE = /^(\d{4})-(\d{2})-(\d{2})-(.+)$/;
16
+ const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
17
+ /**
18
+ * Canonical state-string normalization. Maps frontmatter values that
19
+ * editorial projects commonly use onto our six lanes. Anything outside
20
+ * this table comes back ambiguous — the operator must pass `--state`.
21
+ */
22
+ export const STATE_ALIASES = {
23
+ ideas: 'Ideas',
24
+ idea: 'Ideas',
25
+ ideas_lane: 'Ideas',
26
+ planned: 'Planned',
27
+ outlining: 'Outlining',
28
+ outline: 'Outlining',
29
+ drafting: 'Drafting',
30
+ draft: 'Drafting',
31
+ review: 'Review',
32
+ reviewing: 'Review',
33
+ 'in-review': 'Review',
34
+ in_review: 'Review',
35
+ published: 'Published',
36
+ publish: 'Published',
37
+ };
38
+ /**
39
+ * Derive a slug for a discovered file. Order:
40
+ *
41
+ * 1. `explicitSlug` (operator's `--slug`) — wins, marked 'explicit'.
42
+ * 2. When `slugFrom === 'frontmatter'`, the named frontmatter field
43
+ * (default `slug:`) when set; otherwise falls through to path.
44
+ * 3. Path-based derivation — see `slugFromPath`.
45
+ */
46
+ export function deriveSlug(input) {
47
+ if (input.explicitSlug !== undefined) {
48
+ return { value: input.explicitSlug, source: 'explicit' };
49
+ }
50
+ if (input.slugFrom === 'frontmatter') {
51
+ const fmSlug = readStringField(input.frontmatter, input.fieldName);
52
+ if (fmSlug !== undefined) {
53
+ return { value: fmSlug, source: 'frontmatter' };
54
+ }
55
+ // Fall through to path when frontmatter slug is missing.
56
+ }
57
+ return slugFromPath(input.filePath, input.root);
58
+ }
59
+ /**
60
+ * Path-based slug derivation. Computes the slug from the file's path
61
+ * relative to its discovery root, with hierarchical-bundle detection.
62
+ *
63
+ * Filename rules (first match wins):
64
+ * 1. `<dir>/index.md` or `<dir>/README.md` (case-insensitive) →
65
+ * drop the suffix; the dir name becomes the slug leaf.
66
+ * 2. Filename matches `YYYY-MM-DD-<slug>.<ext>` → strip date prefix
67
+ * and extension. Jekyll posts.
68
+ * 3. Otherwise → filename minus extension.
69
+ *
70
+ * Hierarchy: a directory between root and the file prefixes the slug
71
+ * if and only if it has its own `index.md` or `README.md`. Such a
72
+ * directory is itself a content node with a slug, and its children
73
+ * nest under it. Plain directories (no own leaf bundle) are
74
+ * "collection containers" — their names do NOT prefix child slugs.
75
+ */
76
+ function slugFromPath(filePath, root) {
77
+ const rel = relative(root, filePath);
78
+ const segments = rel.split(sep).filter((s) => s.length > 0);
79
+ if (segments.length === 0) {
80
+ return { value: '', source: 'path', reason: 'file path equals root' };
81
+ }
82
+ const filename = segments[segments.length - 1];
83
+ const dot = filename.lastIndexOf('.');
84
+ const base = dot > 0 ? filename.slice(0, dot) : filename;
85
+ const baseLower = base.toLowerCase();
86
+ let leafSegments;
87
+ let dirSegments;
88
+ if (baseLower === 'index' || baseLower === 'readme') {
89
+ if (segments.length < 2) {
90
+ // Leaf-bundle file at the discovery root — root's basename
91
+ // becomes the slug (the case for a single-file argument like
92
+ // `<...>/strivers/index.md` where root = `<...>/strivers`).
93
+ const rootSegments = root.split(sep).filter((s) => s.length > 0);
94
+ const rootLeaf = rootSegments[rootSegments.length - 1];
95
+ if (!rootLeaf) {
96
+ return {
97
+ value: '',
98
+ source: 'path',
99
+ reason: `${filename} at the filesystem root has no directory name to derive a slug from`,
100
+ };
101
+ }
102
+ leafSegments = [rootLeaf];
103
+ dirSegments = [];
104
+ }
105
+ else {
106
+ leafSegments = [segments[segments.length - 2]];
107
+ dirSegments = segments.slice(0, -2);
108
+ }
109
+ }
110
+ else {
111
+ const jekyll = base.match(JEKYLL_RE);
112
+ leafSegments = [jekyll ? jekyll[4] : base];
113
+ dirSegments = segments.slice(0, -1);
114
+ }
115
+ // Walk directory ancestors from root → leaf. Each ancestor
116
+ // contributes to the slug only if it has its own index.md or
117
+ // README.md (i.e. it's itself a content node, not just a folder).
118
+ const prefix = [];
119
+ // Special case: when the discovery root itself is a content node
120
+ // (has its own index.md/README.md), its basename prefixes child
121
+ // slugs. Skip when leafSegments already equals the root's basename
122
+ // (the case when the discovered file IS the root's own index.md —
123
+ // handled above by setting leafSegments to the root's name).
124
+ if (directoryIsHierarchicalNode(root)) {
125
+ const rootSegments = root.split(sep).filter((s) => s.length > 0);
126
+ const rootLeaf = rootSegments[rootSegments.length - 1];
127
+ if (rootLeaf && leafSegments[0] !== rootLeaf) {
128
+ prefix.push(rootLeaf);
129
+ }
130
+ }
131
+ let cursor = root;
132
+ for (const dir of dirSegments) {
133
+ cursor = join(cursor, dir);
134
+ if (directoryIsHierarchicalNode(cursor)) {
135
+ prefix.push(dir);
136
+ }
137
+ else {
138
+ // Once an ancestor isn't itself a content node, the chain
139
+ // ends — the operator put a non-tracked folder between
140
+ // content nodes, so that folder's name shouldn't bleed in.
141
+ prefix.length = 0;
142
+ }
143
+ }
144
+ return { value: [...prefix, ...leafSegments].join('/'), source: 'path' };
145
+ }
146
+ /**
147
+ * True if `dir` itself has a leaf bundle (index.md / README.md /
148
+ * index.mdx / README.mdx / etc.) — i.e. it's a content node whose
149
+ * name should prefix its children's slugs.
150
+ */
151
+ function directoryIsHierarchicalNode(dir) {
152
+ let entries;
153
+ try {
154
+ entries = readdirSync(dir, { withFileTypes: true });
155
+ }
156
+ catch {
157
+ return false;
158
+ }
159
+ for (const entry of entries) {
160
+ if (!entry.isFile())
161
+ continue;
162
+ const lower = entry.name.toLowerCase();
163
+ for (const ext of MARKDOWN_EXTENSIONS) {
164
+ if (lower === `index${ext}` || lower === `readme${ext}`) {
165
+ return true;
166
+ }
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+ export function deriveState(input) {
172
+ if (input.explicitState !== undefined) {
173
+ return { value: input.explicitState, source: 'explicit' };
174
+ }
175
+ if (input.stateFrom === 'frontmatter') {
176
+ const raw = readStringField(input.frontmatter, input.stateField);
177
+ if (raw === undefined) {
178
+ // No state field — default to Ideas as the safest lane. The
179
+ // value did NOT come from the file; mark the source as
180
+ // `'default'` so the audit trail doesn't lie (#23).
181
+ return { value: 'Ideas', source: 'default' };
182
+ }
183
+ const normalized = normalizeStateString(raw);
184
+ if (normalized === null) {
185
+ return { value: null, source: 'frontmatter', rawValue: raw };
186
+ }
187
+ return { value: normalized, source: 'frontmatter' };
188
+ }
189
+ // stateFrom === 'datePublished'
190
+ const dateRaw = readDateField(input.frontmatter, input.dateField);
191
+ if (dateRaw === undefined) {
192
+ // No datePublished — same Ideas fallback as above; same provenance
193
+ // honesty applies (#23).
194
+ return { value: 'Ideas', source: 'default' };
195
+ }
196
+ const today = (input.now ?? new Date()).toISOString().slice(0, 10);
197
+ if (dateRaw <= today) {
198
+ return { value: 'Published', source: 'frontmatter' };
199
+ }
200
+ return { value: 'Drafting', source: 'frontmatter' };
201
+ }
202
+ function normalizeStateString(raw) {
203
+ const key = raw.trim().toLowerCase();
204
+ if (key.length === 0)
205
+ return null;
206
+ const direct = STATE_ALIASES[key];
207
+ if (direct)
208
+ return direct;
209
+ // Stage names verbatim (Title-cased) — accept them too.
210
+ const titled = key.charAt(0).toUpperCase() + key.slice(1);
211
+ if (isStage(titled))
212
+ return titled;
213
+ return null;
214
+ }
215
+ export function deriveDate(input) {
216
+ if (input.explicitDate !== undefined) {
217
+ return { value: input.explicitDate, source: 'explicit' };
218
+ }
219
+ const fmDate = readDateField(input.frontmatter, input.dateField);
220
+ if (fmDate !== undefined) {
221
+ return { value: fmDate, source: 'frontmatter' };
222
+ }
223
+ // Try the secondary `date` field too, when the primary one was
224
+ // overridden — `--date-field datePublished` should still find a
225
+ // generic `date:` as a backstop.
226
+ if (input.dateField !== 'date') {
227
+ const generic = readDateField(input.frontmatter, 'date');
228
+ if (generic !== undefined) {
229
+ return { value: generic, source: 'frontmatter' };
230
+ }
231
+ }
232
+ // mtime fallback — accurate enough for "approximately when the
233
+ // operator wrote this", but the operator can override with --date.
234
+ try {
235
+ const stat = statSync(input.filePath);
236
+ return { value: stat.mtime.toISOString().slice(0, 10), source: 'mtime' };
237
+ }
238
+ catch {
239
+ // Should never happen — we just read the file. Fall through.
240
+ }
241
+ const today = (input.now ?? new Date()).toISOString().slice(0, 10);
242
+ return { value: today, source: 'today' };
243
+ }
244
+ // ---------------------------------------------------------------------------
245
+ // Title / description
246
+ // ---------------------------------------------------------------------------
247
+ export function deriveTitle(frontmatter, fieldName, slug) {
248
+ const raw = readStringField(frontmatter, fieldName);
249
+ if (raw !== undefined && raw.length > 0)
250
+ return raw;
251
+ // Humanize the slug as a last resort. Strip leading hierarchy
252
+ // segments — title for `the-outbound/characters/strivers` should
253
+ // be "Strivers", not "The Outbound Characters Strivers".
254
+ const leaf = slug.split('/').pop() ?? slug;
255
+ return leaf
256
+ .split('-')
257
+ .map((w) => (w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w))
258
+ .join(' ');
259
+ }
260
+ export function deriveDescription(frontmatter, fieldName) {
261
+ return readStringField(frontmatter, fieldName) ?? '';
262
+ }
263
+ // ---------------------------------------------------------------------------
264
+ // Field readers
265
+ // ---------------------------------------------------------------------------
266
+ function readStringField(frontmatter, field) {
267
+ const value = frontmatter[field];
268
+ if (typeof value !== 'string')
269
+ return undefined;
270
+ const trimmed = value.trim();
271
+ return trimmed.length > 0 ? trimmed : undefined;
272
+ }
273
+ /**
274
+ * Read a date-like field. YAML may parse `2024-01-15` as a Date or as
275
+ * a string depending on quoting. Both shapes resolve to YYYY-MM-DD.
276
+ * Anything else returns undefined.
277
+ */
278
+ function readDateField(frontmatter, field) {
279
+ const value = frontmatter[field];
280
+ if (value === undefined || value === null)
281
+ return undefined;
282
+ if (value instanceof Date) {
283
+ return value.toISOString().slice(0, 10);
284
+ }
285
+ if (typeof value === 'string') {
286
+ const trimmed = value.trim();
287
+ if (ISO_DATE_RE.test(trimmed))
288
+ return trimmed;
289
+ // Try Date.parse for non-ISO formats — the operator's frontmatter
290
+ // might be `date: 2024/01/15` or `date: January 15, 2024`. Parse
291
+ // leniently and serialize as ISO.
292
+ const parsed = Date.parse(trimmed);
293
+ if (!Number.isNaN(parsed)) {
294
+ return new Date(parsed).toISOString().slice(0, 10);
295
+ }
296
+ }
297
+ return undefined;
298
+ }
299
+ //# sourceMappingURL=ingest-derive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-derive.js","sourceRoot":"","sources":["../src/ingest-derive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ingest-paths.ts — markdown file collection for ingest discovery.
3
+ *
4
+ * Walks a list of operator-supplied paths (file / directory / glob)
5
+ * and produces a deduplicated, deterministically-ordered list of
6
+ * `CollectedFile` records — each one a markdown file paired with the
7
+ * "discovery root" it was found under. The root is what slug derivation
8
+ * uses to compute the file's path-relative slug.
9
+ *
10
+ * Glob expansion is hand-rolled to avoid pulling a dep onto the
11
+ * discovery hot path. The supported pattern surface — `*`, `**`, `?`,
12
+ * `[...]` — covers every operator pattern surfaced in the issue (e.g.
13
+ * `src/content/essays/​**​/*.md`).
14
+ */
15
+ declare const MARKDOWN_EXTENSIONS: readonly [".md", ".mdx", ".markdown"];
16
+ /**
17
+ * A discovered markdown file paired with its discovery root — the
18
+ * directory the operator's path argument resolved to (or the deepest
19
+ * static prefix for a glob). Slug derivation computes the slug as
20
+ * the file's path relative to this root, so siblings of a flat
21
+ * collection ("essays/foo/index.md", "essays/bar/index.md") get
22
+ * unprefixed slugs while deeper nesting produces hierarchical slugs.
23
+ */
24
+ export interface CollectedFile {
25
+ filePath: string;
26
+ root: string;
27
+ }
28
+ /**
29
+ * Walk every supplied path and return a deduplicated, sorted list of
30
+ * `CollectedFile` records. First-seen wins for root attribution: if
31
+ * the same file is reachable from two paths the operator passed, the
32
+ * first path's discovery root is canonical.
33
+ */
34
+ export declare function collectMarkdownFiles(paths: string[]): CollectedFile[];
35
+ export declare function hasMarkdownExtension(filename: string): boolean;
36
+ export { MARKDOWN_EXTENSIONS };
37
+ //# sourceMappingURL=ingest-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-paths.d.ts","sourceRoot":"","sources":["../src/ingest-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,QAAA,MAAM,mBAAmB,uCAAwC,CAAC;AAElE;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAYrE;AAqJD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG9D;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * ingest-paths.ts — markdown file collection for ingest discovery.
3
+ *
4
+ * Walks a list of operator-supplied paths (file / directory / glob)
5
+ * and produces a deduplicated, deterministically-ordered list of
6
+ * `CollectedFile` records — each one a markdown file paired with the
7
+ * "discovery root" it was found under. The root is what slug derivation
8
+ * uses to compute the file's path-relative slug.
9
+ *
10
+ * Glob expansion is hand-rolled to avoid pulling a dep onto the
11
+ * discovery hot path. The supported pattern surface — `*`, `**`, `?`,
12
+ * `[...]` — covers every operator pattern surfaced in the issue (e.g.
13
+ * `src/content/essays/​**​/*.md`).
14
+ */
15
+ import { existsSync, readdirSync, statSync, } from 'node:fs';
16
+ import { isAbsolute, join, resolve, sep } from 'node:path';
17
+ const MARKDOWN_EXTENSIONS = ['.md', '.mdx', '.markdown'];
18
+ /**
19
+ * Walk every supplied path and return a deduplicated, sorted list of
20
+ * `CollectedFile` records. First-seen wins for root attribution: if
21
+ * the same file is reachable from two paths the operator passed, the
22
+ * first path's discovery root is canonical.
23
+ */
24
+ export function collectMarkdownFiles(paths) {
25
+ const seen = new Map();
26
+ for (const p of paths) {
27
+ for (const file of expandPath(p)) {
28
+ if (!seen.has(file.filePath)) {
29
+ seen.set(file.filePath, file);
30
+ }
31
+ }
32
+ }
33
+ return [...seen.values()].sort((a, b) => a.filePath.localeCompare(b.filePath));
34
+ }
35
+ function expandPath(input) {
36
+ const absolute = isAbsolute(input) ? input : resolve(process.cwd(), input);
37
+ if (containsGlob(input)) {
38
+ return expandGlob(absolute);
39
+ }
40
+ if (!existsSync(absolute)) {
41
+ throw new Error(`Path does not exist: ${input}`);
42
+ }
43
+ const stat = statSync(absolute);
44
+ if (stat.isFile()) {
45
+ if (!hasMarkdownExtension(absolute)) {
46
+ throw new Error(`Path is not a markdown file: ${input} (expected one of ${MARKDOWN_EXTENSIONS.join(', ')})`);
47
+ }
48
+ // For a single-file argument the discovery root is the file's
49
+ // parent — no hierarchical prefix.
50
+ return [{ filePath: absolute, root: dirnameOf(absolute) }];
51
+ }
52
+ if (stat.isDirectory()) {
53
+ return walkDirectory(absolute, absolute);
54
+ }
55
+ return [];
56
+ }
57
+ function dirnameOf(filePath) {
58
+ const idx = filePath.lastIndexOf(sep);
59
+ if (idx <= 0)
60
+ return sep;
61
+ return filePath.slice(0, idx);
62
+ }
63
+ function walkDirectory(dir, root) {
64
+ const out = [];
65
+ const entries = readdirSync(dir, { withFileTypes: true });
66
+ for (const entry of entries) {
67
+ const child = join(dir, entry.name);
68
+ if (entry.isDirectory()) {
69
+ out.push(...walkDirectory(child, root));
70
+ }
71
+ else if (entry.isFile() && hasMarkdownExtension(entry.name)) {
72
+ out.push({ filePath: child, root });
73
+ }
74
+ }
75
+ return out;
76
+ }
77
+ function containsGlob(input) {
78
+ return /[*?[]/.test(input);
79
+ }
80
+ /**
81
+ * Minimal glob expansion supporting `*`, `**`, `?`, and `[...]`.
82
+ *
83
+ * The deepest static prefix becomes the discovery root so slugs are
84
+ * computed relative to it (e.g. `src/posts/​**​/*.md` uses `src/posts`
85
+ * as the slug-derivation root).
86
+ */
87
+ function expandGlob(absolutePattern) {
88
+ const segments = absolutePattern.split(sep);
89
+ let rootEnd = 0;
90
+ for (let i = 0; i < segments.length; i++) {
91
+ if (containsGlob(segments[i]))
92
+ break;
93
+ rootEnd = i;
94
+ }
95
+ const root = segments.slice(0, rootEnd + 1).join(sep) || sep;
96
+ const remainder = segments.slice(rootEnd + 1);
97
+ if (!existsSync(root)) {
98
+ return [];
99
+ }
100
+ return matchPattern(root, remainder, root);
101
+ }
102
+ function matchPattern(currentDir, remaining, root) {
103
+ if (remaining.length === 0) {
104
+ if (statSync(currentDir).isFile() && hasMarkdownExtension(currentDir)) {
105
+ return [{ filePath: currentDir, root }];
106
+ }
107
+ return [];
108
+ }
109
+ const [head, ...rest] = remaining;
110
+ const out = [];
111
+ let entries;
112
+ try {
113
+ entries = readdirSync(currentDir, { withFileTypes: true });
114
+ }
115
+ catch {
116
+ return out;
117
+ }
118
+ if (head === '**') {
119
+ // Match zero or more directories, then continue with `rest`.
120
+ out.push(...matchPattern(currentDir, rest, root));
121
+ for (const entry of entries) {
122
+ if (entry.isDirectory()) {
123
+ out.push(...matchPattern(join(currentDir, entry.name), remaining, root));
124
+ }
125
+ }
126
+ return out;
127
+ }
128
+ const matcher = globSegmentMatcher(head);
129
+ for (const entry of entries) {
130
+ if (!matcher(entry.name))
131
+ continue;
132
+ const child = join(currentDir, entry.name);
133
+ if (rest.length === 0) {
134
+ if (entry.isFile() && hasMarkdownExtension(entry.name)) {
135
+ out.push({ filePath: child, root });
136
+ }
137
+ }
138
+ else if (entry.isDirectory()) {
139
+ out.push(...matchPattern(child, rest, root));
140
+ }
141
+ }
142
+ return out;
143
+ }
144
+ function globSegmentMatcher(pattern) {
145
+ let re = '^';
146
+ for (let i = 0; i < pattern.length; i++) {
147
+ const ch = pattern[i];
148
+ if (ch === '*')
149
+ re += '[^/]*';
150
+ else if (ch === '?')
151
+ re += '[^/]';
152
+ else if (ch === '[') {
153
+ const close = pattern.indexOf(']', i);
154
+ if (close === -1) {
155
+ re += '\\[';
156
+ }
157
+ else {
158
+ re += pattern.slice(i, close + 1);
159
+ i = close;
160
+ }
161
+ }
162
+ else if (/[\\^$+().{}|]/.test(ch))
163
+ re += `\\${ch}`;
164
+ else
165
+ re += ch;
166
+ }
167
+ re += '$';
168
+ const compiled = new RegExp(re);
169
+ return (name) => compiled.test(name);
170
+ }
171
+ export function hasMarkdownExtension(filename) {
172
+ const lower = filename.toLowerCase();
173
+ return MARKDOWN_EXTENSIONS.some((ext) => lower.endsWith(ext));
174
+ }
175
+ export { MARKDOWN_EXTENSIONS };
176
+ //# sourceMappingURL=ingest-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-paths.js","sourceRoot":"","sources":["../src/ingest-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,UAAU,EACV,WAAW,EACX,QAAQ,GACT,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAE3D,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAU,CAAC;AAelE;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAe;IAClD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACtC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CACrC,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IAE3E,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAClB,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACb,gCAAgC,KAAK,qBAAqB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5F,CAAC;QACJ,CAAC;QACD,8DAA8D;QAC9D,mCAAmC;QACnC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACvB,OAAO,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,SAAS,CAAC,QAAgB;IACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IACzB,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,GAAW,EAAE,IAAY;IAC9C,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1C,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,eAAuB;IACzC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAAE,MAAM;QACrC,OAAO,GAAG,CAAC,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IAC7D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAE9C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,YAAY,CACnB,UAAkB,EAClB,SAAmB,EACnB,IAAY;IAEZ,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,IAAI,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;YACtE,OAAO,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,MAAM,GAAG,GAAoB,EAAE,CAAC;IAEhC,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,6DAA6D;QAC7D,GAAG,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAClD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,GAAG,CAAC,IAAI,CACN,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvD,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YAC/B,GAAG,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAe;IACzC,IAAI,EAAE,GAAG,GAAG,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,GAAG;YAAE,EAAE,IAAI,OAAO,CAAC;aACzB,IAAI,EAAE,KAAK,GAAG;YAAE,EAAE,IAAI,MAAM,CAAC;aAC7B,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACtC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,EAAE,IAAI,KAAK,CAAC;YACd,CAAC;iBAAM,CAAC;gBACN,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;gBAClC,CAAC,GAAG,KAAK,CAAC;YACZ,CAAC;QACH,CAAC;aAAM,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,EAAE,IAAI,KAAK,EAAE,EAAE,CAAC;;YAChD,EAAE,IAAI,EAAE,CAAC;IAChB,CAAC;IACD,EAAE,IAAI,GAAG,CAAC;IACV,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC;IAChC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}