@cudoment/cudoc 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +1 -1
  2. package/dist/document.d.ts +11 -1
  3. package/dist/document.d.ts.map +1 -1
  4. package/dist/document.js +33 -2
  5. package/dist/document.js.map +1 -1
  6. package/dist/internal/core/mdx/imports.d.ts +21 -0
  7. package/dist/internal/core/mdx/imports.d.ts.map +1 -0
  8. package/dist/internal/core/mdx/imports.js +80 -0
  9. package/dist/internal/core/mdx/imports.js.map +1 -0
  10. package/dist/internal/core/mdx/index.d.ts +1 -0
  11. package/dist/internal/core/mdx/index.d.ts.map +1 -1
  12. package/dist/internal/core/mdx/index.js +1 -0
  13. package/dist/internal/core/mdx/index.js.map +1 -1
  14. package/dist/internal/transforms/table-column-layout/create-table.d.ts.map +1 -1
  15. package/dist/internal/transforms/table-column-layout/create-table.js +40 -17
  16. package/dist/internal/transforms/table-column-layout/create-table.js.map +1 -1
  17. package/dist/internal/transforms/table-column-layout/index.d.ts +32 -0
  18. package/dist/internal/transforms/table-column-layout/index.d.ts.map +1 -1
  19. package/dist/internal/transforms/table-column-layout/index.js +66 -0
  20. package/dist/internal/transforms/table-column-layout/index.js.map +1 -1
  21. package/dist/markdown.d.ts +8 -0
  22. package/dist/markdown.d.ts.map +1 -1
  23. package/dist/markdown.js +9 -1
  24. package/dist/markdown.js.map +1 -1
  25. package/dist/node/check.d.ts +6 -3
  26. package/dist/node/check.d.ts.map +1 -1
  27. package/dist/node/check.js +101 -23
  28. package/dist/node/check.js.map +1 -1
  29. package/dist/node/cli.js +26 -1
  30. package/dist/node/cli.js.map +1 -1
  31. package/dist/node/dataset.d.ts +14 -1
  32. package/dist/node/dataset.d.ts.map +1 -1
  33. package/dist/node/dataset.js +40 -4
  34. package/dist/node/dataset.js.map +1 -1
  35. package/dist/node/glob.d.ts +21 -0
  36. package/dist/node/glob.d.ts.map +1 -0
  37. package/dist/node/glob.js +61 -0
  38. package/dist/node/glob.js.map +1 -0
  39. package/dist/node/library.d.ts +70 -4
  40. package/dist/node/library.d.ts.map +1 -1
  41. package/dist/node/library.js +196 -32
  42. package/dist/node/library.js.map +1 -1
  43. package/dist/node/local-target.d.ts +28 -8
  44. package/dist/node/local-target.d.ts.map +1 -1
  45. package/dist/node/local-target.js +41 -12
  46. package/dist/node/local-target.js.map +1 -1
  47. package/dist/node/prepare-embeds.d.ts +16 -2
  48. package/dist/node/prepare-embeds.d.ts.map +1 -1
  49. package/dist/node/prepare-embeds.js +41 -5
  50. package/dist/node/prepare-embeds.js.map +1 -1
  51. package/dist/node/resolve-embed.d.ts +79 -1
  52. package/dist/node/resolve-embed.d.ts.map +1 -1
  53. package/dist/node/resolve-embed.js +251 -43
  54. package/dist/node/resolve-embed.js.map +1 -1
  55. package/dist/node/roots.d.ts +67 -0
  56. package/dist/node/roots.d.ts.map +1 -0
  57. package/dist/node/roots.js +134 -0
  58. package/dist/node/roots.js.map +1 -0
  59. package/dist/node/storage.d.ts +21 -3
  60. package/dist/node/storage.d.ts.map +1 -1
  61. package/dist/node/storage.js +41 -12
  62. package/dist/node/storage.js.map +1 -1
  63. package/dist/node/watch.d.ts +81 -0
  64. package/dist/node/watch.d.ts.map +1 -0
  65. package/dist/node/watch.js +140 -0
  66. package/dist/node/watch.js.map +1 -0
  67. package/dist/paged.d.ts +34 -0
  68. package/dist/paged.d.ts.map +1 -0
  69. package/dist/paged.js +44 -0
  70. package/dist/paged.js.map +1 -0
  71. package/package.json +15 -2
  72. package/styles.css +5 -2
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Where documents come from, and how a library path maps back to a file.
3
+ *
4
+ * A library has one coordinate system: the library path, which is a root's
5
+ * `base` followed by the file's path under that root. Document ids, links,
6
+ * embed sources and the checker all speak that system, so a project can
7
+ * collect `content/` under `docs` and `glossary/` under `terms` and have
8
+ * `/docs/guide` and `/terms/token` mean what they mean on the site. These
9
+ * helpers are the one place that knows which directory a library path lives
10
+ * in, so nothing else has to.
11
+ */
12
+ import fs from "node:fs";
13
+ import path from "node:path";
14
+ import { posix, safePath } from "./storage.js";
15
+ /** `/docs/` and `docs` are the same base; `..`, `?` and `#` never are one. */
16
+ export function normalizeBase(base) {
17
+ if (base === undefined)
18
+ return "";
19
+ if (typeof base !== "string")
20
+ throw new Error("cudoc: a root base must be a string");
21
+ const value = base.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
22
+ if (!value)
23
+ return "";
24
+ if (value.split("/").some((part) => !part || part === "." || part === "..") ||
25
+ /[?#]/.test(value))
26
+ throw new Error(`cudoc: invalid root base: ${base}`);
27
+ return value;
28
+ }
29
+ /**
30
+ * The roots a collection or a consumer was given. `sourceRoot` is the
31
+ * single-root shorthand for `roots: [{ dir: sourceRoot }]`; giving both is an
32
+ * error rather than a merge, because the two spell the same thing.
33
+ */
34
+ export function resolveRoots(options) {
35
+ if (options.sourceRoot !== undefined && options.roots !== undefined)
36
+ throw new Error("cudoc: give either sourceRoot or roots, not both");
37
+ const given = options.roots ??
38
+ (options.sourceRoot === undefined ? [] : [{ dir: options.sourceRoot }]);
39
+ if (!Array.isArray(given) || !given.length)
40
+ throw new Error("cudoc: sourceRoot or a non-empty roots list is required");
41
+ const roots = given.map((root) => {
42
+ if (!root || typeof root !== "object" || typeof root.dir !== "string")
43
+ throw new Error("cudoc: each root needs a dir");
44
+ if (!root.dir)
45
+ throw new Error("cudoc: a root dir must not be empty");
46
+ return { dir: path.resolve(root.dir), base: normalizeBase(root.base) };
47
+ });
48
+ const dirs = new Set();
49
+ for (const root of roots) {
50
+ if (dirs.has(root.dir))
51
+ throw new Error(`cudoc: root directory listed twice: ${root.dir}`);
52
+ dirs.add(root.dir);
53
+ }
54
+ return roots;
55
+ }
56
+ /** A root's path for a file inside it, or undefined when the file is elsewhere. */
57
+ const under = (dir, file) => {
58
+ const relative = path.relative(dir, file);
59
+ if (!relative ||
60
+ relative === ".." ||
61
+ relative.startsWith(`..${path.sep}`) ||
62
+ path.isAbsolute(relative))
63
+ return undefined;
64
+ return posix(relative);
65
+ };
66
+ /** `base/relative`, or just `relative` for a root at the top. */
67
+ export const libraryPath = (root, relative) => root.base ? `${root.base}/${relative}` : relative;
68
+ /**
69
+ * The library path of a file, from the innermost root that contains it.
70
+ *
71
+ * Nested root directories are allowed — a project may collect `docs/` and
72
+ * give `docs/api/` its own base — and the deeper one owns the file.
73
+ */
74
+ export function libraryPathOf(roots, file) {
75
+ const absolute = path.resolve(file);
76
+ let best;
77
+ for (const root of roots) {
78
+ const relative = under(root.dir, absolute);
79
+ if (relative === undefined)
80
+ continue;
81
+ const depth = root.dir.split(path.sep).length;
82
+ if (!best || depth > best.depth)
83
+ best = { depth, value: libraryPath(root, relative) };
84
+ }
85
+ return best?.value;
86
+ }
87
+ /** The document id a file collects as: its library path without the extension. */
88
+ export const documentIdOf = (roots, file) => libraryPathOf(roots, file)?.replace(/\.mdx?$/i, "");
89
+ /** Whether `libraryPath` sits under the root's base. */
90
+ const inBase = (root, target) => {
91
+ if (!root.base)
92
+ return target;
93
+ if (target === root.base)
94
+ return "";
95
+ return target.startsWith(`${root.base}/`)
96
+ ? target.slice(root.base.length + 1)
97
+ : undefined;
98
+ };
99
+ /**
100
+ * Every file a library path could name, most specific base first.
101
+ *
102
+ * Two roots may share a base, and one base may extend another, so the answer
103
+ * is a list: the caller that wants the file that exists checks each, and the
104
+ * caller that wants to know whether the path could exist at all takes the
105
+ * first. A path that would escape a root's directory is left out.
106
+ */
107
+ export function candidateFiles(roots, target) {
108
+ return [...roots]
109
+ .map((root, order) => ({ root, order }))
110
+ .sort((a, b) => b.root.base.length - a.root.base.length || a.order - b.order)
111
+ .flatMap(({ root }) => {
112
+ const relative = inBase(root, target);
113
+ if (relative === undefined)
114
+ return [];
115
+ try {
116
+ return [safePath(root.dir, relative)];
117
+ }
118
+ catch {
119
+ return [];
120
+ }
121
+ });
122
+ }
123
+ /**
124
+ * The file a library path names, preferring one that exists.
125
+ *
126
+ * When none exists — the caller is about to compile a slice of a document
127
+ * that has since been deleted, say — the first candidate is returned so an
128
+ * error names a real location.
129
+ */
130
+ export function sourceFileOf(roots, target) {
131
+ const candidates = candidateFiles(roots, target);
132
+ return candidates.find((file) => fs.existsSync(file)) ?? candidates[0];
133
+ }
134
+ //# sourceMappingURL=roots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roots.js","sourceRoot":"","sources":["../../src/node/roots.ts"],"names":[],"mappings":"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"}
@@ -3,8 +3,26 @@ export declare const posix: (value: string) => string;
3
3
  export declare function contained(root: string, target: string): boolean;
4
4
  export declare function realPath(target: string): string;
5
5
  export declare function safePath(root: string, relative: string): string;
6
- export declare function sourceFiles(root: string, extensions?: string[]): string[];
6
+ /**
7
+ * Every file under `root` with one of the extensions, sorted, as absolute
8
+ * paths. Dot entries and `node_modules` are always skipped; `exclude` is asked
9
+ * about each remaining entry's POSIX path relative to `root`, and a directory
10
+ * it excludes is not entered, so a symlink inside one is never seen.
11
+ */
12
+ export declare function sourceFiles(root: string, extensions?: string[], options?: {
13
+ exclude?: (relative: string) => boolean;
14
+ }): string[];
7
15
  export declare function writeJson(file: string, value: unknown): void;
8
- /** Only replace directories bearing our ownership marker. Never delete arbitrary output. */
9
- export declare function publishDirectory(inputRoot: string, outputRoot: string, build: (staging: string) => void): void;
16
+ /**
17
+ * Only replace directories bearing our ownership marker. Never delete arbitrary output.
18
+ *
19
+ * `inputRoots` are the directories the build reads; the output may not sit
20
+ * inside or around any of them. A build callback may be synchronous or
21
+ * asynchronous. The return value of `build` is what decides: a thenable defers
22
+ * the commit until it settles and makes this function return a promise,
23
+ * anything else commits immediately and returns nothing. The overloads are a
24
+ * convenience; the runtime check is the authority.
25
+ */
26
+ export declare function publishDirectory(inputRoots: string | string[], outputRoot: string, build: (staging: string) => void): void;
27
+ export declare function publishDirectory(inputRoots: string | string[], outputRoot: string, build: (staging: string) => Promise<void>): Promise<void>;
10
28
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/node/storage.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI,GAAI,OAAO,MAAM,WACuB,CAAA;AACzD,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,WAAoC,CAAA;AACvE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAQ/D;AACD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAI/C;AACD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ/D;AACD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,UAAU,WAAkB,GAC3B,MAAM,EAAE,CAiBV;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,QAGrD;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC/B,IAAI,CAkCN"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/node/storage.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI,GAAI,OAAO,MAAM,WACuB,CAAA;AACzD,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,WAAoC,CAAA;AACvE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAQ/D;AACD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAI/C;AACD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ/D;AACD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,UAAU,WAAkB,EAC5B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;CAAO,GACxD,MAAM,EAAE,CAmBV;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,QAGrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,EAC7B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC/B,IAAI,CAAA;AACP,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,EAC7B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GACxC,OAAO,CAAC,IAAI,CAAC,CAAA"}
@@ -23,7 +23,14 @@ export function safePath(root, relative) {
23
23
  throw new Error(`cudoc: path escapes document root: ${relative}`);
24
24
  return target;
25
25
  }
26
- export function sourceFiles(root, extensions = [".md", ".mdx"]) {
26
+ /**
27
+ * Every file under `root` with one of the extensions, sorted, as absolute
28
+ * paths. Dot entries and `node_modules` are always skipped; `exclude` is asked
29
+ * about each remaining entry's POSIX path relative to `root`, and a directory
30
+ * it excludes is not entered, so a symlink inside one is never seen.
31
+ */
32
+ export function sourceFiles(root, extensions = [".md", ".mdx"], options = {}) {
33
+ const base = path.resolve(root);
27
34
  const walk = (dir) => fs
28
35
  .readdirSync(dir, { withFileTypes: true })
29
36
  .sort((a, b) => a.name.localeCompare(b.name, "en"))
@@ -31,6 +38,8 @@ export function sourceFiles(root, extensions = [".md", ".mdx"]) {
31
38
  if (entry.name.startsWith(".") || entry.name === "node_modules")
32
39
  return [];
33
40
  const file = path.join(dir, entry.name);
41
+ if (options.exclude?.(posix(path.relative(base, file))))
42
+ return [];
34
43
  if (entry.isSymbolicLink())
35
44
  throw new Error(`cudoc: symlink in source tree: ${file}`);
36
45
  if (entry.isDirectory())
@@ -39,19 +48,21 @@ export function sourceFiles(root, extensions = [".md", ".mdx"]) {
39
48
  ? [file]
40
49
  : [];
41
50
  });
42
- return walk(path.resolve(root));
51
+ return walk(base);
43
52
  }
44
53
  export function writeJson(file, value) {
45
54
  fs.mkdirSync(path.dirname(file), { recursive: true });
46
55
  fs.writeFileSync(file, JSON.stringify(value));
47
56
  }
48
- /** Only replace directories bearing our ownership marker. Never delete arbitrary output. */
49
- export function publishDirectory(inputRoot, outputRoot, build) {
57
+ export function publishDirectory(inputRoots, outputRoot, build) {
50
58
  if (fs.existsSync(outputRoot) && fs.lstatSync(outputRoot).isSymbolicLink())
51
59
  throw new Error("cudoc: output directory must not be a symlink");
52
- const input = realPath(inputRoot), output = realPath(outputRoot);
53
- if (contained(input, output) || contained(output, input))
54
- throw new Error("cudoc: input and output directories overlap");
60
+ const output = realPath(outputRoot);
61
+ for (const inputRoot of [inputRoots].flat()) {
62
+ const input = realPath(inputRoot);
63
+ if (contained(input, output) || contained(output, input))
64
+ throw new Error("cudoc: input and output directories overlap");
65
+ }
55
66
  fs.mkdirSync(path.dirname(output), { recursive: true });
56
67
  const owner = path.join(output, ".cudoc-output");
57
68
  if (fs.existsSync(output) &&
@@ -61,9 +72,7 @@ export function publishDirectory(inputRoot, outputRoot, build) {
61
72
  const fd = fs.openSync(lock, "wx");
62
73
  const staging = fs.mkdtempSync(`${output}.tmp-`);
63
74
  const backup = `${output}.previous-${crypto.randomUUID()}`;
64
- try {
65
- fs.writeFileSync(path.join(staging, ".cudoc-output"), "cudoc\n");
66
- build(staging);
75
+ const commit = () => {
67
76
  if (fs.existsSync(output))
68
77
  fs.renameSync(output, backup);
69
78
  try {
@@ -75,11 +84,31 @@ export function publishDirectory(inputRoot, outputRoot, build) {
75
84
  throw error;
76
85
  }
77
86
  fs.rmSync(backup, { recursive: true, force: true });
78
- }
79
- finally {
87
+ };
88
+ const cleanup = () => {
80
89
  fs.rmSync(staging, { recursive: true, force: true });
81
90
  fs.closeSync(fd);
82
91
  fs.unlinkSync(lock);
92
+ };
93
+ let result;
94
+ try {
95
+ fs.writeFileSync(path.join(staging, ".cudoc-output"), "cudoc\n");
96
+ result = build(staging);
97
+ }
98
+ catch (error) {
99
+ cleanup();
100
+ throw error;
101
+ }
102
+ const pending = result;
103
+ if (typeof pending?.then !== "function") {
104
+ try {
105
+ commit();
106
+ }
107
+ finally {
108
+ cleanup();
109
+ }
110
+ return;
83
111
  }
112
+ return pending.then(commit).finally(cleanup);
84
113
  }
85
114
  //# sourceMappingURL=storage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/node/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,MAAM,MAAM,aAAa,CAAA;AAEhC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CACpC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACzD,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACvE,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc;IACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC5C,OAAO,CACL,QAAQ,KAAK,EAAE;QACf,CAAC,QAAQ,KAAK,IAAI;YAChB,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;YACrC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAC9B,CAAA;AACH,CAAC;AACD,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACrC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;IAC7D,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC7E,CAAC;AACD,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,QAAgB;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAC3C,IACE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QAE7B,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,EAAE,CAAC,CAAA;IACnE,OAAO,MAAM,CAAA;AACf,CAAC;AACD,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC;IAE5B,MAAM,IAAI,GAAG,CAAC,GAAW,EAAY,EAAE,CACrC,EAAE;SACC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;SAClD,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACjB,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;YAC7D,OAAO,EAAE,CAAA;QACX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,KAAK,CAAC,cAAc,EAAE;YACxB,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAA;QAC3D,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAA;QAC1C,OAAO,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAC1D,CAAC,CAAC,CAAC,IAAI,CAAC;YACR,CAAC,CAAC,EAAE,CAAA;IACR,CAAC,CAAC,CAAA;IACN,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;AACjC,CAAC;AACD,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAc;IACpD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;AAC/C,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,UAAkB,EAClB,KAAgC;IAEhC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,cAAc,EAAE;QACxE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,EAC/B,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAA;IAC/B,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAChD,IACE,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QACrB,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,SAAS,CAAC;QAEvE,MAAM,IAAI,KAAK,CAAC,iDAAiD,MAAM,EAAE,CAAC,CAAA;IAC5E,MAAM,IAAI,GAAG,GAAG,MAAM,OAAO,CAAA;IAC7B,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAClC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,CAAA;IAChD,MAAM,MAAM,GAAG,GAAG,MAAM,aAAa,MAAM,CAAC,UAAU,EAAE,EAAE,CAAA;IAC1D,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,SAAS,CAAC,CAAA;QAChE,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACxD,IAAI,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;gBAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;YACxD,MAAM,KAAK,CAAA;QACb,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;QAChB,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/node/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Collection that repeats as sources change.
3
+ *
4
+ * A pass is what the CLI's `collect` does once: build the library, then
5
+ * prepare the embeds. Here every pass after the first hands the previous
6
+ * library and the previous preparation back in, so only the documents whose
7
+ * text changed compile again and only the blocks that read a changed document
8
+ * resolve again. The watcher runs a pass when a file under any root changes,
9
+ * after a short quiet period, and keeps the last good result when a pass
10
+ * fails, so a half-typed document is an error message rather than a broken
11
+ * library.
12
+ */
13
+ import type { CompiledDocument } from "../markdown.js";
14
+ import { type BuildDocumentsOptions, type Library } from "./library.js";
15
+ import { type PreparedEmbeds } from "./prepare-embeds.js";
16
+ /**
17
+ * A collection configuration as a config file exports it: the build options,
18
+ * where the compiler may return its result synchronously or as a promise.
19
+ */
20
+ export type CollectConfig = Omit<BuildDocumentsOptions, "compiler"> & {
21
+ compiler?: (...parameters: Parameters<NonNullable<BuildDocumentsOptions["compiler"]>>) => CompiledDocument | Promise<CompiledDocument>;
22
+ };
23
+ /** What one pass produced and how much of it was new. */
24
+ export type CollectionPass = {
25
+ library: Library;
26
+ prepared: PreparedEmbeds;
27
+ documentCount: number;
28
+ /** Ids of the documents this pass compiled. Every document on a full pass. */
29
+ compiled: string[];
30
+ /** Documents taken from the previous library unchanged. */
31
+ reused: number;
32
+ /** Embed blocks in the library, and how many were taken from the previous preparation. */
33
+ blocks: number;
34
+ reusedBlocks: number;
35
+ outDir: string;
36
+ /** Wall-clock milliseconds the pass took. */
37
+ elapsed: number;
38
+ };
39
+ export type CollectionState = {
40
+ library?: Library;
41
+ prepared?: PreparedEmbeds;
42
+ };
43
+ /**
44
+ * The library and preparation already in `outDir`, when they load and are
45
+ * worth reusing, so a watcher's first pass compiles only what changed since
46
+ * the last run. Anything unreadable or incompatible means starting fresh.
47
+ */
48
+ export declare function previousCollection(outDir?: string): CollectionState;
49
+ /**
50
+ * One pass: collect, then prepare. With `previous`, an unchanged document is
51
+ * not compiled and an unaffected block is not resolved; the published files
52
+ * are complete either way.
53
+ */
54
+ export declare function collectDocuments(config: CollectConfig, previous?: CollectionState): Promise<CollectionPass>;
55
+ export type WatchOptions = {
56
+ /** Quiet time after the last change before a pass starts, in milliseconds. Default 150. */
57
+ debounce?: number;
58
+ /** The result of every pass, the first included. */
59
+ onPass?: (pass: CollectionPass) => void;
60
+ /** A failed pass. The watcher keeps the last good result and keeps running. */
61
+ onError?: (error: unknown) => void;
62
+ /**
63
+ * Whether the first pass may start from what `outDir` already holds.
64
+ * Default true.
65
+ */
66
+ reuseOutput?: boolean;
67
+ };
68
+ export type CollectionWatcher = {
69
+ /** Resolves when the first pass has finished, whether it succeeded or failed. */
70
+ ready: Promise<void>;
71
+ /** Stops watching. A pass in progress finishes. */
72
+ close(): void;
73
+ };
74
+ /**
75
+ * Collects once, then again whenever a `.md` or `.mdx` file under any root is
76
+ * created, changed, renamed or deleted. Changes that arrive while a pass runs
77
+ * start another pass when it finishes, so the output always reflects the
78
+ * latest files.
79
+ */
80
+ export declare function watchDocuments(config: CollectConfig, options?: WatchOptions): CollectionWatcher;
81
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/node/watch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAKL,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACb,MAAM,cAAc,CAAA;AACrB,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAExE;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,GAAG;IACpE,QAAQ,CAAC,EAAE,CACT,GAAG,UAAU,EAAE,UAAU,CAAC,WAAW,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAC,KACtE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;CAClD,CAAA;AAED,yDAAyD;AACzD,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,cAAc,CAAA;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAA;IACd,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,cAAc,CAAA;CAC1B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,SAAqB,GAC1B,eAAe,CAkBjB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,aAAa,EACrB,QAAQ,GAAE,eAAoB,GAC7B,OAAO,CAAC,cAAc,CAAC,CA8BzB;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oDAAoD;IACpD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;IACvC,+EAA+E;IAC/E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iFAAiF;IACjF,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACpB,mDAAmD;IACnD,KAAK,IAAI,IAAI,CAAA;CACd,CAAA;AAOD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,YAAiB,GACzB,iBAAiB,CAoDnB"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Collection that repeats as sources change.
3
+ *
4
+ * A pass is what the CLI's `collect` does once: build the library, then
5
+ * prepare the embeds. Here every pass after the first hands the previous
6
+ * library and the previous preparation back in, so only the documents whose
7
+ * text changed compile again and only the blocks that read a changed document
8
+ * resolve again. The watcher runs a pass when a file under any root changes,
9
+ * after a short quiet period, and keeps the last good result when a pass
10
+ * fails, so a half-typed document is an error message rather than a broken
11
+ * library.
12
+ */
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import { buildDocuments, buildDocumentsAsync, loadLibrary, resolveRoots, } from "./library.js";
16
+ import { prepareEmbeds } from "./prepare-embeds.js";
17
+ /**
18
+ * The library and preparation already in `outDir`, when they load and are
19
+ * worth reusing, so a watcher's first pass compiles only what changed since
20
+ * the last run. Anything unreadable or incompatible means starting fresh.
21
+ */
22
+ export function previousCollection(outDir = ".cudoc/documents") {
23
+ const state = {};
24
+ try {
25
+ if (fs.existsSync(path.join(outDir, "manifest.json")))
26
+ state.library = loadLibrary(outDir);
27
+ }
28
+ catch {
29
+ return {};
30
+ }
31
+ try {
32
+ const file = path.join(outDir, "embeds.json");
33
+ if (state.library && fs.existsSync(file)) {
34
+ const prepared = JSON.parse(fs.readFileSync(file, "utf8"));
35
+ if (prepared?.schemaVersion === 2)
36
+ state.prepared = prepared;
37
+ }
38
+ }
39
+ catch {
40
+ delete state.prepared;
41
+ }
42
+ return state;
43
+ }
44
+ /**
45
+ * One pass: collect, then prepare. With `previous`, an unchanged document is
46
+ * not compiled and an unaffected block is not resolved; the published files
47
+ * are complete either way.
48
+ */
49
+ export async function collectDocuments(config, previous = {}) {
50
+ const started = Date.now();
51
+ const outDir = config.outDir ?? ".cudoc/documents";
52
+ const { compiler, ...rest } = config;
53
+ const options = { ...rest, previous: previous.library };
54
+ const library = compiler
55
+ ? await buildDocumentsAsync({
56
+ ...options,
57
+ compiler: async (...parameters) => compiler(...parameters),
58
+ })
59
+ : buildDocuments(options);
60
+ const prepared = await prepareEmbeds(library, outDir, {
61
+ previous: previous.prepared,
62
+ });
63
+ const keys = Object.keys(prepared.blocks);
64
+ return {
65
+ library,
66
+ prepared,
67
+ documentCount: library.documents.length,
68
+ compiled: library.incremental?.compiled ??
69
+ library.documents.map((document) => document.id),
70
+ reused: library.incremental?.reused.length ?? 0,
71
+ blocks: keys.length,
72
+ reusedBlocks: keys.filter((key) => previous.prepared?.blocks[key] === prepared.blocks[key]).length,
73
+ outDir,
74
+ elapsed: Date.now() - started,
75
+ };
76
+ }
77
+ /** Whether a changed path is one collection reads. */
78
+ const isSource = (filename) => filename === null ||
79
+ /\.mdx?$/i.test(typeof filename === "string" ? filename : String(filename));
80
+ /**
81
+ * Collects once, then again whenever a `.md` or `.mdx` file under any root is
82
+ * created, changed, renamed or deleted. Changes that arrive while a pass runs
83
+ * start another pass when it finishes, so the output always reflects the
84
+ * latest files.
85
+ */
86
+ export function watchDocuments(config, options = {}) {
87
+ const debounce = options.debounce ?? 150;
88
+ const roots = resolveRoots(config);
89
+ let state = options.reuseOutput === false ? {} : previousCollection(config.outDir);
90
+ let running;
91
+ let pending = false;
92
+ let timer;
93
+ let closed = false;
94
+ const pass = async () => {
95
+ try {
96
+ const result = await collectDocuments(config, state);
97
+ state = { library: result.library, prepared: result.prepared };
98
+ options.onPass?.(result);
99
+ }
100
+ catch (error) {
101
+ options.onError?.(error);
102
+ }
103
+ };
104
+ const run = () => {
105
+ if (running) {
106
+ pending = true;
107
+ return running;
108
+ }
109
+ running = pass().then(async () => {
110
+ running = undefined;
111
+ if (pending && !closed) {
112
+ pending = false;
113
+ await run();
114
+ }
115
+ });
116
+ return running;
117
+ };
118
+ const schedule = (_event, filename) => {
119
+ if (closed || !isSource(filename))
120
+ return;
121
+ if (timer)
122
+ clearTimeout(timer);
123
+ timer = setTimeout(() => {
124
+ timer = undefined;
125
+ void run();
126
+ }, debounce);
127
+ };
128
+ const watchers = roots.map((root) => fs.watch(root.dir, { recursive: true }, schedule));
129
+ return {
130
+ ready: run(),
131
+ close() {
132
+ closed = true;
133
+ if (timer)
134
+ clearTimeout(timer);
135
+ for (const watcher of watchers)
136
+ watcher.close();
137
+ },
138
+ };
139
+ }
140
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/node/watch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,YAAY,GAGb,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,aAAa,EAAuB,MAAM,qBAAqB,CAAA;AAkCxE;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAM,GAAG,kBAAkB;IAE3B,MAAM,KAAK,GAAoB,EAAE,CAAA;IACjC,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YACnD,KAAK,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;QAC7C,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;YAC1D,IAAI,QAAQ,EAAE,aAAa,KAAK,CAAC;gBAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAA;QAC9D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,QAAQ,CAAA;IACvB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAqB,EACrB,WAA4B,EAAE;IAE9B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,kBAAkB,CAAA;IAClD,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAA;IACpC,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAA;IACvD,MAAM,OAAO,GAAG,QAAQ;QACtB,CAAC,CAAC,MAAM,mBAAmB,CAAC;YACxB,GAAG,OAAO;YACV,QAAQ,EAAE,KAAK,EAAE,GAAG,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC;SAC3D,CAAC;QACJ,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;IAC3B,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE;QACpD,QAAQ,EAAE,QAAQ,CAAC,QAAQ;KAC5B,CAAC,CAAA;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACzC,OAAO;QACL,OAAO;QACP,QAAQ;QACR,aAAa,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM;QACvC,QAAQ,EACN,OAAO,CAAC,WAAW,EAAE,QAAQ;YAC7B,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClD,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;QAC/C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,YAAY,EAAE,IAAI,CAAC,MAAM,CACvB,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CACjE,CAAC,MAAM;QACR,MAAM;QACN,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;KAC9B,CAAA;AACH,CAAC;AAuBD,sDAAsD;AACtD,MAAM,QAAQ,GAAG,CAAC,QAAgC,EAAE,EAAE,CACpD,QAAQ,KAAK,IAAI;IACjB,UAAU,CAAC,IAAI,CAAC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;AAE7E;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAqB,EACrB,UAAwB,EAAE;IAE1B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAA;IACxC,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;IAClC,IAAI,KAAK,GACP,OAAO,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxE,IAAI,OAAkC,CAAA;IACtC,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,KAAiC,CAAA;IACrC,IAAI,MAAM,GAAG,KAAK,CAAA;IAElB,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;YACpD,KAAK,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAA;YAC9D,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAA;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC,CAAA;IACD,MAAM,GAAG,GAAG,GAAkB,EAAE;QAC9B,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,GAAG,IAAI,CAAA;YACd,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,OAAO,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YAC/B,OAAO,GAAG,SAAS,CAAA;YACnB,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;gBACvB,OAAO,GAAG,KAAK,CAAA;gBACf,MAAM,GAAG,EAAE,CAAA;YACb,CAAC;QACH,CAAC,CAAC,CAAA;QACF,OAAO,OAAO,CAAA;IAChB,CAAC,CAAA;IACD,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,QAAgC,EAAE,EAAE;QACpE,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAM;QACzC,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAA;QAC9B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,KAAK,GAAG,SAAS,CAAA;YACjB,KAAK,GAAG,EAAE,CAAA;QACZ,CAAC,EAAE,QAAQ,CAAC,CAAA;IACd,CAAC,CAAA;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,CAClD,CAAA;IACD,OAAO;QACL,KAAK,EAAE,GAAG,EAAE;QACZ,KAAK;YACH,MAAM,GAAG,IAAI,CAAA;YACb,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAA;YAC9B,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,OAAO,CAAC,KAAK,EAAE,CAAA;QACjD,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * What the paginated output formats have to agree on.
3
+ *
4
+ * A PDF is printed by a browser and a `.docx` is assembled by a writer that
5
+ * never sees CSS, so the only thing keeping the two in step is a shared
6
+ * definition rather than two implementations that happen to match. This module
7
+ * is browser-safe and holds no I/O.
8
+ */
9
+ import type { Position } from "unist";
10
+ import type { DocumentNode } from "./document.js";
11
+ /** The info string an author writes on a fence to force a page break. */
12
+ export declare const PAGE_BREAK_FENCE = "cudoc-pagebreak";
13
+ /** `data.cudoc.kind` on the node the fence normalizes to. */
14
+ export declare const PAGE_BREAK_KIND = "pageBreak";
15
+ /** The class the printed stylesheets key their `break-after` rule off. */
16
+ export declare const PAGE_BREAK_CLASS = "cudoc-page-break";
17
+ /**
18
+ * Whether a node is an authored page break.
19
+ *
20
+ * A writer must test this **before** any generic `thematicBreak` handling: the
21
+ * break is carried on a `thematicBreak` because that is a childless flow node
22
+ * which can never swallow content, so a handler that dispatches on `type` alone
23
+ * turns an authored page break into a horizontal rule.
24
+ */
25
+ export declare const isPageBreak: (node: DocumentNode) => boolean;
26
+ /**
27
+ * The node an authored break becomes.
28
+ *
29
+ * `hidden` gives it the user agent's `display: none`, so a host stylesheet
30
+ * cudoc does not own cannot give the empty element a margin on the primary
31
+ * site. The printed stylesheet turns it back on and breaks after it.
32
+ */
33
+ export declare const pageBreakNode: (position?: Position) => DocumentNode;
34
+ //# sourceMappingURL=paged.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paged.d.ts","sourceRoot":"","sources":["../src/paged.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,oBAAoB,CAAA;AAEjD,6DAA6D;AAC7D,eAAO,MAAM,eAAe,cAAc,CAAA;AAE1C,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,qBAAqB,CAAA;AAElD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,YAAY,KAAG,OACL,CAAA;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAI,WAAW,QAAQ,KAAG,YAYlD,CAAA"}
package/dist/paged.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * What the paginated output formats have to agree on.
3
+ *
4
+ * A PDF is printed by a browser and a `.docx` is assembled by a writer that
5
+ * never sees CSS, so the only thing keeping the two in step is a shared
6
+ * definition rather than two implementations that happen to match. This module
7
+ * is browser-safe and holds no I/O.
8
+ */
9
+ /** The info string an author writes on a fence to force a page break. */
10
+ export const PAGE_BREAK_FENCE = "cudoc-pagebreak";
11
+ /** `data.cudoc.kind` on the node the fence normalizes to. */
12
+ export const PAGE_BREAK_KIND = "pageBreak";
13
+ /** The class the printed stylesheets key their `break-after` rule off. */
14
+ export const PAGE_BREAK_CLASS = "cudoc-page-break";
15
+ /**
16
+ * Whether a node is an authored page break.
17
+ *
18
+ * A writer must test this **before** any generic `thematicBreak` handling: the
19
+ * break is carried on a `thematicBreak` because that is a childless flow node
20
+ * which can never swallow content, so a handler that dispatches on `type` alone
21
+ * turns an authored page break into a horizontal rule.
22
+ */
23
+ export const isPageBreak = (node) => node.data?.cudoc?.kind === PAGE_BREAK_KIND;
24
+ /**
25
+ * The node an authored break becomes.
26
+ *
27
+ * `hidden` gives it the user agent's `display: none`, so a host stylesheet
28
+ * cudoc does not own cannot give the empty element a margin on the primary
29
+ * site. The printed stylesheet turns it back on and breaks after it.
30
+ */
31
+ export const pageBreakNode = (position) => ({
32
+ type: "thematicBreak",
33
+ ...(position ? { position } : {}),
34
+ data: {
35
+ hName: "div",
36
+ hProperties: {
37
+ className: [PAGE_BREAK_CLASS],
38
+ "data-cudoc-break": "page",
39
+ hidden: true,
40
+ },
41
+ cudoc: { kind: PAGE_BREAK_KIND },
42
+ },
43
+ });
44
+ //# sourceMappingURL=paged.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paged.js","sourceRoot":"","sources":["../src/paged.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,yEAAyE;AACzE,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAAiB,CAAA;AAEjD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAA;AAE1C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAA;AAElD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAkB,EAAW,EAAE,CACzD,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,KAAK,eAAe,CAAA;AAE5C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAmB,EAAgB,EAAE,CAAC,CAAC;IACnE,IAAI,EAAE,eAAe;IACrB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACjC,IAAI,EAAE;QACJ,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,gBAAgB,CAAC;YAC7B,kBAAkB,EAAE,MAAM;YAC1B,MAAM,EAAE,IAAI;SACb;QACD,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE;KACjC;CACF,CAAC,CAAA"}