@glw907/cairn-cms 0.60.1 → 0.62.1

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 (254) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/components/AdminLayout.svelte +22 -0
  3. package/dist/components/CairnAdmin.svelte +3 -0
  4. package/dist/components/CairnTidySettings.svelte +2 -2
  5. package/dist/components/CairnTidySettings.svelte.d.ts +1 -1
  6. package/dist/components/EditPage.svelte +116 -39
  7. package/dist/components/HelpHome.svelte +824 -0
  8. package/dist/components/HelpHome.svelte.d.ts +22 -0
  9. package/dist/components/MarkdownHelpDialog.svelte +4 -15
  10. package/dist/components/client-ingest.d.ts +16 -8
  11. package/dist/components/client-ingest.js +12 -6
  12. package/dist/components/editor-media.js +16 -8
  13. package/dist/components/editor-placeholder.d.ts +4 -2
  14. package/dist/components/editor-tidy.d.ts +24 -12
  15. package/dist/components/editor-tidy.js +8 -4
  16. package/dist/components/index.d.ts +1 -0
  17. package/dist/components/index.js +1 -0
  18. package/dist/components/link-completion.d.ts +12 -6
  19. package/dist/components/link-completion.js +12 -6
  20. package/dist/components/markdown-directives.d.ts +9 -6
  21. package/dist/components/markdown-directives.js +9 -6
  22. package/dist/components/markdown-format.d.ts +7 -2
  23. package/dist/components/markdown-format.js +59 -28
  24. package/dist/components/markdown-reference.d.ts +8 -0
  25. package/dist/components/markdown-reference.js +22 -0
  26. package/dist/components/media-upload-outcome.d.ts +12 -6
  27. package/dist/components/objective-errors.d.ts +8 -4
  28. package/dist/components/objective-errors.js +8 -4
  29. package/dist/components/preview-doc.d.ts +4 -2
  30. package/dist/components/preview-doc.js +4 -2
  31. package/dist/components/spellcheck.d.ts +55 -29
  32. package/dist/components/spellcheck.js +39 -21
  33. package/dist/components/tidy-categorize.d.ts +20 -10
  34. package/dist/components/tidy-categorize.js +16 -8
  35. package/dist/components/tidy-validate.d.ts +12 -6
  36. package/dist/components/tidy-validate.js +20 -10
  37. package/dist/components/topbar-context.d.ts +4 -2
  38. package/dist/content/advisories.d.ts +51 -0
  39. package/dist/content/advisories.js +79 -0
  40. package/dist/content/compose.d.ts +4 -2
  41. package/dist/content/compose.js +1 -0
  42. package/dist/content/excerpt.js +4 -2
  43. package/dist/content/getting-started.d.ts +18 -0
  44. package/dist/content/getting-started.js +12 -0
  45. package/dist/content/links.d.ts +16 -8
  46. package/dist/content/links.js +12 -6
  47. package/dist/content/manifest.d.ts +36 -18
  48. package/dist/content/manifest.js +32 -16
  49. package/dist/content/media-refs.d.ts +4 -2
  50. package/dist/content/media-refs.js +4 -2
  51. package/dist/content/media-rewrite.d.ts +8 -4
  52. package/dist/content/media-rewrite.js +76 -38
  53. package/dist/content/schema.d.ts +20 -10
  54. package/dist/content/site-dictionary.d.ts +4 -2
  55. package/dist/content/site-dictionary.js +8 -4
  56. package/dist/content/types.d.ts +97 -42
  57. package/dist/delivery/content-index.d.ts +16 -8
  58. package/dist/delivery/feeds.js +4 -2
  59. package/dist/delivery/json-ld.d.ts +3 -0
  60. package/dist/delivery/json-ld.js +3 -0
  61. package/dist/delivery/manifest.d.ts +4 -2
  62. package/dist/delivery/manifest.js +4 -2
  63. package/dist/delivery/public-routes.d.ts +12 -6
  64. package/dist/delivery/public-routes.js +4 -2
  65. package/dist/delivery/seo-fields.d.ts +12 -6
  66. package/dist/delivery/seo-fields.js +8 -4
  67. package/dist/delivery/site-indexes.d.ts +4 -2
  68. package/dist/delivery/site-resolver.d.ts +4 -2
  69. package/dist/delivery/site-resolver.js +4 -2
  70. package/dist/doctor/cloudflare-api.d.ts +6 -0
  71. package/dist/doctor/cloudflare-api.js +6 -0
  72. package/dist/doctor/index.d.ts +12 -6
  73. package/dist/doctor/report.d.ts +3 -0
  74. package/dist/doctor/report.js +3 -0
  75. package/dist/doctor/run.d.ts +3 -0
  76. package/dist/doctor/run.js +3 -0
  77. package/dist/doctor/types.d.ts +10 -2
  78. package/dist/doctor/types.js +6 -0
  79. package/dist/doctor/wrangler-config.d.ts +7 -2
  80. package/dist/doctor/wrangler-config.js +3 -0
  81. package/dist/email.d.ts +4 -2
  82. package/dist/env.d.ts +0 -3
  83. package/dist/env.js +0 -3
  84. package/dist/github/branches.d.ts +4 -2
  85. package/dist/github/branches.js +4 -2
  86. package/dist/github/signing.d.ts +1 -1
  87. package/dist/github/signing.js +2 -2
  88. package/dist/log/events.d.ts +1 -1
  89. package/dist/media/bulk-delete-plan.d.ts +8 -4
  90. package/dist/media/config.d.ts +12 -6
  91. package/dist/media/config.js +16 -8
  92. package/dist/media/delivery-bucket.d.ts +4 -2
  93. package/dist/media/library-entry.d.ts +4 -2
  94. package/dist/media/library-entry.js +4 -2
  95. package/dist/media/manifest.d.ts +29 -15
  96. package/dist/media/manifest.js +29 -16
  97. package/dist/media/naming.d.ts +12 -6
  98. package/dist/media/naming.js +24 -12
  99. package/dist/media/orphan-scan.d.ts +4 -2
  100. package/dist/media/reconcile.d.ts +21 -11
  101. package/dist/media/reconcile.js +12 -6
  102. package/dist/media/reference.d.ts +8 -4
  103. package/dist/media/reference.js +12 -6
  104. package/dist/media/rewrite-plan.d.ts +12 -6
  105. package/dist/media/sniff.d.ts +4 -2
  106. package/dist/media/sniff.js +28 -14
  107. package/dist/media/store.d.ts +16 -8
  108. package/dist/media/store.js +4 -2
  109. package/dist/media/transform-url.d.ts +12 -6
  110. package/dist/media/transform-url.js +8 -4
  111. package/dist/media/usage.d.ts +8 -4
  112. package/dist/nav/site-config.d.ts +16 -8
  113. package/dist/render/component-grammar.d.ts +23 -10
  114. package/dist/render/component-grammar.js +19 -8
  115. package/dist/render/component-insert.d.ts +8 -4
  116. package/dist/render/component-insert.js +4 -2
  117. package/dist/render/component-reference.d.ts +4 -2
  118. package/dist/render/component-reference.js +4 -2
  119. package/dist/render/component-validate.d.ts +3 -0
  120. package/dist/render/component-validate.js +3 -0
  121. package/dist/render/glyph.d.ts +4 -2
  122. package/dist/render/glyph.js +4 -2
  123. package/dist/render/pipeline.d.ts +20 -10
  124. package/dist/render/pipeline.js +4 -2
  125. package/dist/render/registry.d.ts +40 -20
  126. package/dist/render/registry.js +16 -8
  127. package/dist/render/rehype-dispatch.d.ts +22 -8
  128. package/dist/render/rehype-dispatch.js +22 -8
  129. package/dist/render/remark-directives.d.ts +3 -0
  130. package/dist/render/remark-directives.js +3 -0
  131. package/dist/render/remark-figure.d.ts +4 -2
  132. package/dist/render/remark-figure.js +4 -2
  133. package/dist/render/resolve-links.d.ts +4 -2
  134. package/dist/render/resolve-links.js +4 -2
  135. package/dist/render/resolve-media.d.ts +16 -8
  136. package/dist/render/resolve-media.js +12 -6
  137. package/dist/sveltekit/admin-dispatch.d.ts +2 -0
  138. package/dist/sveltekit/admin-dispatch.js +9 -3
  139. package/dist/sveltekit/auth-routes.d.ts +3 -0
  140. package/dist/sveltekit/auth-routes.js +3 -0
  141. package/dist/sveltekit/cairn-admin.d.ts +16 -5
  142. package/dist/sveltekit/cairn-admin.js +26 -10
  143. package/dist/sveltekit/content-routes.d.ts +191 -86
  144. package/dist/sveltekit/content-routes.js +295 -107
  145. package/dist/sveltekit/editors-routes.d.ts +3 -0
  146. package/dist/sveltekit/editors-routes.js +3 -0
  147. package/dist/sveltekit/guard.d.ts +4 -2
  148. package/dist/sveltekit/guard.js +4 -2
  149. package/dist/sveltekit/https-required-page.d.ts +1 -1
  150. package/dist/sveltekit/https-required-page.js +1 -1
  151. package/dist/sveltekit/index.d.ts +1 -1
  152. package/dist/sveltekit/media-route.d.ts +1 -2
  153. package/dist/sveltekit/media-route.js +13 -8
  154. package/dist/sveltekit/nav-routes.d.ts +7 -2
  155. package/dist/sveltekit/nav-routes.js +3 -0
  156. package/dist/sveltekit/types.d.ts +4 -2
  157. package/dist/vite/index.d.ts +32 -16
  158. package/dist/vite/index.js +52 -26
  159. package/dist/vite/resolve-root.d.ts +8 -4
  160. package/dist/vite/resolve-root.js +4 -2
  161. package/package.json +7 -1
  162. package/src/lib/components/AdminLayout.svelte +22 -0
  163. package/src/lib/components/CairnAdmin.svelte +3 -0
  164. package/src/lib/components/CairnTidySettings.svelte +2 -2
  165. package/src/lib/components/ComponentForm.svelte +0 -1
  166. package/src/lib/components/EditPage.svelte +133 -41
  167. package/src/lib/components/HelpHome.svelte +850 -0
  168. package/src/lib/components/MarkdownHelpDialog.svelte +4 -15
  169. package/src/lib/components/client-ingest.ts +20 -10
  170. package/src/lib/components/editor-media.ts +20 -10
  171. package/src/lib/components/editor-placeholder.ts +12 -6
  172. package/src/lib/components/editor-tidy.ts +28 -14
  173. package/src/lib/components/index.ts +1 -0
  174. package/src/lib/components/link-completion.ts +12 -6
  175. package/src/lib/components/markdown-directives.ts +13 -8
  176. package/src/lib/components/markdown-format.ts +63 -30
  177. package/src/lib/components/markdown-reference.ts +30 -0
  178. package/src/lib/components/media-upload-outcome.ts +12 -6
  179. package/src/lib/components/objective-errors.ts +16 -8
  180. package/src/lib/components/preview-doc.ts +4 -2
  181. package/src/lib/components/spellcheck.ts +79 -41
  182. package/src/lib/components/tidy-categorize.ts +28 -14
  183. package/src/lib/components/tidy-validate.ts +28 -14
  184. package/src/lib/components/topbar-context.ts +4 -2
  185. package/src/lib/content/advisories.ts +141 -0
  186. package/src/lib/content/compose.ts +5 -2
  187. package/src/lib/content/excerpt.ts +4 -2
  188. package/src/lib/content/getting-started.ts +31 -0
  189. package/src/lib/content/links.ts +16 -8
  190. package/src/lib/content/manifest.ts +36 -18
  191. package/src/lib/content/media-refs.ts +4 -2
  192. package/src/lib/content/media-rewrite.ts +100 -50
  193. package/src/lib/content/schema.ts +20 -10
  194. package/src/lib/content/site-dictionary.ts +8 -4
  195. package/src/lib/content/types.ts +97 -42
  196. package/src/lib/delivery/content-index.ts +16 -8
  197. package/src/lib/delivery/feeds.ts +4 -2
  198. package/src/lib/delivery/json-ld.ts +3 -0
  199. package/src/lib/delivery/manifest.ts +4 -2
  200. package/src/lib/delivery/public-routes.ts +16 -8
  201. package/src/lib/delivery/seo-fields.ts +12 -6
  202. package/src/lib/delivery/site-indexes.ts +4 -2
  203. package/src/lib/delivery/site-resolver.ts +4 -2
  204. package/src/lib/doctor/cloudflare-api.ts +6 -0
  205. package/src/lib/doctor/index.ts +12 -6
  206. package/src/lib/doctor/report.ts +3 -0
  207. package/src/lib/doctor/run.ts +3 -0
  208. package/src/lib/doctor/types.ts +10 -2
  209. package/src/lib/doctor/wrangler-config.ts +7 -2
  210. package/src/lib/email.ts +4 -2
  211. package/src/lib/env.ts +0 -3
  212. package/src/lib/github/branches.ts +4 -2
  213. package/src/lib/github/signing.ts +2 -2
  214. package/src/lib/log/events.ts +1 -0
  215. package/src/lib/media/bulk-delete-plan.ts +8 -4
  216. package/src/lib/media/config.ts +24 -12
  217. package/src/lib/media/delivery-bucket.ts +4 -2
  218. package/src/lib/media/library-entry.ts +4 -2
  219. package/src/lib/media/manifest.ts +33 -18
  220. package/src/lib/media/naming.ts +24 -12
  221. package/src/lib/media/orphan-scan.ts +4 -2
  222. package/src/lib/media/reconcile.ts +21 -11
  223. package/src/lib/media/reference.ts +12 -6
  224. package/src/lib/media/rewrite-plan.ts +12 -6
  225. package/src/lib/media/sniff.ts +28 -14
  226. package/src/lib/media/store.ts +16 -8
  227. package/src/lib/media/transform-url.ts +12 -6
  228. package/src/lib/media/usage.ts +8 -4
  229. package/src/lib/nav/site-config.ts +16 -8
  230. package/src/lib/render/component-grammar.ts +23 -10
  231. package/src/lib/render/component-insert.ts +8 -4
  232. package/src/lib/render/component-reference.ts +4 -2
  233. package/src/lib/render/component-validate.ts +3 -0
  234. package/src/lib/render/glyph.ts +4 -2
  235. package/src/lib/render/pipeline.ts +20 -10
  236. package/src/lib/render/registry.ts +44 -22
  237. package/src/lib/render/rehype-dispatch.ts +22 -8
  238. package/src/lib/render/remark-directives.ts +3 -0
  239. package/src/lib/render/remark-figure.ts +4 -2
  240. package/src/lib/render/resolve-links.ts +4 -2
  241. package/src/lib/render/resolve-media.ts +16 -8
  242. package/src/lib/sveltekit/admin-dispatch.ts +10 -4
  243. package/src/lib/sveltekit/auth-routes.ts +3 -0
  244. package/src/lib/sveltekit/cairn-admin.ts +37 -15
  245. package/src/lib/sveltekit/content-routes.ts +492 -197
  246. package/src/lib/sveltekit/editors-routes.ts +3 -0
  247. package/src/lib/sveltekit/guard.ts +4 -2
  248. package/src/lib/sveltekit/https-required-page.ts +1 -1
  249. package/src/lib/sveltekit/index.ts +3 -0
  250. package/src/lib/sveltekit/media-route.ts +13 -8
  251. package/src/lib/sveltekit/nav-routes.ts +7 -2
  252. package/src/lib/sveltekit/types.ts +4 -2
  253. package/src/lib/vite/index.ts +60 -30
  254. package/src/lib/vite/resolve-root.ts +8 -4
