@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.
- package/dist/body-state.d.ts +27 -0
- package/dist/body-state.d.ts.map +1 -0
- package/dist/body-state.js +62 -0
- package/dist/body-state.js.map +1 -0
- package/dist/calendar-mutations.d.ts +124 -0
- package/dist/calendar-mutations.d.ts.map +1 -0
- package/dist/calendar-mutations.js +305 -0
- package/dist/calendar-mutations.js.map +1 -0
- package/dist/calendar.d.ts +54 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +430 -0
- package/dist/calendar.js.map +1 -0
- package/dist/cli.d.ts +38 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +72 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +91 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +216 -0
- package/dist/config.js.map +1 -0
- package/dist/content-index.d.ts +74 -0
- package/dist/content-index.d.ts.map +1 -0
- package/dist/content-index.js +205 -0
- package/dist/content-index.js.map +1 -0
- package/dist/content-tree-fs-walk.d.ts +54 -0
- package/dist/content-tree-fs-walk.d.ts.map +1 -0
- package/dist/content-tree-fs-walk.js +112 -0
- package/dist/content-tree-fs-walk.js.map +1 -0
- package/dist/content-tree-helpers.d.ts +52 -0
- package/dist/content-tree-helpers.d.ts.map +1 -0
- package/dist/content-tree-helpers.js +116 -0
- package/dist/content-tree-helpers.js.map +1 -0
- package/dist/content-tree-types.d.ts +175 -0
- package/dist/content-tree-types.d.ts.map +1 -0
- package/dist/content-tree-types.js +10 -0
- package/dist/content-tree-types.js.map +1 -0
- package/dist/content-tree.d.ts +93 -0
- package/dist/content-tree.d.ts.map +1 -0
- package/dist/content-tree.js +385 -0
- package/dist/content-tree.js.map +1 -0
- package/dist/doctor/index.d.ts +11 -0
- package/dist/doctor/index.d.ts.map +1 -0
- package/dist/doctor/index.js +10 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/doctor/project-rules.d.ts +59 -0
- package/dist/doctor/project-rules.d.ts.map +1 -0
- package/dist/doctor/project-rules.js +143 -0
- package/dist/doctor/project-rules.js.map +1 -0
- package/dist/doctor/rules/calendar-uuid-missing.d.ts +19 -0
- package/dist/doctor/rules/calendar-uuid-missing.d.ts.map +1 -0
- package/dist/doctor/rules/calendar-uuid-missing.js +176 -0
- package/dist/doctor/rules/calendar-uuid-missing.js.map +1 -0
- package/dist/doctor/rules/duplicate-id.d.ts +27 -0
- package/dist/doctor/rules/duplicate-id.d.ts.map +1 -0
- package/dist/doctor/rules/duplicate-id.js +157 -0
- package/dist/doctor/rules/duplicate-id.js.map +1 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.d.ts +40 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.d.ts.map +1 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.js +232 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.js.map +1 -0
- package/dist/doctor/rules/missing-frontmatter-id.d.ts +45 -0
- package/dist/doctor/rules/missing-frontmatter-id.d.ts.map +1 -0
- package/dist/doctor/rules/missing-frontmatter-id.js +283 -0
- package/dist/doctor/rules/missing-frontmatter-id.js.map +1 -0
- package/dist/doctor/rules/orphan-frontmatter-id.d.ts +18 -0
- package/dist/doctor/rules/orphan-frontmatter-id.d.ts.map +1 -0
- package/dist/doctor/rules/orphan-frontmatter-id.js +154 -0
- package/dist/doctor/rules/orphan-frontmatter-id.js.map +1 -0
- package/dist/doctor/rules/schema-rejected.d.ts +20 -0
- package/dist/doctor/rules/schema-rejected.d.ts.map +1 -0
- package/dist/doctor/rules/schema-rejected.js +44 -0
- package/dist/doctor/rules/schema-rejected.js.map +1 -0
- package/dist/doctor/rules/slug-collision.d.ts +18 -0
- package/dist/doctor/rules/slug-collision.d.ts.map +1 -0
- package/dist/doctor/rules/slug-collision.js +65 -0
- package/dist/doctor/rules/slug-collision.js.map +1 -0
- package/dist/doctor/rules/workflow-stale.d.ts +20 -0
- package/dist/doctor/rules/workflow-stale.d.ts.map +1 -0
- package/dist/doctor/rules/workflow-stale.js +136 -0
- package/dist/doctor/rules/workflow-stale.js.map +1 -0
- package/dist/doctor/runner.d.ts +75 -0
- package/dist/doctor/runner.d.ts.map +1 -0
- package/dist/doctor/runner.js +289 -0
- package/dist/doctor/runner.js.map +1 -0
- package/dist/doctor/schema-patch.d.ts +21 -0
- package/dist/doctor/schema-patch.d.ts.map +1 -0
- package/dist/doctor/schema-patch.js +92 -0
- package/dist/doctor/schema-patch.js.map +1 -0
- package/dist/doctor/types.d.ts +185 -0
- package/dist/doctor/types.d.ts.map +1 -0
- package/dist/doctor/types.js +13 -0
- package/dist/doctor/types.js.map +1 -0
- package/dist/frontmatter.d.ts +103 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +306 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest-derive.d.ts +79 -0
- package/dist/ingest-derive.d.ts.map +1 -0
- package/dist/ingest-derive.js +299 -0
- package/dist/ingest-derive.js.map +1 -0
- package/dist/ingest-paths.d.ts +37 -0
- package/dist/ingest-paths.d.ts.map +1 -0
- package/dist/ingest-paths.js +176 -0
- package/dist/ingest-paths.js.map +1 -0
- package/dist/ingest.d.ts +162 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +269 -0
- package/dist/ingest.js.map +1 -0
- package/dist/journal.d.ts +49 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +113 -0
- package/dist/journal.js.map +1 -0
- package/dist/outline-split.d.ts +38 -0
- package/dist/outline-split.d.ts.map +1 -0
- package/dist/outline-split.js +84 -0
- package/dist/outline-split.js.map +1 -0
- package/dist/overrides.d.ts +83 -0
- package/dist/overrides.d.ts.map +1 -0
- package/dist/overrides.js +88 -0
- package/dist/overrides.js.map +1 -0
- package/dist/paths.d.ts +183 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +266 -0
- package/dist/paths.js.map +1 -0
- package/dist/remark-image-figure.mjs +77 -0
- package/dist/remark-strip-first-h1.mjs +26 -0
- package/dist/remark-strip-outline.mjs +44 -0
- package/dist/rename-slug.d.ts +49 -0
- package/dist/rename-slug.d.ts.map +1 -0
- package/dist/rename-slug.js +161 -0
- package/dist/rename-slug.js.map +1 -0
- package/dist/review/handlers.d.ts +55 -0
- package/dist/review/handlers.d.ts.map +1 -0
- package/dist/review/handlers.js +307 -0
- package/dist/review/handlers.js.map +1 -0
- package/dist/review/index.d.ts +14 -0
- package/dist/review/index.d.ts.map +1 -0
- package/dist/review/index.js +13 -0
- package/dist/review/index.js.map +1 -0
- package/dist/review/journal-mappers.d.ts +35 -0
- package/dist/review/journal-mappers.d.ts.map +1 -0
- package/dist/review/journal-mappers.js +48 -0
- package/dist/review/journal-mappers.js.map +1 -0
- package/dist/review/pipeline.d.ts +79 -0
- package/dist/review/pipeline.d.ts.map +1 -0
- package/dist/review/pipeline.js +234 -0
- package/dist/review/pipeline.js.map +1 -0
- package/dist/review/render.d.ts +27 -0
- package/dist/review/render.d.ts.map +1 -0
- package/dist/review/render.js +42 -0
- package/dist/review/render.js.map +1 -0
- package/dist/review/report.d.ts +50 -0
- package/dist/review/report.d.ts.map +1 -0
- package/dist/review/report.js +164 -0
- package/dist/review/report.js.map +1 -0
- package/dist/review/result.d.ts +12 -0
- package/dist/review/result.d.ts.map +1 -0
- package/dist/review/result.js +12 -0
- package/dist/review/result.js.map +1 -0
- package/dist/review/start-handlers.d.ts +62 -0
- package/dist/review/start-handlers.d.ts.map +1 -0
- package/dist/review/start-handlers.js +223 -0
- package/dist/review/start-handlers.js.map +1 -0
- package/dist/review/types.d.ts +169 -0
- package/dist/review/types.d.ts.map +1 -0
- package/dist/review/types.js +26 -0
- package/dist/review/types.js.map +1 -0
- package/dist/review/workflow-paths.d.ts +68 -0
- package/dist/review/workflow-paths.d.ts.map +1 -0
- package/dist/review/workflow-paths.js +112 -0
- package/dist/review/workflow-paths.js.map +1 -0
- package/dist/scaffold.d.ts +67 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +122 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/scrapbook.d.ts +229 -0
- package/dist/scrapbook.d.ts.map +1 -0
- package/dist/scrapbook.js +500 -0
- package/dist/scrapbook.js.map +1 -0
- package/dist/types.d.ts +197 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +120 -0
- package/dist/types.js.map +1 -0
- package/package.json +160 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,wEAAwE;AACxE,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,iCAAiC;AACjC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,cAAc,CAAC;IAC/B,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAqBD,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAwE1D;AA+ID,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAoB9D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deskwork plugin configuration.
|
|
3
|
+
*
|
|
4
|
+
* A host project is "installed" by writing a `.deskwork/config.json` at the
|
|
5
|
+
* project root. The config tells the plugin where content lives, where to
|
|
6
|
+
* keep the editorial calendar, and which sites the project hosts.
|
|
7
|
+
*
|
|
8
|
+
* The schema is intentionally minimal — one version, one set of required
|
|
9
|
+
* fields per site, no hidden defaults. `parseConfig` validates an unknown
|
|
10
|
+
* JSON value and returns a typed DeskworkConfig or throws an Error whose
|
|
11
|
+
* message tells the user which field is wrong.
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
/** Current config schema version. Bumped only with a migration path. */
|
|
16
|
+
export const CONFIG_VERSION = 1;
|
|
17
|
+
const ALLOWED_TOP_LEVEL_KEYS = new Set([
|
|
18
|
+
'version',
|
|
19
|
+
'sites',
|
|
20
|
+
'defaultSite',
|
|
21
|
+
'author',
|
|
22
|
+
'reviewJournalDir',
|
|
23
|
+
]);
|
|
24
|
+
const REQUIRED_SITE_KEYS = ['contentDir', 'calendarPath'];
|
|
25
|
+
const ALLOWED_SITE_KEYS = new Set([
|
|
26
|
+
...REQUIRED_SITE_KEYS,
|
|
27
|
+
'host',
|
|
28
|
+
'channelsPath',
|
|
29
|
+
'blogLayout',
|
|
30
|
+
'blogFilenameTemplate',
|
|
31
|
+
'blogInitialState',
|
|
32
|
+
'blogOutlineSection',
|
|
33
|
+
'redirectsPath',
|
|
34
|
+
]);
|
|
35
|
+
/** Return the absolute path to `.deskwork/config.json` under a project root. */
|
|
36
|
+
export function configPath(projectRoot) {
|
|
37
|
+
return join(projectRoot, '.deskwork', 'config.json');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validate and normalize an unknown value as a DeskworkConfig.
|
|
41
|
+
*
|
|
42
|
+
* Throws an Error with a specific message when the value doesn't match the
|
|
43
|
+
* schema. On success, returns a fresh typed object — callers can mutate it
|
|
44
|
+
* without worrying about shared references.
|
|
45
|
+
*/
|
|
46
|
+
export function parseConfig(value) {
|
|
47
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
48
|
+
throw new Error(`Invalid deskwork config: expected a JSON object, got ${describe(value)}.`);
|
|
49
|
+
}
|
|
50
|
+
const obj = value;
|
|
51
|
+
for (const key of Object.keys(obj)) {
|
|
52
|
+
if (!ALLOWED_TOP_LEVEL_KEYS.has(key)) {
|
|
53
|
+
throw new Error(`Invalid deskwork config: unknown key "${key}". ` +
|
|
54
|
+
`Allowed keys: ${[...ALLOWED_TOP_LEVEL_KEYS].join(', ')}.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (obj.version !== CONFIG_VERSION) {
|
|
58
|
+
throw new Error(`Invalid deskwork config: expected version ${CONFIG_VERSION}, got ${JSON.stringify(obj.version)}. Run /deskwork:install to regenerate the config.`);
|
|
59
|
+
}
|
|
60
|
+
const sitesValue = obj.sites;
|
|
61
|
+
if (sitesValue === undefined ||
|
|
62
|
+
sitesValue === null ||
|
|
63
|
+
typeof sitesValue !== 'object' ||
|
|
64
|
+
Array.isArray(sitesValue)) {
|
|
65
|
+
throw new Error(`Invalid deskwork config: "sites" must be an object keyed by site slug.`);
|
|
66
|
+
}
|
|
67
|
+
const siteSlugs = Object.keys(sitesValue);
|
|
68
|
+
if (siteSlugs.length === 0) {
|
|
69
|
+
throw new Error(`Invalid deskwork config: at least one site must be defined under "sites".`);
|
|
70
|
+
}
|
|
71
|
+
const sites = {};
|
|
72
|
+
for (const slug of siteSlugs) {
|
|
73
|
+
sites[slug] = parseSiteConfig(slug, sitesValue[slug]);
|
|
74
|
+
}
|
|
75
|
+
const defaultSite = resolveDefaultSite(obj.defaultSite, siteSlugs);
|
|
76
|
+
const config = { version: CONFIG_VERSION, sites, defaultSite };
|
|
77
|
+
if (obj.author !== undefined) {
|
|
78
|
+
if (typeof obj.author !== 'string' || obj.author.length === 0) {
|
|
79
|
+
throw new Error(`Invalid deskwork config: "author" must be a non-empty string when set.`);
|
|
80
|
+
}
|
|
81
|
+
config.author = obj.author;
|
|
82
|
+
}
|
|
83
|
+
if (obj.reviewJournalDir !== undefined) {
|
|
84
|
+
if (typeof obj.reviewJournalDir !== 'string' ||
|
|
85
|
+
obj.reviewJournalDir.length === 0) {
|
|
86
|
+
throw new Error(`Invalid deskwork config: "reviewJournalDir" must be a non-empty string when set.`);
|
|
87
|
+
}
|
|
88
|
+
config.reviewJournalDir = obj.reviewJournalDir;
|
|
89
|
+
}
|
|
90
|
+
return config;
|
|
91
|
+
}
|
|
92
|
+
function parseSiteConfig(slug, value) {
|
|
93
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
94
|
+
throw new Error(`Invalid deskwork config: site "${slug}" must be an object, got ${describe(value)}.`);
|
|
95
|
+
}
|
|
96
|
+
const obj = value;
|
|
97
|
+
for (const key of Object.keys(obj)) {
|
|
98
|
+
if (!ALLOWED_SITE_KEYS.has(key)) {
|
|
99
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has unknown key "${key}". ` +
|
|
100
|
+
`Allowed keys: ${[...ALLOWED_SITE_KEYS].join(', ')}.`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const key of REQUIRED_SITE_KEYS) {
|
|
104
|
+
const v = obj[key];
|
|
105
|
+
if (typeof v !== 'string' || v.length === 0) {
|
|
106
|
+
throw new Error(`Invalid deskwork config: site "${slug}" is missing required field "${key}" ` +
|
|
107
|
+
`(must be a non-empty string).`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const site = {
|
|
111
|
+
contentDir: obj.contentDir,
|
|
112
|
+
calendarPath: obj.calendarPath,
|
|
113
|
+
};
|
|
114
|
+
if (obj.host !== undefined) {
|
|
115
|
+
if (typeof obj.host !== 'string' || obj.host.length === 0) {
|
|
116
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has invalid "host" ` +
|
|
117
|
+
`(must be a non-empty string when set).`);
|
|
118
|
+
}
|
|
119
|
+
site.host = obj.host;
|
|
120
|
+
}
|
|
121
|
+
if (obj.channelsPath !== undefined) {
|
|
122
|
+
if (typeof obj.channelsPath !== 'string' || obj.channelsPath.length === 0) {
|
|
123
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has invalid "channelsPath" ` +
|
|
124
|
+
`(must be a non-empty string when set).`);
|
|
125
|
+
}
|
|
126
|
+
site.channelsPath = obj.channelsPath;
|
|
127
|
+
}
|
|
128
|
+
if (obj.blogLayout !== undefined) {
|
|
129
|
+
if (typeof obj.blogLayout !== 'string' || obj.blogLayout.length === 0) {
|
|
130
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has invalid "blogLayout" ` +
|
|
131
|
+
`(must be a non-empty string when set).`);
|
|
132
|
+
}
|
|
133
|
+
site.blogLayout = obj.blogLayout;
|
|
134
|
+
}
|
|
135
|
+
if (obj.blogFilenameTemplate !== undefined) {
|
|
136
|
+
if (typeof obj.blogFilenameTemplate !== 'string' ||
|
|
137
|
+
obj.blogFilenameTemplate.length === 0) {
|
|
138
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has invalid ` +
|
|
139
|
+
`"blogFilenameTemplate" (must be a non-empty string when set).`);
|
|
140
|
+
}
|
|
141
|
+
if (!obj.blogFilenameTemplate.includes('{slug}')) {
|
|
142
|
+
throw new Error(`Invalid deskwork config: site "${slug}" blogFilenameTemplate ` +
|
|
143
|
+
`"${obj.blogFilenameTemplate}" must contain the "{slug}" placeholder.`);
|
|
144
|
+
}
|
|
145
|
+
site.blogFilenameTemplate = obj.blogFilenameTemplate;
|
|
146
|
+
}
|
|
147
|
+
if (obj.blogInitialState !== undefined) {
|
|
148
|
+
if (typeof obj.blogInitialState !== 'string' ||
|
|
149
|
+
obj.blogInitialState.length === 0) {
|
|
150
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has invalid ` +
|
|
151
|
+
`"blogInitialState" (must be a non-empty string when set).`);
|
|
152
|
+
}
|
|
153
|
+
site.blogInitialState = obj.blogInitialState;
|
|
154
|
+
}
|
|
155
|
+
if (obj.blogOutlineSection !== undefined) {
|
|
156
|
+
if (typeof obj.blogOutlineSection !== 'boolean') {
|
|
157
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has invalid ` +
|
|
158
|
+
`"blogOutlineSection" (must be a boolean when set).`);
|
|
159
|
+
}
|
|
160
|
+
site.blogOutlineSection = obj.blogOutlineSection;
|
|
161
|
+
}
|
|
162
|
+
if (obj.redirectsPath !== undefined) {
|
|
163
|
+
if (typeof obj.redirectsPath !== 'string' || obj.redirectsPath.length === 0) {
|
|
164
|
+
throw new Error(`Invalid deskwork config: site "${slug}" has invalid "redirectsPath" ` +
|
|
165
|
+
`(must be a non-empty string when set).`);
|
|
166
|
+
}
|
|
167
|
+
site.redirectsPath = obj.redirectsPath;
|
|
168
|
+
}
|
|
169
|
+
return site;
|
|
170
|
+
}
|
|
171
|
+
function resolveDefaultSite(value, siteSlugs) {
|
|
172
|
+
if (value === undefined || value === null) {
|
|
173
|
+
if (siteSlugs.length === 1)
|
|
174
|
+
return siteSlugs[0];
|
|
175
|
+
throw new Error(`Invalid deskwork config: "defaultSite" is required when more than one site is defined. ` +
|
|
176
|
+
`Configured sites: ${siteSlugs.join(', ')}.`);
|
|
177
|
+
}
|
|
178
|
+
if (typeof value !== 'string') {
|
|
179
|
+
throw new Error(`Invalid deskwork config: "defaultSite" must be a string, got ${describe(value)}.`);
|
|
180
|
+
}
|
|
181
|
+
if (!siteSlugs.includes(value)) {
|
|
182
|
+
throw new Error(`Invalid deskwork config: defaultSite "${value}" is not a configured site. ` +
|
|
183
|
+
`Valid sites: ${siteSlugs.join(', ')}.`);
|
|
184
|
+
}
|
|
185
|
+
return value;
|
|
186
|
+
}
|
|
187
|
+
/** Read and parse the deskwork config for a project root. */
|
|
188
|
+
export function readConfig(projectRoot) {
|
|
189
|
+
const path = configPath(projectRoot);
|
|
190
|
+
let raw;
|
|
191
|
+
try {
|
|
192
|
+
raw = readFileSync(path, 'utf8');
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
196
|
+
throw new Error(`Could not read .deskwork/config.json at ${path}: ${reason}. ` +
|
|
197
|
+
`Run /deskwork:install to create one.`);
|
|
198
|
+
}
|
|
199
|
+
let parsed;
|
|
200
|
+
try {
|
|
201
|
+
parsed = JSON.parse(raw);
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
205
|
+
throw new Error(`Invalid JSON in ${path}: ${reason}`);
|
|
206
|
+
}
|
|
207
|
+
return parseConfig(parsed);
|
|
208
|
+
}
|
|
209
|
+
function describe(value) {
|
|
210
|
+
if (value === null)
|
|
211
|
+
return 'null';
|
|
212
|
+
if (Array.isArray(value))
|
|
213
|
+
return 'array';
|
|
214
|
+
return typeof value;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,wEAAwE;AACxE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAoEhC,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,SAAS;IACT,OAAO;IACP,aAAa;IACb,QAAQ;IACR,kBAAkB;CACnB,CAAC,CAAC;AACH,MAAM,kBAAkB,GAAG,CAAC,YAAY,EAAE,cAAc,CAAU,CAAC;AACnE,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAS;IACxC,GAAG,kBAAkB;IACrB,MAAM;IACN,cAAc;IACd,YAAY;IACZ,sBAAsB;IACtB,kBAAkB;IAClB,oBAAoB;IACpB,eAAe;CAChB,CAAC,CAAC;AAEH,gFAAgF;AAChF,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CACb,wDAAwD,QAAQ,CAAC,KAAK,CAAC,GAAG,CAC3E,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CACb,yCAAyC,GAAG,KAAK;gBAC/C,iBAAiB,CAAC,GAAG,sBAAsB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC7D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,GAAG,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,6CAA6C,cAAc,SAAS,IAAI,CAAC,SAAS,CAChF,GAAG,CAAC,OAAO,CACZ,mDAAmD,CACrD,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC;IAC7B,IACE,UAAU,KAAK,SAAS;QACxB,UAAU,KAAK,IAAI;QACnB,OAAO,UAAU,KAAK,QAAQ;QAC9B,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EACzB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wEAAwE,CACzE,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAA+B,EAAE,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,IAAI,EAAG,UAAsC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAEnE,MAAM,MAAM,GAAmB,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAC/E,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CACb,wEAAwE,CACzE,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC7B,CAAC;IACD,IAAI,GAAG,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACvC,IACE,OAAO,GAAG,CAAC,gBAAgB,KAAK,QAAQ;YACxC,GAAG,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,EACjC,CAAC;YACD,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,CAAC;IACjD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,KAAc;IACnD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,4BAA4B,QAAQ,CACxE,KAAK,CACN,GAAG,CACL,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,sBAAsB,GAAG,KAAK;gBAClE,iBAAiB,CAAC,GAAG,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACxD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,gCAAgC,GAAG,IAAI;gBAC3E,+BAA+B,CAClC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAe;QACvB,UAAU,EAAE,GAAG,CAAC,UAAoB;QACpC,YAAY,EAAE,GAAG,CAAC,YAAsB;KACzC,CAAC;IAEF,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,uBAAuB;gBAC3D,wCAAwC,CAC3C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACvB,CAAC;IAED,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1E,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,+BAA+B;gBACnE,wCAAwC,CAC3C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;IACvC,CAAC;IAED,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACjC,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,6BAA6B;gBACjE,wCAAwC,CAC3C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;IACnC,CAAC;IAED,IAAI,GAAG,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;QAC3C,IACE,OAAO,GAAG,CAAC,oBAAoB,KAAK,QAAQ;YAC5C,GAAG,CAAC,oBAAoB,CAAC,MAAM,KAAK,CAAC,EACrC,CAAC;YACD,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,gBAAgB;gBACpD,+DAA+D,CAClE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,yBAAyB;gBAC7D,IAAI,GAAG,CAAC,oBAAoB,0CAA0C,CACzE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,oBAAoB,GAAG,GAAG,CAAC,oBAAoB,CAAC;IACvD,CAAC;IAED,IAAI,GAAG,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACvC,IACE,OAAO,GAAG,CAAC,gBAAgB,KAAK,QAAQ;YACxC,GAAG,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,EACjC,CAAC;YACD,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,gBAAgB;gBACpD,2DAA2D,CAC9D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,CAAC;IAC/C,CAAC;IAED,IAAI,GAAG,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;QACzC,IAAI,OAAO,GAAG,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,gBAAgB;gBACpD,oDAAoD,CACvD,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,kBAAkB,GAAG,GAAG,CAAC,kBAAkB,CAAC;IACnD,CAAC;IAED,IAAI,GAAG,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACpC,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CACb,kCAAkC,IAAI,gCAAgC;gBACpE,wCAAwC,CAC3C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;IACzC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc,EAAE,SAAmB;IAC7D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,IAAI,KAAK,CACb,yFAAyF;YACvF,qBAAqB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC/C,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,gEAAgE,QAAQ,CAAC,KAAK,CAAC,GAAG,CACnF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,yCAAyC,KAAK,8BAA8B;YAC1E,gBAAgB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC1C,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,2CAA2C,IAAI,KAAK,MAAM,IAAI;YAC5D,sCAAsC,CACzC,CAAC;IACJ,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACzC,OAAO,OAAO,KAAK,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content index — `{uuid → absolute path}` and `{relative path → uuid}`.
|
|
3
|
+
*
|
|
4
|
+
* Walks `<contentDir>/` for a configured site, parses every markdown file's
|
|
5
|
+
* YAML frontmatter, and records the file's `deskwork.id:` field when present
|
|
6
|
+
* and shaped like a UUID. The result drives id-based file lookups (Phase 19c)
|
|
7
|
+
* and `deskwork doctor`'s validation rules (Phase 19b).
|
|
8
|
+
*
|
|
9
|
+
* Namespace (Issue #38): the binding key lives under a `deskwork:`
|
|
10
|
+
* namespace in frontmatter (`deskwork.id`), NOT at the top level. Older
|
|
11
|
+
* v0.7.0/v0.7.1 files with a top-level `id:` are NOT picked up here —
|
|
12
|
+
* the `legacy-top-level-id-migration` doctor rule surfaces and migrates
|
|
13
|
+
* those.
|
|
14
|
+
*
|
|
15
|
+
* Design notes:
|
|
16
|
+
* - Pure function: each call walks fresh. Callers that want memoization
|
|
17
|
+
* wrap (the studio memoizes per HTTP request; doctor memoizes per run).
|
|
18
|
+
* Building the index here means not maintaining a stale-cache invariant.
|
|
19
|
+
* - Files with no `deskwork.id:` are simply omitted — that's the
|
|
20
|
+
* legitimate pre-bind state. `doctor` reports them via the calendar
|
|
21
|
+
* join, not by treating "no id" as an error here.
|
|
22
|
+
* - Files with a malformed `deskwork.id:` go into `invalid` so `doctor`
|
|
23
|
+
* can surface them; they don't pollute `byId` / `byPath`.
|
|
24
|
+
* - On duplicate ids across files, the first encountered (in sorted
|
|
25
|
+
* directory walk order) wins `byId`; the second is silently dropped
|
|
26
|
+
* from `byId` but its path still appears in `byPath`. The
|
|
27
|
+
* `duplicate-id` doctor rule is a separate concern and reads files
|
|
28
|
+
* directly when reporting.
|
|
29
|
+
*
|
|
30
|
+
* Sibling-relative imports per the project convention — `@/` doesn't
|
|
31
|
+
* resolve under tsx at runtime in this package's `src/`, only in tests.
|
|
32
|
+
*/
|
|
33
|
+
import type { DeskworkConfig } from './config.ts';
|
|
34
|
+
/** A markdown file whose frontmatter `id:` couldn't be used as an index key. */
|
|
35
|
+
export interface InvalidIndexEntry {
|
|
36
|
+
/** Absolute path to the offending file. */
|
|
37
|
+
absolutePath: string;
|
|
38
|
+
/** Why the file was rejected — surfaced verbatim by doctor. */
|
|
39
|
+
reason: string;
|
|
40
|
+
}
|
|
41
|
+
/** Result of scanning a site's content directory for id ↔ path bindings. */
|
|
42
|
+
export interface ContentIndex {
|
|
43
|
+
/**
|
|
44
|
+
* uuid → absolute path. Maps an entry's id to the file claiming it via
|
|
45
|
+
* frontmatter `id:`. Studio request-lifecycle and doctor read this to
|
|
46
|
+
* resolve a calendar entry to its file regardless of slug or path.
|
|
47
|
+
*/
|
|
48
|
+
byId: Map<string, string>;
|
|
49
|
+
/**
|
|
50
|
+
* Relative path (under contentDir) → uuid. Reverse lookup for code
|
|
51
|
+
* driven by a filesystem walk that needs the entry id for a given
|
|
52
|
+
* file. Both maps are kept in sync — every byId mapping has a
|
|
53
|
+
* matching byPath mapping pointing back at the same uuid.
|
|
54
|
+
*/
|
|
55
|
+
byPath: Map<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* Files that have an `id:` frontmatter but the value isn't a valid
|
|
58
|
+
* UUID v4-shape. Reported by doctor. Files without any `id:` field
|
|
59
|
+
* are NOT reported here — they're just absent from the index, which
|
|
60
|
+
* is the legitimate pre-bind state.
|
|
61
|
+
*/
|
|
62
|
+
invalid: InvalidIndexEntry[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Build a content index for one site. Walks `<contentDir>/`, parses
|
|
66
|
+
* every markdown file's frontmatter, and binds `id ↔ path` where the
|
|
67
|
+
* frontmatter declares a valid UUID.
|
|
68
|
+
*
|
|
69
|
+
* Returns empty maps when `<contentDir>` doesn't exist (e.g. a freshly
|
|
70
|
+
* configured site with nothing on disk yet) — the caller can still
|
|
71
|
+
* proceed; doctor will report calendar entries with no matching files.
|
|
72
|
+
*/
|
|
73
|
+
export declare function buildContentIndex(projectRoot: string, config: DeskworkConfig, site: string): ContentIndex;
|
|
74
|
+
//# sourceMappingURL=content-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-index.d.ts","sourceRoot":"","sources":["../src/content-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,gFAAgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B;;;;;OAKG;IACH,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B;;;;;OAKG;IACH,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAgJD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,GACX,YAAY,CAiCd"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content index — `{uuid → absolute path}` and `{relative path → uuid}`.
|
|
3
|
+
*
|
|
4
|
+
* Walks `<contentDir>/` for a configured site, parses every markdown file's
|
|
5
|
+
* YAML frontmatter, and records the file's `deskwork.id:` field when present
|
|
6
|
+
* and shaped like a UUID. The result drives id-based file lookups (Phase 19c)
|
|
7
|
+
* and `deskwork doctor`'s validation rules (Phase 19b).
|
|
8
|
+
*
|
|
9
|
+
* Namespace (Issue #38): the binding key lives under a `deskwork:`
|
|
10
|
+
* namespace in frontmatter (`deskwork.id`), NOT at the top level. Older
|
|
11
|
+
* v0.7.0/v0.7.1 files with a top-level `id:` are NOT picked up here —
|
|
12
|
+
* the `legacy-top-level-id-migration` doctor rule surfaces and migrates
|
|
13
|
+
* those.
|
|
14
|
+
*
|
|
15
|
+
* Design notes:
|
|
16
|
+
* - Pure function: each call walks fresh. Callers that want memoization
|
|
17
|
+
* wrap (the studio memoizes per HTTP request; doctor memoizes per run).
|
|
18
|
+
* Building the index here means not maintaining a stale-cache invariant.
|
|
19
|
+
* - Files with no `deskwork.id:` are simply omitted — that's the
|
|
20
|
+
* legitimate pre-bind state. `doctor` reports them via the calendar
|
|
21
|
+
* join, not by treating "no id" as an error here.
|
|
22
|
+
* - Files with a malformed `deskwork.id:` go into `invalid` so `doctor`
|
|
23
|
+
* can surface them; they don't pollute `byId` / `byPath`.
|
|
24
|
+
* - On duplicate ids across files, the first encountered (in sorted
|
|
25
|
+
* directory walk order) wins `byId`; the second is silently dropped
|
|
26
|
+
* from `byId` but its path still appears in `byPath`. The
|
|
27
|
+
* `duplicate-id` doctor rule is a separate concern and reads files
|
|
28
|
+
* directly when reporting.
|
|
29
|
+
*
|
|
30
|
+
* Sibling-relative imports per the project convention — `@/` doesn't
|
|
31
|
+
* resolve under tsx at runtime in this package's `src/`, only in tests.
|
|
32
|
+
*/
|
|
33
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
34
|
+
import { join, relative } from 'node:path';
|
|
35
|
+
import { resolveContentDir } from "./paths.js";
|
|
36
|
+
import { readFrontmatter } from "./frontmatter.js";
|
|
37
|
+
/** Directory names skipped by the walk. Matched case-insensitively on the leaf. */
|
|
38
|
+
const SKIP_DIRS = new Set([
|
|
39
|
+
'scrapbook',
|
|
40
|
+
'node_modules',
|
|
41
|
+
'dist',
|
|
42
|
+
'.git',
|
|
43
|
+
]);
|
|
44
|
+
/** Markdown extensions recognized by the walker. */
|
|
45
|
+
const MARKDOWN_EXTENSIONS = new Set([
|
|
46
|
+
'.md',
|
|
47
|
+
'.mdx',
|
|
48
|
+
'.markdown',
|
|
49
|
+
]);
|
|
50
|
+
/**
|
|
51
|
+
* UUID v4 shape check — 36 chars, lowercase or uppercase hex, hyphens
|
|
52
|
+
* at positions 8/13/18/23. Permissive on the variant nibbles to
|
|
53
|
+
* accommodate v4-but-non-canonical values that the rest of the system
|
|
54
|
+
* already accepts (the parser auto-backfill uses `randomUUID()` which
|
|
55
|
+
* IS canonical, but we shouldn't reject id values that round-tripped
|
|
56
|
+
* through other tooling).
|
|
57
|
+
*/
|
|
58
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
59
|
+
function isUuid(value) {
|
|
60
|
+
return UUID_RE.test(value);
|
|
61
|
+
}
|
|
62
|
+
/** Lowercased extension of a filename, including the leading dot. */
|
|
63
|
+
function extensionOf(name) {
|
|
64
|
+
const idx = name.lastIndexOf('.');
|
|
65
|
+
if (idx < 0)
|
|
66
|
+
return '';
|
|
67
|
+
return name.slice(idx).toLowerCase();
|
|
68
|
+
}
|
|
69
|
+
/** True when this directory entry name should be skipped during the walk. */
|
|
70
|
+
function shouldSkipDir(name) {
|
|
71
|
+
if (name.startsWith('.'))
|
|
72
|
+
return true;
|
|
73
|
+
return SKIP_DIRS.has(name.toLowerCase());
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Recursively collect markdown file paths under `dir`. Returns a sorted
|
|
77
|
+
* list (by absolute path) so the walk is deterministic — same input
|
|
78
|
+
* tree always produces the same maps regardless of OS-level readdir
|
|
79
|
+
* order.
|
|
80
|
+
*/
|
|
81
|
+
function collectMarkdownFiles(dir) {
|
|
82
|
+
const out = [];
|
|
83
|
+
visit(dir);
|
|
84
|
+
out.sort();
|
|
85
|
+
return out;
|
|
86
|
+
function visit(currentDir) {
|
|
87
|
+
let names;
|
|
88
|
+
try {
|
|
89
|
+
names = readdirSync(currentDir);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
for (const name of names) {
|
|
95
|
+
const abs = join(currentDir, name);
|
|
96
|
+
let st;
|
|
97
|
+
try {
|
|
98
|
+
st = statSync(abs);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (st.isDirectory()) {
|
|
104
|
+
if (shouldSkipDir(name))
|
|
105
|
+
continue;
|
|
106
|
+
visit(abs);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (!st.isFile())
|
|
110
|
+
continue;
|
|
111
|
+
if (MARKDOWN_EXTENSIONS.has(extensionOf(name))) {
|
|
112
|
+
out.push(abs);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function readIdFromFrontmatter(absPath) {
|
|
118
|
+
let parsed;
|
|
119
|
+
try {
|
|
120
|
+
parsed = readFrontmatter(absPath);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
124
|
+
return { kind: 'invalid', reason: `unreadable frontmatter: ${reason}` };
|
|
125
|
+
}
|
|
126
|
+
// Issue #38: read `deskwork.id` only — top-level `id:` belongs to the
|
|
127
|
+
// operator, not to deskwork. Files with only a top-level id are
|
|
128
|
+
// surfaced separately by the legacy-top-level-id-migration doctor rule.
|
|
129
|
+
const deskworkBlock = parsed.data.deskwork;
|
|
130
|
+
if (deskworkBlock === undefined || deskworkBlock === null) {
|
|
131
|
+
return { kind: 'absent' };
|
|
132
|
+
}
|
|
133
|
+
if (typeof deskworkBlock !== 'object' || Array.isArray(deskworkBlock)) {
|
|
134
|
+
return {
|
|
135
|
+
kind: 'invalid',
|
|
136
|
+
reason: `frontmatter deskwork is ${typeof deskworkBlock}, expected mapping`,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const raw = deskworkBlock.id;
|
|
140
|
+
if (raw === undefined)
|
|
141
|
+
return { kind: 'absent' };
|
|
142
|
+
if (typeof raw !== 'string') {
|
|
143
|
+
return {
|
|
144
|
+
kind: 'invalid',
|
|
145
|
+
reason: `frontmatter deskwork.id is ${typeof raw}, expected string`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const trimmed = raw.trim();
|
|
149
|
+
if (trimmed === '') {
|
|
150
|
+
return {
|
|
151
|
+
kind: 'invalid',
|
|
152
|
+
reason: 'frontmatter deskwork.id is empty',
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (!isUuid(trimmed)) {
|
|
156
|
+
return {
|
|
157
|
+
kind: 'invalid',
|
|
158
|
+
reason: `frontmatter deskwork.id "${trimmed}" is not a valid UUID`,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return { kind: 'valid', id: trimmed };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Build a content index for one site. Walks `<contentDir>/`, parses
|
|
165
|
+
* every markdown file's frontmatter, and binds `id ↔ path` where the
|
|
166
|
+
* frontmatter declares a valid UUID.
|
|
167
|
+
*
|
|
168
|
+
* Returns empty maps when `<contentDir>` doesn't exist (e.g. a freshly
|
|
169
|
+
* configured site with nothing on disk yet) — the caller can still
|
|
170
|
+
* proceed; doctor will report calendar entries with no matching files.
|
|
171
|
+
*/
|
|
172
|
+
export function buildContentIndex(projectRoot, config, site) {
|
|
173
|
+
const contentDir = resolveContentDir(projectRoot, config, site);
|
|
174
|
+
const byId = new Map();
|
|
175
|
+
const byPath = new Map();
|
|
176
|
+
const invalid = [];
|
|
177
|
+
let files;
|
|
178
|
+
try {
|
|
179
|
+
files = collectMarkdownFiles(contentDir);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return { byId, byPath, invalid };
|
|
183
|
+
}
|
|
184
|
+
for (const abs of files) {
|
|
185
|
+
const lookup = readIdFromFrontmatter(abs);
|
|
186
|
+
if (lookup.kind === 'absent')
|
|
187
|
+
continue;
|
|
188
|
+
if (lookup.kind === 'invalid') {
|
|
189
|
+
invalid.push({ absolutePath: abs, reason: lookup.reason });
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const rel = relative(contentDir, abs);
|
|
193
|
+
// First-encountered wins for byId on duplicates. Sorted walk above
|
|
194
|
+
// gives deterministic "first" — same fixture tree always picks the
|
|
195
|
+
// same file. byPath records every path so a later fs-walk-driven
|
|
196
|
+
// caller can still resolve uuid by path even when the duplicate
|
|
197
|
+
// is the colliding entry.
|
|
198
|
+
if (!byId.has(lookup.id)) {
|
|
199
|
+
byId.set(lookup.id, abs);
|
|
200
|
+
}
|
|
201
|
+
byPath.set(rel, lookup.id);
|
|
202
|
+
}
|
|
203
|
+
return { byId, byPath, invalid };
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=content-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-index.js","sourceRoot":"","sources":["../src/content-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-tree filesystem walk — pure recursive directory scan.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `content-tree.ts` (Phase 19c) to keep that file under
|
|
5
|
+
* the project's 500-line guideline. The walk is read-only and produces
|
|
6
|
+
* one `FsWalkEntry` per directory beneath `<contentDir>` — the input
|
|
7
|
+
* to the tree assembly's fs-primary inversion.
|
|
8
|
+
*
|
|
9
|
+
* No knowledge of the calendar or content index lives here.
|
|
10
|
+
*/
|
|
11
|
+
import type { DeskworkConfig } from './config.ts';
|
|
12
|
+
/**
|
|
13
|
+
* One row of the filesystem walk: a directory found under contentDir,
|
|
14
|
+
* plus the on-disk markers (README / index) used to decide whether
|
|
15
|
+
* it's a candidate organizational node.
|
|
16
|
+
*/
|
|
17
|
+
export interface FsWalkEntry {
|
|
18
|
+
/**
|
|
19
|
+
* Fs-relative path from contentDir (e.g. `the-outbound/characters`).
|
|
20
|
+
* Field name retained as `slug` for backward-compat with existing
|
|
21
|
+
* test fixtures and external callers; semantically it is now an
|
|
22
|
+
* "fs path" — kebab-case segments separated by `/`.
|
|
23
|
+
*/
|
|
24
|
+
slug: string;
|
|
25
|
+
/** True when the directory has an `index.md` / `index.mdx` file. */
|
|
26
|
+
hasIndex: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* True when the directory has a `README.md` / `README.mdx` file.
|
|
29
|
+
* Used to surface organizational nodes that aren't part of the
|
|
30
|
+
* calendar's tracked set.
|
|
31
|
+
*/
|
|
32
|
+
hasReadme: boolean;
|
|
33
|
+
/** Title from the README/index frontmatter `title` field, when present. */
|
|
34
|
+
title: string | null;
|
|
35
|
+
}
|
|
36
|
+
/** Match the index/README basenames the studio recognizes as a node marker. */
|
|
37
|
+
export declare const INDEX_BASENAMES: ReadonlySet<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Index file basenames the host's default template (`<path>/index.md`)
|
|
40
|
+
* recognises. Used to decide `hasOwnIndex` for tracked entries when the
|
|
41
|
+
* content index doesn't bind them to a specific file (pre-doctor state).
|
|
42
|
+
*/
|
|
43
|
+
export declare const TEMPLATE_INDEX_BASENAMES: readonly string[];
|
|
44
|
+
/**
|
|
45
|
+
* Default filesystem walk — recursively scan a site's contentDir for
|
|
46
|
+
* directories. Returns one `FsWalkEntry` per directory beneath
|
|
47
|
+
* contentDir (not contentDir itself). Skips dotfiles and the
|
|
48
|
+
* conventional non-content names (`scrapbook`, `node_modules`, etc.).
|
|
49
|
+
*
|
|
50
|
+
* Per-directory the walk records whether an `index.md` / `README.md`
|
|
51
|
+
* is present and (when present) reads the frontmatter `title`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function defaultFsWalk(projectRoot: string, config: DeskworkConfig, site: string): FsWalkEntry[];
|
|
54
|
+
//# sourceMappingURL=content-tree-fs-walk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-tree-fs-walk.d.ts","sourceRoot":"","sources":["../src/content-tree-fs-walk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,+EAA+E;AAC/E,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAE9C,CAAC;AAKH;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAIrD,CAAC;AAcF;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,GACX,WAAW,EAAE,CAkDf"}
|