@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,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML frontmatter reader/writer for markdown files.
|
|
3
|
+
*
|
|
4
|
+
* Deskwork skills that touch blog posts (draft, publish, distribute) need to
|
|
5
|
+
* read and update frontmatter — e.g. setting `datePublished` when a post
|
|
6
|
+
* ships, reading `contentUrl` when recording a distribution. This module
|
|
7
|
+
* wraps the `yaml` library so callers don't have to hand-roll YAML parsing.
|
|
8
|
+
*
|
|
9
|
+
* ## Shape
|
|
10
|
+
*
|
|
11
|
+
* A file with frontmatter looks like:
|
|
12
|
+
*
|
|
13
|
+
* ```markdown
|
|
14
|
+
* ---
|
|
15
|
+
* title: My Post
|
|
16
|
+
* datePublished: 2026-01-15
|
|
17
|
+
* ---
|
|
18
|
+
*
|
|
19
|
+
* # Body
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* `parseFrontmatter` splits this into `data` (parsed YAML) and `body` (the
|
|
23
|
+
* remainder, including the leading newline if present). `stringifyFrontmatter`
|
|
24
|
+
* is the inverse for callers that need to construct frontmatter from scratch.
|
|
25
|
+
*
|
|
26
|
+
* ## Round-trip preservation (Issue #37)
|
|
27
|
+
*
|
|
28
|
+
* Naive parse → mutate → stringify normalizes everything: quoting styles
|
|
29
|
+
* dissolve, comments evaporate, key order shuffles. That bites Astro
|
|
30
|
+
* schemas that demand string scalars: `datePublished: "2020-10-01"`
|
|
31
|
+
* round-trips to `datePublished: 2020-10-01` and re-parses as a `Date`,
|
|
32
|
+
* which `z.string()` rejects.
|
|
33
|
+
*
|
|
34
|
+
* `updateFrontmatter` and `writeFrontmatter` use the yaml library's
|
|
35
|
+
* Document mode (`parseDocument` → mutate AST → `Document.toString()`)
|
|
36
|
+
* so the only bytes that change are the keys we touched. Existing
|
|
37
|
+
* quoting, comments, blank lines, and key order are byte-preserved.
|
|
38
|
+
*
|
|
39
|
+
* Read-only consumers (`parseFrontmatter`, `readFrontmatter`) still use
|
|
40
|
+
* the simpler `parse` API since they don't write anything back.
|
|
41
|
+
*/
|
|
42
|
+
/** Frontmatter values come back as whatever YAML parses them to. */
|
|
43
|
+
export type FrontmatterData = Record<string, unknown>;
|
|
44
|
+
export interface ParsedMarkdown {
|
|
45
|
+
data: FrontmatterData;
|
|
46
|
+
body: string;
|
|
47
|
+
}
|
|
48
|
+
/** Split a markdown string into its frontmatter data and body. */
|
|
49
|
+
export declare function parseFrontmatter(markdown: string): ParsedMarkdown;
|
|
50
|
+
/**
|
|
51
|
+
* Build a markdown string from frontmatter data and body.
|
|
52
|
+
*
|
|
53
|
+
* The body is joined to the frontmatter with a single newline — callers that
|
|
54
|
+
* want a blank line between the closing `---` and the body should start their
|
|
55
|
+
* body with `'\n'`.
|
|
56
|
+
*
|
|
57
|
+
* This is for callers that build frontmatter from scratch (e.g. the
|
|
58
|
+
* scaffolder writing a brand-new file). It does NOT preserve formatting
|
|
59
|
+
* since there's no existing source to preserve. Callers performing a
|
|
60
|
+
* read/mutate/write round-trip should use `updateFrontmatter` instead.
|
|
61
|
+
*/
|
|
62
|
+
export declare function stringifyFrontmatter(data: FrontmatterData, body: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Merge a patch into a markdown file's frontmatter and return the new contents.
|
|
65
|
+
*
|
|
66
|
+
* Round-trip-preserving (Issue #37): edits the existing YAML AST in place
|
|
67
|
+
* so untouched keys remain byte-identical. Quoting styles, comments, blank
|
|
68
|
+
* lines, and key order are preserved exactly. Patched keys overwrite
|
|
69
|
+
* existing values; new keys are appended at the bottom of the map.
|
|
70
|
+
*
|
|
71
|
+
* If the file has no frontmatter, one is created with the patch as its
|
|
72
|
+
* only contents.
|
|
73
|
+
*/
|
|
74
|
+
export declare function updateFrontmatter(markdown: string, patch: FrontmatterData): string;
|
|
75
|
+
/**
|
|
76
|
+
* Delete keys (or nested key paths) from a markdown file's frontmatter
|
|
77
|
+
* while preserving every other byte (round-trip-preserving, like
|
|
78
|
+
* `updateFrontmatter`).
|
|
79
|
+
*
|
|
80
|
+
* Each path is an array of string keys describing the descent into
|
|
81
|
+
* nested mappings, e.g. `['deskwork', 'id']` removes the `id` field
|
|
82
|
+
* inside the top-level `deskwork:` mapping. Top-level keys can be
|
|
83
|
+
* passed as a single-element path (`['datePublished']`).
|
|
84
|
+
*
|
|
85
|
+
* After a deletion, if the parent collection is left empty AND
|
|
86
|
+
* `pruneEmptyParents` is true (default), the parent collection is also
|
|
87
|
+
* removed. Set false to keep the empty container.
|
|
88
|
+
*/
|
|
89
|
+
export declare function removeFrontmatterPaths(markdown: string, paths: ReadonlyArray<ReadonlyArray<string>>, options?: {
|
|
90
|
+
pruneEmptyParents?: boolean;
|
|
91
|
+
}): string;
|
|
92
|
+
/** Read and parse a markdown file with frontmatter. */
|
|
93
|
+
export declare function readFrontmatter(path: string): ParsedMarkdown;
|
|
94
|
+
/**
|
|
95
|
+
* Write a markdown file with frontmatter.
|
|
96
|
+
*
|
|
97
|
+
* Like `stringifyFrontmatter`, this is for callers that build frontmatter
|
|
98
|
+
* from scratch (the scaffolder, primarily). For "read existing file →
|
|
99
|
+
* mutate → write back" flows, prefer reading the file and applying
|
|
100
|
+
* `updateFrontmatter` so existing formatting is preserved.
|
|
101
|
+
*/
|
|
102
|
+
export declare function writeFrontmatter(path: string, data: FrontmatterData, body: string): void;
|
|
103
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAeH,oEAAoE;AACpE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAID,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAsBjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,CAGR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,eAAe,GACrB,MAAM,CAkBR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EAC3C,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5C,MAAM,CAkCR;AAED,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAE5D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,MAAM,GACX,IAAI,CAEN"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML frontmatter reader/writer for markdown files.
|
|
3
|
+
*
|
|
4
|
+
* Deskwork skills that touch blog posts (draft, publish, distribute) need to
|
|
5
|
+
* read and update frontmatter — e.g. setting `datePublished` when a post
|
|
6
|
+
* ships, reading `contentUrl` when recording a distribution. This module
|
|
7
|
+
* wraps the `yaml` library so callers don't have to hand-roll YAML parsing.
|
|
8
|
+
*
|
|
9
|
+
* ## Shape
|
|
10
|
+
*
|
|
11
|
+
* A file with frontmatter looks like:
|
|
12
|
+
*
|
|
13
|
+
* ```markdown
|
|
14
|
+
* ---
|
|
15
|
+
* title: My Post
|
|
16
|
+
* datePublished: 2026-01-15
|
|
17
|
+
* ---
|
|
18
|
+
*
|
|
19
|
+
* # Body
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* `parseFrontmatter` splits this into `data` (parsed YAML) and `body` (the
|
|
23
|
+
* remainder, including the leading newline if present). `stringifyFrontmatter`
|
|
24
|
+
* is the inverse for callers that need to construct frontmatter from scratch.
|
|
25
|
+
*
|
|
26
|
+
* ## Round-trip preservation (Issue #37)
|
|
27
|
+
*
|
|
28
|
+
* Naive parse → mutate → stringify normalizes everything: quoting styles
|
|
29
|
+
* dissolve, comments evaporate, key order shuffles. That bites Astro
|
|
30
|
+
* schemas that demand string scalars: `datePublished: "2020-10-01"`
|
|
31
|
+
* round-trips to `datePublished: 2020-10-01` and re-parses as a `Date`,
|
|
32
|
+
* which `z.string()` rejects.
|
|
33
|
+
*
|
|
34
|
+
* `updateFrontmatter` and `writeFrontmatter` use the yaml library's
|
|
35
|
+
* Document mode (`parseDocument` → mutate AST → `Document.toString()`)
|
|
36
|
+
* so the only bytes that change are the keys we touched. Existing
|
|
37
|
+
* quoting, comments, blank lines, and key order are byte-preserved.
|
|
38
|
+
*
|
|
39
|
+
* Read-only consumers (`parseFrontmatter`, `readFrontmatter`) still use
|
|
40
|
+
* the simpler `parse` API since they don't write anything back.
|
|
41
|
+
*/
|
|
42
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
43
|
+
import { parse as parseYaml, stringify as stringifyYaml, parseDocument, isMap, isScalar, Scalar, YAMLMap, } from 'yaml';
|
|
44
|
+
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
45
|
+
/** Split a markdown string into its frontmatter data and body. */
|
|
46
|
+
export function parseFrontmatter(markdown) {
|
|
47
|
+
const match = markdown.match(FRONTMATTER_RE);
|
|
48
|
+
if (!match) {
|
|
49
|
+
return { data: {}, body: markdown };
|
|
50
|
+
}
|
|
51
|
+
const [, yamlContent, body] = match;
|
|
52
|
+
let data;
|
|
53
|
+
try {
|
|
54
|
+
data = parseYaml(yamlContent);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
58
|
+
throw new Error(`Invalid YAML frontmatter: ${reason}`);
|
|
59
|
+
}
|
|
60
|
+
if (data === null || data === undefined) {
|
|
61
|
+
return { data: {}, body };
|
|
62
|
+
}
|
|
63
|
+
if (typeof data !== 'object' || Array.isArray(data)) {
|
|
64
|
+
throw new Error(`Invalid frontmatter: expected a YAML mapping at the top level, got ${typeof data}.`);
|
|
65
|
+
}
|
|
66
|
+
return { data: toFrontmatterData(data), body };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build a markdown string from frontmatter data and body.
|
|
70
|
+
*
|
|
71
|
+
* The body is joined to the frontmatter with a single newline — callers that
|
|
72
|
+
* want a blank line between the closing `---` and the body should start their
|
|
73
|
+
* body with `'\n'`.
|
|
74
|
+
*
|
|
75
|
+
* This is for callers that build frontmatter from scratch (e.g. the
|
|
76
|
+
* scaffolder writing a brand-new file). It does NOT preserve formatting
|
|
77
|
+
* since there's no existing source to preserve. Callers performing a
|
|
78
|
+
* read/mutate/write round-trip should use `updateFrontmatter` instead.
|
|
79
|
+
*/
|
|
80
|
+
export function stringifyFrontmatter(data, body) {
|
|
81
|
+
const doc = buildDocument(data);
|
|
82
|
+
return `---\n${doc.toString({ lineWidth: 0 }).replace(/\n$/, '')}\n---\n${body}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Merge a patch into a markdown file's frontmatter and return the new contents.
|
|
86
|
+
*
|
|
87
|
+
* Round-trip-preserving (Issue #37): edits the existing YAML AST in place
|
|
88
|
+
* so untouched keys remain byte-identical. Quoting styles, comments, blank
|
|
89
|
+
* lines, and key order are preserved exactly. Patched keys overwrite
|
|
90
|
+
* existing values; new keys are appended at the bottom of the map.
|
|
91
|
+
*
|
|
92
|
+
* If the file has no frontmatter, one is created with the patch as its
|
|
93
|
+
* only contents.
|
|
94
|
+
*/
|
|
95
|
+
export function updateFrontmatter(markdown, patch) {
|
|
96
|
+
const match = markdown.match(FRONTMATTER_RE);
|
|
97
|
+
if (!match) {
|
|
98
|
+
// No existing frontmatter — emit a fresh block. The body becomes
|
|
99
|
+
// the entire input; we prepend a fresh `---…---` block.
|
|
100
|
+
return stringifyFrontmatter(patch, markdown);
|
|
101
|
+
}
|
|
102
|
+
const [, yamlContent, body] = match;
|
|
103
|
+
const doc = parseDocument(yamlContent, { keepSourceTokens: false });
|
|
104
|
+
if (doc.errors.length > 0) {
|
|
105
|
+
const first = doc.errors[0];
|
|
106
|
+
throw new Error(`Invalid YAML frontmatter: ${first.message}`);
|
|
107
|
+
}
|
|
108
|
+
applyPatchToDocument(doc, patch);
|
|
109
|
+
// doc.toString() always ends with `\n`; trim it and re-add inside our
|
|
110
|
+
// delimiters so the on-disk shape stays `---\n<yaml>\n---\n<body>`.
|
|
111
|
+
const yamlOut = doc.toString({ lineWidth: 0 }).replace(/\n$/, '');
|
|
112
|
+
return `---\n${yamlOut}\n---\n${body}`;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Delete keys (or nested key paths) from a markdown file's frontmatter
|
|
116
|
+
* while preserving every other byte (round-trip-preserving, like
|
|
117
|
+
* `updateFrontmatter`).
|
|
118
|
+
*
|
|
119
|
+
* Each path is an array of string keys describing the descent into
|
|
120
|
+
* nested mappings, e.g. `['deskwork', 'id']` removes the `id` field
|
|
121
|
+
* inside the top-level `deskwork:` mapping. Top-level keys can be
|
|
122
|
+
* passed as a single-element path (`['datePublished']`).
|
|
123
|
+
*
|
|
124
|
+
* After a deletion, if the parent collection is left empty AND
|
|
125
|
+
* `pruneEmptyParents` is true (default), the parent collection is also
|
|
126
|
+
* removed. Set false to keep the empty container.
|
|
127
|
+
*/
|
|
128
|
+
export function removeFrontmatterPaths(markdown, paths, options = {}) {
|
|
129
|
+
const match = markdown.match(FRONTMATTER_RE);
|
|
130
|
+
if (!match)
|
|
131
|
+
return markdown;
|
|
132
|
+
const [, yamlContent, body] = match;
|
|
133
|
+
const doc = parseDocument(yamlContent);
|
|
134
|
+
if (doc.errors.length > 0) {
|
|
135
|
+
const first = doc.errors[0];
|
|
136
|
+
throw new Error(`Invalid YAML frontmatter: ${first.message}`);
|
|
137
|
+
}
|
|
138
|
+
const prune = options.pruneEmptyParents ?? true;
|
|
139
|
+
let mutated = false;
|
|
140
|
+
for (const path of paths) {
|
|
141
|
+
if (path.length === 0)
|
|
142
|
+
continue;
|
|
143
|
+
if (!doc.hasIn(path))
|
|
144
|
+
continue;
|
|
145
|
+
doc.deleteIn(path);
|
|
146
|
+
mutated = true;
|
|
147
|
+
if (prune && path.length > 1) {
|
|
148
|
+
// Walk parents, deleting any that became empty maps.
|
|
149
|
+
for (let depth = path.length - 1; depth >= 1; depth--) {
|
|
150
|
+
const parentPath = path.slice(0, depth);
|
|
151
|
+
const parent = doc.getIn(parentPath, true);
|
|
152
|
+
if (isMap(parent) && parent.items.length === 0) {
|
|
153
|
+
doc.deleteIn(parentPath);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (!mutated)
|
|
162
|
+
return markdown;
|
|
163
|
+
const yamlOut = doc.toString({ lineWidth: 0 }).replace(/\n$/, '');
|
|
164
|
+
return `---\n${yamlOut}\n---\n${body}`;
|
|
165
|
+
}
|
|
166
|
+
/** Read and parse a markdown file with frontmatter. */
|
|
167
|
+
export function readFrontmatter(path) {
|
|
168
|
+
return parseFrontmatter(readFileSync(path, 'utf-8'));
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Write a markdown file with frontmatter.
|
|
172
|
+
*
|
|
173
|
+
* Like `stringifyFrontmatter`, this is for callers that build frontmatter
|
|
174
|
+
* from scratch (the scaffolder, primarily). For "read existing file →
|
|
175
|
+
* mutate → write back" flows, prefer reading the file and applying
|
|
176
|
+
* `updateFrontmatter` so existing formatting is preserved.
|
|
177
|
+
*/
|
|
178
|
+
export function writeFrontmatter(path, data, body) {
|
|
179
|
+
writeFileSync(path, stringifyFrontmatter(data, body), 'utf-8');
|
|
180
|
+
}
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// Internal helpers — Document AST mutation.
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
/**
|
|
185
|
+
* Apply a `{key: value}` patch to a parsed YAML Document, mutating the
|
|
186
|
+
* AST in place. Existing keys keep their quoting style; new keys are
|
|
187
|
+
* appended at the bottom of the top-level map.
|
|
188
|
+
*
|
|
189
|
+
* Nested objects are written via `setIn` so that `{deskwork: {id: …}}`
|
|
190
|
+
* patches the deeper key without clobbering siblings of `deskwork`.
|
|
191
|
+
*/
|
|
192
|
+
function applyPatchToDocument(doc, patch) {
|
|
193
|
+
// The frontmatter block must be a mapping. parseFrontmatter validates
|
|
194
|
+
// this on the read path; for the write path here we treat empty/null
|
|
195
|
+
// contents as a fresh empty map by setting keys directly through the
|
|
196
|
+
// Document API (which lazily creates the top-level container).
|
|
197
|
+
if (doc.contents !== null && !isMap(doc.contents)) {
|
|
198
|
+
throw new Error('Cannot patch frontmatter: top-level YAML node is not a mapping.');
|
|
199
|
+
}
|
|
200
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
201
|
+
if (isPlainObject(value)) {
|
|
202
|
+
// Merge into nested map: only keys present in the patch are
|
|
203
|
+
// overwritten; existing siblings under the same parent stay.
|
|
204
|
+
mergeNestedObject(doc, [key], value);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (isMap(doc.contents)) {
|
|
208
|
+
setScalarPreservingStyle(doc.contents, key, value);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
doc.set(key, value);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Set a scalar (or array) value on a YAMLMap, preserving the existing
|
|
217
|
+
* Scalar node's `type` (quoting style) when the key already exists. This
|
|
218
|
+
* is the round-trip-preservation hook: editing an already-double-quoted
|
|
219
|
+
* key keeps the double quotes.
|
|
220
|
+
*/
|
|
221
|
+
function setScalarPreservingStyle(map, key, value) {
|
|
222
|
+
const existing = map.get(key, true);
|
|
223
|
+
if (isScalar(existing)) {
|
|
224
|
+
const next = new Scalar(value);
|
|
225
|
+
if (existing.type !== undefined)
|
|
226
|
+
next.type = existing.type;
|
|
227
|
+
map.set(key, next);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
// No existing key, or the existing value was a collection — let the
|
|
231
|
+
// library pick the default representation.
|
|
232
|
+
map.set(key, value);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Merge a nested-object patch under `path` (e.g. `['deskwork']`) into
|
|
236
|
+
* the document. If the parent doesn't exist, create it as an empty map
|
|
237
|
+
* BEFORE descending. If individual keys under the parent collide,
|
|
238
|
+
* recursively merge so untouched siblings stay put.
|
|
239
|
+
*
|
|
240
|
+
* `Document.setIn` does not auto-vivify intermediate collections; it
|
|
241
|
+
* throws if the parent isn't a YAML collection. We materialize each
|
|
242
|
+
* level explicitly with `setIn(parentPath, {})` whenever it's missing.
|
|
243
|
+
*/
|
|
244
|
+
function mergeNestedObject(doc, path, value) {
|
|
245
|
+
// Ensure every prefix of `path` exists as a YAMLMap. setIn does not
|
|
246
|
+
// auto-vivify intermediate collections; passing a plain `{}` puts a
|
|
247
|
+
// JS object at the slot (which the next setIn refuses to descend
|
|
248
|
+
// into). We materialize each missing level explicitly with a real
|
|
249
|
+
// YAMLMap node so subsequent setIn calls can write into it.
|
|
250
|
+
for (let depth = 1; depth <= path.length; depth++) {
|
|
251
|
+
const prefix = path.slice(0, depth);
|
|
252
|
+
if (!doc.hasIn(prefix)) {
|
|
253
|
+
doc.setIn(prefix, new YAMLMap(doc.schema));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
for (const [k, v] of Object.entries(value)) {
|
|
257
|
+
const fullPath = [...path, k];
|
|
258
|
+
if (isPlainObject(v)) {
|
|
259
|
+
mergeNestedObject(doc, fullPath, v);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
doc.setIn(fullPath, v);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Plain-object check used to decide whether a value should be merged
|
|
267
|
+
* via setIn (preserving sibling keys) or replaced wholesale via set.
|
|
268
|
+
*
|
|
269
|
+
* Plain objects are non-null, non-array, prototype-Object values —
|
|
270
|
+
* Records of unknown.
|
|
271
|
+
*/
|
|
272
|
+
function isPlainObject(value) {
|
|
273
|
+
if (value === null || typeof value !== 'object')
|
|
274
|
+
return false;
|
|
275
|
+
if (Array.isArray(value))
|
|
276
|
+
return false;
|
|
277
|
+
const proto = Object.getPrototypeOf(value);
|
|
278
|
+
return proto === Object.prototype || proto === null;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Build a fresh Document from plain data. Used by `stringifyFrontmatter`
|
|
282
|
+
* for write-from-scratch callers. We round-trip the data through
|
|
283
|
+
* `parseDocument(stringify(...))` rather than constructing nodes by
|
|
284
|
+
* hand so that block-style output (with proper indentation for nested
|
|
285
|
+
* collections) is the default — that's the format every existing
|
|
286
|
+
* scaffold/test asserts on.
|
|
287
|
+
*/
|
|
288
|
+
function buildDocument(data) {
|
|
289
|
+
const initialYaml = stringifyYaml(data, { lineWidth: 0 });
|
|
290
|
+
// Empty data renders as `{}\n`; parseDocument handles both shapes.
|
|
291
|
+
return parseDocument(initialYaml);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Narrow `unknown` from yaml's `parse` return type to FrontmatterData.
|
|
295
|
+
* The caller has already asserted the parse result is an object and
|
|
296
|
+
* not an array; this is the single point that crosses the typing gap
|
|
297
|
+
* between yaml's `unknown` and our typed surface.
|
|
298
|
+
*/
|
|
299
|
+
function toFrontmatterData(value) {
|
|
300
|
+
const out = {};
|
|
301
|
+
for (const k of Object.keys(value)) {
|
|
302
|
+
out[k] = value[k];
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deskwork/core — barrel export of every public symbol used across
|
|
3
|
+
* the cli and studio packages.
|
|
4
|
+
*
|
|
5
|
+
* Subpath imports (e.g. `@deskwork/core/calendar`) are also supported
|
|
6
|
+
* for callers that want to be explicit about which module they pull
|
|
7
|
+
* from. Both forms resolve to the same source files.
|
|
8
|
+
*/
|
|
9
|
+
export * from './types.ts';
|
|
10
|
+
export * from './config.ts';
|
|
11
|
+
export * from './paths.ts';
|
|
12
|
+
export * from './cli.ts';
|
|
13
|
+
export * from './calendar.ts';
|
|
14
|
+
export * from './calendar-mutations.ts';
|
|
15
|
+
export * from './frontmatter.ts';
|
|
16
|
+
export * from './journal.ts';
|
|
17
|
+
export * from './scaffold.ts';
|
|
18
|
+
export * from './body-state.ts';
|
|
19
|
+
export * from './ingest.ts';
|
|
20
|
+
export * as scrapbook from './scrapbook.ts';
|
|
21
|
+
export * as renameSlug from './rename-slug.ts';
|
|
22
|
+
export * as review from './review/index.ts';
|
|
23
|
+
export * as contentTree from './content-tree.ts';
|
|
24
|
+
export * from './content-index.ts';
|
|
25
|
+
export * as doctor from './doctor/index.ts';
|
|
26
|
+
export * from './overrides.ts';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,cAAc,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deskwork/core — barrel export of every public symbol used across
|
|
3
|
+
* the cli and studio packages.
|
|
4
|
+
*
|
|
5
|
+
* Subpath imports (e.g. `@deskwork/core/calendar`) are also supported
|
|
6
|
+
* for callers that want to be explicit about which module they pull
|
|
7
|
+
* from. Both forms resolve to the same source files.
|
|
8
|
+
*/
|
|
9
|
+
export * from "./types.js";
|
|
10
|
+
export * from "./config.js";
|
|
11
|
+
export * from "./paths.js";
|
|
12
|
+
export * from "./cli.js";
|
|
13
|
+
export * from "./calendar.js";
|
|
14
|
+
export * from "./calendar-mutations.js";
|
|
15
|
+
export * from "./frontmatter.js";
|
|
16
|
+
export * from "./journal.js";
|
|
17
|
+
export * from "./scaffold.js";
|
|
18
|
+
export * from "./body-state.js";
|
|
19
|
+
export * from "./ingest.js";
|
|
20
|
+
export * as scrapbook from "./scrapbook.js";
|
|
21
|
+
export * as renameSlug from "./rename-slug.js";
|
|
22
|
+
export * as review from "./review/index.js";
|
|
23
|
+
export * as contentTree from "./content-tree.js";
|
|
24
|
+
export * from "./content-index.js";
|
|
25
|
+
export * as doctor from "./doctor/index.js";
|
|
26
|
+
export * from "./overrides.js";
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,cAAc,oBAAoB,CAAC;AACnC,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
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 { type Stage } from './types.ts';
|
|
12
|
+
import type { FrontmatterData } from './frontmatter.ts';
|
|
13
|
+
/**
|
|
14
|
+
* Where a derived value came from. `'frontmatter'` is reserved for
|
|
15
|
+
* values that actually appear in the file's frontmatter — when a field
|
|
16
|
+
* is absent and we substitute a hardcoded fallback (e.g. defaulting
|
|
17
|
+
* state to `Ideas` when the frontmatter has no `state:` key), the
|
|
18
|
+
* source is `'default'`. The dry-run plan surfaces this so the
|
|
19
|
+
* operator can tell at a glance whether a row reflects the file or
|
|
20
|
+
* was filled in by the ingest layer.
|
|
21
|
+
*/
|
|
22
|
+
export type DerivationSource = 'frontmatter' | 'path' | 'mtime' | 'today' | 'explicit' | 'default';
|
|
23
|
+
export interface SlugDerivation {
|
|
24
|
+
value: string;
|
|
25
|
+
source: DerivationSource;
|
|
26
|
+
reason?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface StateDerivation {
|
|
29
|
+
value: Stage | null;
|
|
30
|
+
source: DerivationSource;
|
|
31
|
+
rawValue?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface DateDerivation {
|
|
34
|
+
value: string;
|
|
35
|
+
source: DerivationSource;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Canonical state-string normalization. Maps frontmatter values that
|
|
39
|
+
* editorial projects commonly use onto our six lanes. Anything outside
|
|
40
|
+
* this table comes back ambiguous — the operator must pass `--state`.
|
|
41
|
+
*/
|
|
42
|
+
export declare const STATE_ALIASES: Record<string, Stage>;
|
|
43
|
+
export interface SlugDeriveInput {
|
|
44
|
+
filePath: string;
|
|
45
|
+
root: string;
|
|
46
|
+
frontmatter: FrontmatterData;
|
|
47
|
+
fieldName: string;
|
|
48
|
+
slugFrom: 'frontmatter' | 'path';
|
|
49
|
+
explicitSlug?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Derive a slug for a discovered file. Order:
|
|
53
|
+
*
|
|
54
|
+
* 1. `explicitSlug` (operator's `--slug`) — wins, marked 'explicit'.
|
|
55
|
+
* 2. When `slugFrom === 'frontmatter'`, the named frontmatter field
|
|
56
|
+
* (default `slug:`) when set; otherwise falls through to path.
|
|
57
|
+
* 3. Path-based derivation — see `slugFromPath`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function deriveSlug(input: SlugDeriveInput): SlugDerivation;
|
|
60
|
+
export interface StateDeriveInput {
|
|
61
|
+
frontmatter: FrontmatterData;
|
|
62
|
+
stateField: string;
|
|
63
|
+
dateField: string;
|
|
64
|
+
stateFrom: 'frontmatter' | 'datePublished';
|
|
65
|
+
explicitState?: Stage;
|
|
66
|
+
now?: Date;
|
|
67
|
+
}
|
|
68
|
+
export declare function deriveState(input: StateDeriveInput): StateDerivation;
|
|
69
|
+
export interface DateDeriveInput {
|
|
70
|
+
filePath: string;
|
|
71
|
+
frontmatter: FrontmatterData;
|
|
72
|
+
dateField: string;
|
|
73
|
+
explicitDate?: string;
|
|
74
|
+
now?: Date;
|
|
75
|
+
}
|
|
76
|
+
export declare function deriveDate(input: DateDeriveInput): DateDerivation;
|
|
77
|
+
export declare function deriveTitle(frontmatter: FrontmatterData, fieldName: string, slug: string): string;
|
|
78
|
+
export declare function deriveDescription(frontmatter: FrontmatterData, fieldName: string): string;
|
|
79
|
+
//# sourceMappingURL=ingest-derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-derive.d.ts","sourceRoot":"","sources":["../src/ingest-derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,MAAM,GACN,OAAO,GACP,OAAO,GACP,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAKD;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAe/C,CAAC;AAMF,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,aAAa,GAAG,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,cAAc,CAYjE;AA0HD,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,eAAe,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,aAAa,GAAG,eAAe,CAAC;IAC3C,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,eAAe,CA+BpE;AAiBD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,cAAc,CA8BjE;AAMD,wBAAgB,WAAW,CACzB,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,MAAM,CAWR;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,MAAM,GAChB,MAAM,CAER"}
|