@@ -28,6 +28,9 @@ function slotByName(def, name) {
28
28
  function nestedSlots(def) {
29
29
  return (def.slots ?? []).filter((s) => s.name !== 'title' && s.name !== 'body');
30
30
  }
31
+ /**
32
+ *
33
+ */
31
34
  export function serializeComponent(def, values) {
32
35
  const fence = COLON.repeat(nestedSlots(def).length > 0 ? 4 : 3);
33
36
  const title = slotByName(def, 'title') ? values.slots.title ?? '' : '';
@@ -109,18 +112,23 @@ function valuesFromRoot(root, def) {
109
112
  function rawKeysFromRoot(root) {
110
113
  return Object.keys(root?.attributes ?? {});
111
114
  }
112
- /** Parse a serialized component directive back into guided-form values, the inverse of
115
+ /**
116
+ * Parse a serialized component directive back into guided-form values, the inverse of
113
117
  * {@link serializeComponent}. The grammar is reversible, so the editor can round-trip a
114
- * saved directive through the form. */
118
+ * saved directive through the form.
119
+ */
115
120
  export async function parseComponent(markdown, def) {
116
121
  return valuesFromRoot(findComponentRoot(markdown, def), def);
117
122
  }
118
- /** The raw attribute keys present on the component's opening directive, read from the parsed tree
119
- * (quote-aware, unlike a regex over the source). Used by validation to flag unknown keys. */
123
+ /**
124
+ * The raw attribute keys present on the component's opening directive, read from the parsed tree
125
+ * (quote-aware, unlike a regex over the source). Used by validation to flag unknown keys.
126
+ */
120
127
  export function parseRawAttributeKeys(markdown, def) {
121
128
  return rawKeysFromRoot(findComponentRoot(markdown, def));
122
129
  }
123
- /** Decide whether guided edit of this placed block is provably lossless. A block a person typed by
130
+ /**
131
+ * Decide whether guided edit of this placed block is provably lossless. A block a person typed by
124
132
  * hand can carry more than the schema models (an attribute the def does not list, a child container
125
133
  * the def does not declare, slot content the form cannot represent stably), and parsing such a block
126
134
  * into the form then re-serializing would silently drop it. The edit affordance is offered only when
@@ -130,7 +138,8 @@ export function parseRawAttributeKeys(markdown, def) {
130
138
  * 2. `unknown-attribute`: the block carries an attribute key the def does not declare.
131
139
  * 3. `undeclared-child`: the root has a direct child container directive that is not a declared
132
140
  * nested slot. Such a child would otherwise fold into the body slot and move on re-serialize.
133
- * 4. `not-idempotent`: `parse -> serialize -> parse` does not recover the same values. */
141
+ * 4. `not-idempotent`: `parse -> serialize -> parse` does not recover the same values.
142
+ */
134
143
  export async function componentRoundTripSafety(markdown, def) {
135
144
  const root = findComponentRoot(markdown, def);
136
145
  if (!root)
@@ -154,9 +163,11 @@ export async function componentRoundTripSafety(markdown, def) {
154
163
  return { safe: false, reason: 'not-idempotent' };
155
164
  return { safe: true };
156
165
  }
157
- /** Parse the component once and derive both the guided-form values and the raw attribute keys.
166
+ /**
167
+ * Parse the component once and derive both the guided-form values and the raw attribute keys.
158
168
  * Validation needs both, so this seam spares it the double parse that calling
159
- * {@link parseComponent} and {@link parseRawAttributeKeys} separately would cost. */
169
+ * {@link parseComponent} and {@link parseRawAttributeKeys} separately would cost.
170
+ */
160
171
  export async function parseComponentWithRawKeys(markdown, def) {
161
172
  const root = findComponentRoot(markdown, def);
162
173
  return { values: valuesFromRoot(root, def), rawKeys: rawKeysFromRoot(root) };
@@ -1,6 +1,8 @@
1
1
  import type { ComponentDef, ComponentValues } from './registry.js';
2
- /** The outcome of preparing a guided-form component for insertion: the markdown to insert, or the
3
- * field-keyed errors to show on the form. */
2
+ /**
3
+ * The outcome of preparing a guided-form component for insertion: the markdown to insert, or the
4
+ * field-keyed errors to show on the form.
5
+ */
4
6
  export type ComponentInsert = {
5
7
  ok: true;
6
8
  markdown: string;
@@ -8,6 +10,8 @@ export type ComponentInsert = {
8
10
  ok: false;
9
11
  errors: Record<string, string>;
10
12
  };
11
- /** Serialize a component's form values, then validate the result against its schema. Returns the
12
- * markdown to insert at the cursor, or the field errors keyed by attribute key or slot name. */
13
+ /**
14
+ * Serialize a component's form values, then validate the result against its schema. Returns the
15
+ * markdown to insert at the cursor, or the field errors keyed by attribute key or slot name.
16
+ */
13
17
  export declare function buildComponentInsert(def: ComponentDef, values: ComponentValues): Promise<ComponentInsert>;
@@ -1,7 +1,9 @@
1
1
  import { serializeComponent } from './component-grammar.js';
2
2
  import { validateComponent } from './component-validate.js';
3
- /** Serialize a component's form values, then validate the result against its schema. Returns the
4
- * markdown to insert at the cursor, or the field errors keyed by attribute key or slot name. */
3
+ /**
4
+ * Serialize a component's form values, then validate the result against its schema. Returns the
5
+ * markdown to insert at the cursor, or the field errors keyed by attribute key or slot name.
6
+ */
5
7
  export async function buildComponentInsert(def, values) {
6
8
  const markdown = serializeComponent(def, values);
7
9
  const verdict = await validateComponent(markdown, def);
@@ -5,6 +5,8 @@ export interface ReferenceOptions {
5
5
  /** The one-line blockquote summary under the title. */
6
6
  summary: string;
7
7
  }
8
- /** Build a self-contained markdown reference (the llms-full.txt shape) for a component registry, for
9
- * authors and for pointing an LLM at one curated file. */
8
+ /**
9
+ * Build a self-contained markdown reference (the llms-full.txt shape) for a component registry, for
10
+ * authors and for pointing an LLM at one curated file.
11
+ */
10
12
  export declare function generateComponentReference(registry: ComponentRegistry, opts: ReferenceOptions): string;
@@ -1,7 +1,9 @@
1
1
  import { serializeComponent } from './component-grammar.js';
2
2
  import { emptyValues } from './registry.js';
3
- /** Build a self-contained markdown reference (the llms-full.txt shape) for a component registry, for
4
- * authors and for pointing an LLM at one curated file. */
3
+ /**
4
+ * Build a self-contained markdown reference (the llms-full.txt shape) for a component registry, for
5
+ * authors and for pointing an LLM at one curated file.
6
+ */
5
7
  export function generateComponentReference(registry, opts) {
6
8
  const sections = registry.defs.map((def) => componentSection(def));
7
9
  return `# ${opts.title}\n\n> ${opts.summary}\n\n${sections.join('\n\n')}\n`;
@@ -6,4 +6,7 @@ export type ComponentValidation = {
6
6
  ok: false;
7
7
  errors: Record<string, string>;
8
8
  };
9
+ /**
10
+ *
11
+ */
9
12
  export declare function validateComponent(markdown: string, def: ComponentDef): Promise<ComponentValidation>;
@@ -1,4 +1,7 @@
1
1
  import { parseComponentWithRawKeys } from './component-grammar.js';
2
+ /**
3
+ *
4
+ */
2
5
  export async function validateComponent(markdown, def) {
3
6
  const { values, rawKeys } = await parseComponentWithRawKeys(markdown, def);
4
7
  const errors = {};
@@ -1,8 +1,10 @@
1
1
  import type { Element } from 'hast';
2
2
  /** A glyph name to SVG path-data map (the site owns the icon set). */
3
3
  export type IconSet = Record<string, string>;
4
- /** Inline SVG glyph as a real hast node: class ec-glyph, 256 viewBox, currentColor fill.
4
+ /**
5
+ * Inline SVG glyph as a real hast node: class ec-glyph, 256 viewBox, currentColor fill.
5
6
  * An unknown icon name yields the bare svg shell with no path child, so it never serializes
6
7
  * a stray empty (or undefined) path. Callers always wrap the returned element, so the shell
7
- * keeps them safe. */
8
+ * keeps them safe.
9
+ */
8
10
  export declare function glyph(name: string, icons: IconSet): Element;
@@ -1,8 +1,10 @@
1
1
  import { s } from 'hastscript';
2
- /** Inline SVG glyph as a real hast node: class ec-glyph, 256 viewBox, currentColor fill.
2
+ /**
3
+ * Inline SVG glyph as a real hast node: class ec-glyph, 256 viewBox, currentColor fill.
3
4
  * An unknown icon name yields the bare svg shell with no path child, so it never serializes
4
5
  * a stray empty (or undefined) path. Callers always wrap the returned element, so the shell
5
- * keeps them safe. */
6
+ * keeps them safe.
7
+ */
6
8
  export function glyph(name, icons) {
7
9
  const d = icons[name];
8
10
  return s('svg', { className: ['ec-glyph'], viewBox: '0 0 256 256', fill: 'currentColor', ariaHidden: 'true' }, d == null ? [] : [s('path', { d })]);
@@ -4,27 +4,37 @@ import { type MediaResolve } from './resolve-media.js';
4
4
  import { type ComponentRegistry } from './registry.js';
5
5
  import type { LinkResolve } from '../content/links.js';
6
6
  export interface RendererOptions {
7
- /** Stamp a `data-rise` ordinal (0, 1, 2, …) on each top-level component so a site's
7
+ /**
8
+ * Stamp a `data-rise` ordinal (0, 1, 2, …) on each top-level component so a site's
8
9
  * CSS can drive an entrance-cascade delay off it. Omit for no stagger. The ordinal
9
- * is inert, so a consumer's sanitize floor can keep `data-rise` and drop `style`. */
10
+ * is inert, so a consumer's sanitize floor can keep `data-rise` and drop `style`.
11
+ */
10
12
  stagger?: boolean;
11
- /** Extend the sanitize allowlist. Receives cairn's default schema (defaultSchema plus the
13
+ /**
14
+ * Extend the sanitize allowlist. Receives cairn's default schema (defaultSchema plus the
12
15
  * directive markers and the common benign tags) and returns the schema to use. Add to the
13
16
  * allowlist for the benign HTML a site's content needs; start from the argument so the
14
- * dangerous strip is preserved. */
17
+ * dangerous strip is preserved.
18
+ */
15
19
  sanitizeSchema?: (defaults: Schema) => Schema;
16
- /** Developer-only escape hatch: disable the sanitize floor entirely. This reintroduces the XSS
20
+ /**
21
+ * Developer-only escape hatch: disable the sanitize floor entirely. This reintroduces the XSS
17
22
  * vector the floor closes, so it is only for a site whose content is fully developer-controlled.
18
- * It is a code-level adapter decision, never an editor-facing setting. */
23
+ * It is a code-level adapter decision, never an editor-facing setting.
24
+ */
19
25
  unsafeDisableSanitize?: boolean;
20
- /** The `rel` value forced on every `target="_blank"` anchor, applied last so it also covers
26
+ /**
27
+ * The `rel` value forced on every `target="_blank"` anchor, applied last so it also covers
21
28
  * component-built anchors. Defaults to `'noopener noreferrer'`. Set a different string to change
22
- * it, or `false` to disable the injection (a site that owns its own anchor hardening). */
29
+ * it, or `false` to disable the injection (a site that owns its own anchor hardening).
30
+ */
23
31
  anchorRel?: string | false;
24
32
  }
25
- /** Compose a site's render pipeline from its component registry: directive syntax to
33
+ /**
34
+ * Compose a site's render pipeline from its component registry: directive syntax to
26
35
  * stamped markers to registry-built hast. Returns `renderMarkdown` plus the remark/
27
- * rehype plugin arrays (so the admin editor preview can reuse the exact same set). */
36
+ * rehype plugin arrays (so the admin editor preview can reuse the exact same set).
37
+ */
28
38
  export declare function createRenderer(registry?: ComponentRegistry, options?: RendererOptions): {
29
39
  remarkPlugins: PluggableList;
30
40
  rehypePlugins: PluggableList;
@@ -15,9 +15,11 @@ import { remarkResolveCairnLinks, CAIRN_RESOLVE } from './resolve-links.js';
15
15
  import { remarkResolveMedia, MEDIA_RESOLVE } from './resolve-media.js';
16
16
  import { rehypeDispatch } from './rehype-dispatch.js';
17
17
  import { defineRegistry } from './registry.js';
18
- /** Compose a site's render pipeline from its component registry: directive syntax to
18
+ /**
19
+ * Compose a site's render pipeline from its component registry: directive syntax to
19
20
  * stamped markers to registry-built hast. Returns `renderMarkdown` plus the remark/
20
- * rehype plugin arrays (so the admin editor preview can reuse the exact same set). */
21
+ * rehype plugin arrays (so the admin editor preview can reuse the exact same set).
22
+ */
21
23
  export function createRenderer(registry = defineRegistry({ components: [] }), options = {}) {
22
24
  const remarkPlugins = [
23
25
  remarkDirective,
@@ -20,14 +20,18 @@ export interface AttributeField {
20
20
  source: string;
21
21
  message: string;
22
22
  };
23
- /** A pure, browser-safe cross-field validator. Returns an error string, or null when valid.
23
+ /**
24
+ * A pure, browser-safe cross-field validator. Returns an error string, or null when valid.
24
25
  * Receives the field's value and the full {@link ComponentValues} so a rule can read sibling
25
- * fields. The picker wraps the call in try/catch so an author's throw never crashes the form. */
26
+ * fields. The picker wraps the call in try/catch so an author's throw never crashes the form.
27
+ */
26
28
  validate?: (value: string | boolean, all: ComponentValues) => string | null;
27
29
  }
28
30
  export type SlotKind = 'markdown' | 'inline' | 'repeatable';
29
- /** One named content region of a component. The slots named `title` and `body` are special: `title`
30
- * serializes to the directive `[label]` and `body` to the unmarked content (see the canonical grammar). */
31
+ /**
32
+ * One named content region of a component. The slots named `title` and `body` are special: `title`
33
+ * serializes to the directive `[label]` and `body` to the unmarked content (see the canonical grammar).
34
+ */
31
35
  export interface SlotDef {
32
36
  name: string;
33
37
  label: string;
@@ -36,14 +40,18 @@ export interface SlotDef {
36
40
  help?: string;
37
41
  /** For `kind: 'repeatable'`: the fields composing each list item (v1 uses the first field). */
38
42
  itemFields?: AttributeField[];
39
- /** For `kind: 'repeatable'`: derives a row's label from its item values and zero-based index.
40
- * When it returns nothing, the picker falls back to `${label} ${index + 1}`. */
43
+ /**
44
+ * For `kind: 'repeatable'`: derives a row's label from its item values and zero-based index.
45
+ * When it returns nothing, the picker falls back to `${label} ${index + 1}`.
46
+ */
41
47
  itemLabel?: (item: Record<string, string | boolean>, index: number) => string;
42
48
  }
43
- /** The structured input a component's `build` receives. The engine stamps the component's
49
+ /**
50
+ * The structured input a component's `build` receives. The engine stamps the component's
44
51
  * attributes and partitions its slots from the rendered hast, so `build` arranges hast and
45
52
  * never walks the tree. `slot(name)` returns a slot's rendered children (title, body, or any
46
- * named slot); `items(name)` returns a repeatable slot's items, one child list per item. */
53
+ * named slot); `items(name)` returns a repeatable slot's items, one child list per item.
54
+ */
47
55
  export interface ComponentContext {
48
56
  /** Declared attribute values, keyed by attribute key. Booleans are real booleans. */
49
57
  attributes: Record<string, string | boolean>;
@@ -64,9 +72,11 @@ export interface ComponentDef {
64
72
  description: string;
65
73
  /** Markdown scaffold inserted at the cursor by the editor palette. */
66
74
  insertTemplate?: string;
67
- /** Build the final hast element from the component context (attributes plus partitioned
75
+ /**
76
+ * Build the final hast element from the component context (attributes plus partitioned
68
77
  * slots). The engine stamps the entrance-stagger ordinal (`data-rise`) on the top-level
69
- * result, so a build fn stays free of any motion concern. */
78
+ * result, so a build fn stays free of any motion concern.
79
+ */
70
80
  build: (ctx: ComponentContext) => Element;
71
81
  /** Optional role-to-default-icon, e.g. `{ caution: 'warning' }`. */
72
82
  defaultIconByRole?: Record<string, string>;
@@ -82,8 +92,10 @@ export interface ComponentDef {
82
92
  group?: string;
83
93
  /** Omit from the top-level picker (for a nested or round-trip-only component). */
84
94
  hidden?: boolean;
85
- /** A structured sample the picker seeds the form with and renders through the same path a real
86
- * insert takes. Declaring `preview` is what opts the component into the two-pane configure layout. */
95
+ /**
96
+ * A structured sample the picker seeds the form with and renders through the same path a real
97
+ * insert takes. Declaring `preview` is what opts the component into the two-pane configure layout.
98
+ */
87
99
  preview?: {
88
100
  attributes?: Record<string, string | boolean>;
89
101
  slots?: Record<string, string | string[]>;
@@ -97,9 +109,11 @@ export interface ComponentRegistry {
97
109
  /** The component's first `type:'icon'` attribute, or undefined when it declares none. */
98
110
  iconField(name: string): AttributeField | undefined;
99
111
  }
100
- /** The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
112
+ /**
113
+ * The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
101
114
  * becomes `dataAttrTone`. The directive stamp writes it and the rehype dispatch reads it, so both
102
- * sides derive the name from this one helper rather than spelling the capitalize twice. */
115
+ * sides derive the name from this one helper rather than spelling the capitalize twice.
116
+ */
103
117
  export declare function dataAttrProp(key: string): string;
104
118
  /**
105
119
  * Build a registry from a site's component definitions. The single source the render
@@ -108,16 +122,22 @@ export declare function dataAttrProp(key: string): string;
108
122
  export declare function defineRegistry({ components }: {
109
123
  components: ComponentDef[];
110
124
  }): ComponentRegistry;
111
- /** Guided-form values for one component: attribute values keyed by attribute key, slot values keyed
112
- * by slot name (a string, or a string list for a repeatable slot). */
125
+ /**
126
+ * Guided-form values for one component: attribute values keyed by attribute key, slot values keyed
127
+ * by slot name (a string, or a string list for a repeatable slot).
128
+ */
113
129
  export interface ComponentValues {
114
130
  attributes: Record<string, string | boolean>;
115
131
  slots: Record<string, string | string[]>;
116
132
  }
117
- /** Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
118
- * and empty slot values ([] for repeatable, '' otherwise). */
133
+ /**
134
+ * Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
135
+ * and empty slot values ([] for repeatable, '' otherwise).
136
+ */
119
137
  export declare function emptyValues(def: ComponentDef): ComponentValues;
120
- /** Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
138
+ /**
139
+ * Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
121
140
  * with `def.preview.attributes` and `def.preview.slots` overlaid (a shallow merge per side). When
122
- * the def declares no `preview`, returns exactly the {@link emptyValues} output. */
141
+ * the def declares no `preview`, returns exactly the {@link emptyValues} output.
142
+ */
123
143
  export declare function previewValues(def: ComponentDef): ComponentValues;
@@ -1,12 +1,16 @@
1
- /** The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
1
+ /**
2
+ * The hast property name carrying one declared attribute from stamp to dispatch, e.g. `tone`
2
3
  * becomes `dataAttrTone`. The directive stamp writes it and the rehype dispatch reads it, so both
3
- * sides derive the name from this one helper rather than spelling the capitalize twice. */
4
+ * sides derive the name from this one helper rather than spelling the capitalize twice.
5
+ */
4
6
  export function dataAttrProp(key) {
5
7
  return `dataAttr${key.charAt(0).toUpperCase()}${key.slice(1)}`;
6
8
  }
7
- /** A component's first `type:'icon'` attribute, or undefined when it declares none. Both the
9
+ /**
10
+ * A component's first `type:'icon'` attribute, or undefined when it declares none. Both the
8
11
  * construction-time guard and the registry's `iconField` derive the icon field from this one
9
- * predicate rather than spelling the `type === 'icon'` find twice. */
12
+ * predicate rather than spelling the `type === 'icon'` find twice.
13
+ */
10
14
  function findIconField(def) {
11
15
  return def.attributes?.find((field) => field.type === 'icon');
12
16
  }
@@ -35,8 +39,10 @@ export function defineRegistry({ components }) {
35
39
  },
36
40
  };
37
41
  }
38
- /** Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
39
- * and empty slot values ([] for repeatable, '' otherwise). */
42
+ /**
43
+ * Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
44
+ * and empty slot values ([] for repeatable, '' otherwise).
45
+ */
40
46
  export function emptyValues(def) {
41
47
  const attributes = {};
42
48
  for (const field of def.attributes ?? []) {
@@ -48,9 +54,11 @@ export function emptyValues(def) {
48
54
  }
49
55
  return { attributes, slots };
50
56
  }
51
- /** Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
57
+ /**
58
+ * Seed {@link ComponentValues} from a component's `preview` sample: the {@link emptyValues} base
52
59
  * with `def.preview.attributes` and `def.preview.slots` overlaid (a shallow merge per side). When
53
- * the def declares no `preview`, returns exactly the {@link emptyValues} output. */
60
+ * the def declares no `preview`, returns exactly the {@link emptyValues} output.
61
+ */
54
62
  export function previewValues(def) {
55
63
  const base = emptyValues(def);
56
64
  if (!def.preview)
@@ -1,9 +1,17 @@
1
1
  import type { Root, Element, ElementContent } from 'hast';
2
2
  import { type ComponentContext, type ComponentRegistry } from './registry.js';
3
+ /**
4
+ *
5
+ */
3
6
  export declare function isElement(node: ElementContent | undefined): node is Element;
4
- /** Read a declared string attribute off the component context, returning undefined for a boolean or
5
- * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats. */
7
+ /**
8
+ * Read a declared string attribute off the component context, returning undefined for a boolean or
9
+ * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats.
10
+ */
6
11
  export declare function strAttr(ctx: ComponentContext, key: string): string | undefined;
12
+ /**
13
+ *
14
+ */
7
15
  export declare function strProp(node: Element, name: string): string | undefined;
8
16
  /** Wrap a pre-built glyph in an ec-icon span; secondary role adds the modifier. */
9
17
  export declare function iconSpan(glyphEl: Element, role?: string): Element;
@@ -11,18 +19,24 @@ export declare function iconSpan(glyphEl: Element, role?: string): Element;
11
19
  export type MakeIcon = (name: string, role?: string) => Element;
12
20
  /** Section wrapper: `<section class=…><div class="card-body">…</div></section>`. */
13
21
  export declare function cardShell(classes: string[], body: ElementContent[]): Element;
14
- /** Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
22
+ /**
23
+ * Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
15
24
  * Pass the title's inline children, an optional pre-built icon element, and an optional heading
16
25
  * level (default 2). This factors the icon-plus-heading head that a titled component build would
17
- * otherwise rebuild by hand (the shape the removed `splitHead` produced). */
26
+ * otherwise rebuild by hand (the shape the removed `splitHead` produced).
27
+ */
18
28
  export declare function headRow(title: ElementContent[], icon?: Element, level?: number): Element;
19
- /** Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
20
- * text nodes so the bare list serializes without newlines. Returns that <ul>. */
29
+ /**
30
+ * Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
31
+ * text nodes so the bare list serializes without newlines. Returns that <ul>.
32
+ */
21
33
  export declare function markFirstList(children: ElementContent[]): Element | undefined;
22
- /** Rehype transformer: dispatch each stamped element through its registry `build`
34
+ /**
35
+ * Rehype transformer: dispatch each stamped element through its registry `build`
23
36
  * fn. When `stagger` is on, each top-level primitive gets a `data-rise` attribute
24
37
  * carrying its document-order index (0, 1, 2, …); the site's CSS maps that ordinal
25
38
  * to an entrance delay. The index is inert, so a consumer's sanitize floor can keep
26
39
  * `data-rise` while dropping `style`. Nested primitives never get it. Non-primitive
27
- * content (lede, intro paragraphs, the page-toc nav) passes through untouched. */
40
+ * content (lede, intro paragraphs, the page-toc nav) passes through untouched.
41
+ */
28
42
  export declare function rehypeDispatch(registry: ComponentRegistry, stagger?: boolean): (tree: Root) => void;
@@ -1,10 +1,15 @@
1
1
  import { h } from 'hastscript';
2
2
  import { dataAttrProp } from './registry.js';
3
+ /**
4
+ *
5
+ */
3
6
  export function isElement(node) {
4
7
  return !!node && node.type === 'element';
5
8
  }
6
- /** Read a declared string attribute off the component context, returning undefined for a boolean or
7
- * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats. */
9
+ /**
10
+ * Read a declared string attribute off the component context, returning undefined for a boolean or
11
+ * absent value. Replaces the `typeof ctx.attributes[key] === 'string'` narrowing a build repeats.
12
+ */
8
13
  export function strAttr(ctx, key) {
9
14
  const value = ctx.attributes[key];
10
15
  return typeof value === 'string' ? value : undefined;
@@ -12,6 +17,9 @@ export function strAttr(ctx, key) {
12
17
  // hast Properties values are PropertyValue (string | number | boolean | array | null).
13
18
  // Directive markers (dataPrimitive/dataRole/dataAttr<Key>) are always stamped as strings;
14
19
  // this reads them back with that guarantee instead of casting at each call site.
20
+ /**
21
+ *
22
+ */
15
23
  export function strProp(node, name) {
16
24
  const value = node.properties?.[name];
17
25
  return typeof value === 'string' ? value : undefined;
@@ -25,10 +33,12 @@ export function iconSpan(glyphEl, role) {
25
33
  export function cardShell(classes, body) {
26
34
  return h('section', { className: classes }, [h('div', { className: ['card-body'] }, body)]);
27
35
  }
28
- /** Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
36
+ /**
37
+ * Card head row: `<div class="ec-head">[icon]<hN class="card-title">{title}</hN></div>`.
29
38
  * Pass the title's inline children, an optional pre-built icon element, and an optional heading
30
39
  * level (default 2). This factors the icon-plus-heading head that a titled component build would
31
- * otherwise rebuild by hand (the shape the removed `splitHead` produced). */
40
+ * otherwise rebuild by hand (the shape the removed `splitHead` produced).
41
+ */
32
42
  export function headRow(title, icon, level = 2) {
33
43
  const children = [];
34
44
  if (icon)
@@ -36,8 +46,10 @@ export function headRow(title, icon, level = 2) {
36
46
  children.push(h(`h${level}`, { className: ['card-title'] }, title));
37
47
  return h('div', { className: ['ec-head'] }, children);
38
48
  }
39
- /** Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
40
- * text nodes so the bare list serializes without newlines. Returns that <ul>. */
49
+ /**
50
+ * Tag the first <ul> among children with `ec-grid` and strip its whitespace-only
51
+ * text nodes so the bare list serializes without newlines. Returns that <ul>.
52
+ */
41
53
  export function markFirstList(children) {
42
54
  const ul = children.find((c) => isElement(c) && c.tagName === 'ul');
43
55
  if (ul) {
@@ -133,12 +145,14 @@ function transformNode(node, registry) {
133
145
  };
134
146
  return def.build(ctx);
135
147
  }
136
- /** Rehype transformer: dispatch each stamped element through its registry `build`
148
+ /**
149
+ * Rehype transformer: dispatch each stamped element through its registry `build`
137
150
  * fn. When `stagger` is on, each top-level primitive gets a `data-rise` attribute
138
151
  * carrying its document-order index (0, 1, 2, …); the site's CSS maps that ordinal
139
152
  * to an entrance delay. The index is inert, so a consumer's sanitize floor can keep
140
153
  * `data-rise` while dropping `style`. Nested primitives never get it. Non-primitive
141
- * content (lede, intro paragraphs, the page-toc nav) passes through untouched. */
154
+ * content (lede, intro paragraphs, the page-toc nav) passes through untouched.
155
+ */
142
156
  export function rehypeDispatch(registry, stagger) {
143
157
  return (tree) => {
144
158
  let idx = 0;
@@ -1,3 +1,6 @@
1
1
  import type { Root } from 'mdast';
2
2
  import { type ComponentRegistry } from './registry.js';
3
+ /**
4
+ *
5
+ */
3
6
  export declare function remarkDirectiveStamp(registry: ComponentRegistry): (tree: Root) => void;
@@ -51,6 +51,9 @@ function restoreLiteral(node) {
51
51
  // component name, icon, and role. No structure is built here; the rehype
52
52
  // dispatcher rewrites the marked elements once their children are hast.
53
53
  // Text and leaf directives are restored to literal text (accidental prose colons).
54
+ /**
55
+ *
56
+ */
54
57
  export function remarkDirectiveStamp(registry) {
55
58
  const known = new Set(registry.names);
56
59
  return (tree) => {
@@ -1,4 +1,6 @@
1
1
  import type { Root } from 'mdast';
2
- /** Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
3
- * is left to remarkDirectiveStamp, which already skips unregistered names. */
2
+ /**
3
+ * Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
4
+ * is left to remarkDirectiveStamp, which already skips unregistered names.
5
+ */
4
6
  export declare function remarkFigure(): (tree: Root) => void;
@@ -42,8 +42,10 @@ function trimLeadingNewline(children) {
42
42
  }
43
43
  return children;
44
44
  }
45
- /** Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
46
- * is left to remarkDirectiveStamp, which already skips unregistered names. */
45
+ /**
46
+ * Rewrite the reserved `figure` container directive into a placed <figure>. Every other directive
47
+ * is left to remarkDirectiveStamp, which already skips unregistered names.
48
+ */
47
49
  export function remarkFigure() {
48
50
  return (tree) => {
49
51
  visit(tree, 'containerDirective', (node) => {
@@ -1,7 +1,9 @@
1
1
  import type { VFile } from 'vfile';
2
2
  /** The VFile data key the renderer sets the per-call resolver under. */
3
3
  export declare const CAIRN_RESOLVE = "cairnResolve";
4
- /** Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
4
+ /**
5
+ * Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
5
6
  * pass through. A missing target is marked with the cairn-broken-link class (the resolver returns
6
- * undefined) or, when the resolver throws, the error propagates and fails the build. */
7
+ * undefined) or, when the resolver throws, the error propagates and fails the build.
8
+ */
7
9
  export declare function remarkResolveCairnLinks(): (tree: unknown, file: VFile) => void;
@@ -7,9 +7,11 @@ import { visit } from 'unist-util-visit';
7
7
  import { parseCairnToken } from '../content/links.js';
8
8
  /** The VFile data key the renderer sets the per-call resolver under. */
9
9
  export const CAIRN_RESOLVE = 'cairnResolve';
10
- /** Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
10
+ /**
11
+ * Resolve cairn: link nodes against the VFile's resolver. A non-cairn href and a malformed token
11
12
  * pass through. A missing target is marked with the cairn-broken-link class (the resolver returns
12
- * undefined) or, when the resolver throws, the error propagates and fails the build. */
13
+ * undefined) or, when the resolver throws, the error propagates and fails the build.
14
+ */
13
15
  export function remarkResolveCairnLinks() {
14
16
  return (tree, file) => {
15
17
  const resolve = file.data[CAIRN_RESOLVE];