@caretcms/core 0.1.1 → 0.2.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 (222) hide show
  1. package/README.md +101 -18
  2. package/dist/browser-runtime.d.ts +16 -0
  3. package/dist/browser-runtime.d.ts.map +1 -1
  4. package/dist/browser-runtime.js +8 -3
  5. package/dist/browser-runtime.js.map +1 -1
  6. package/dist/contracts.d.ts +1 -0
  7. package/dist/contracts.d.ts.map +1 -1
  8. package/dist/contracts.js +1 -0
  9. package/dist/contracts.js.map +1 -1
  10. package/dist/index.d.ts +34 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +239 -13
  13. package/dist/index.js.map +1 -1
  14. package/dist/loader.d.ts +17 -6
  15. package/dist/loader.d.ts.map +1 -1
  16. package/dist/loader.js +33 -14
  17. package/dist/loader.js.map +1 -1
  18. package/dist/markdown/block-context.d.ts +21 -0
  19. package/dist/markdown/block-context.d.ts.map +1 -0
  20. package/dist/markdown/block-context.js +27 -0
  21. package/dist/markdown/block-context.js.map +1 -0
  22. package/dist/markdown/canonical-body.d.ts +30 -0
  23. package/dist/markdown/canonical-body.d.ts.map +1 -0
  24. package/dist/markdown/canonical-body.js +54 -0
  25. package/dist/markdown/canonical-body.js.map +1 -0
  26. package/dist/markdown/contracts.d.ts +66 -0
  27. package/dist/markdown/contracts.d.ts.map +1 -0
  28. package/dist/markdown/contracts.js +102 -0
  29. package/dist/markdown/contracts.js.map +1 -0
  30. package/dist/markdown/html-to-snodes.d.ts +26 -0
  31. package/dist/markdown/html-to-snodes.d.ts.map +1 -0
  32. package/dist/markdown/html-to-snodes.js +118 -0
  33. package/dist/markdown/html-to-snodes.js.map +1 -0
  34. package/dist/markdown/remark.d.ts +35 -0
  35. package/dist/markdown/remark.d.ts.map +1 -0
  36. package/dist/markdown/remark.js +66 -0
  37. package/dist/markdown/remark.js.map +1 -0
  38. package/dist/markdown/satteri.d.ts +19 -0
  39. package/dist/markdown/satteri.d.ts.map +1 -0
  40. package/dist/markdown/satteri.js +120 -0
  41. package/dist/markdown/satteri.js.map +1 -0
  42. package/dist/markdown/serialize.d.ts +60 -0
  43. package/dist/markdown/serialize.d.ts.map +1 -0
  44. package/dist/markdown/serialize.js +264 -0
  45. package/dist/markdown/serialize.js.map +1 -0
  46. package/dist/markdown/splice.d.ts +32 -0
  47. package/dist/markdown/splice.d.ts.map +1 -0
  48. package/dist/markdown/splice.js +44 -0
  49. package/dist/markdown/splice.js.map +1 -0
  50. package/dist/markdown/stamp.d.ts +68 -0
  51. package/dist/markdown/stamp.d.ts.map +1 -0
  52. package/dist/markdown/stamp.js +131 -0
  53. package/dist/markdown/stamp.js.map +1 -0
  54. package/dist/runtime/auth/rate-limiter.d.ts.map +1 -1
  55. package/dist/runtime/auth/rate-limiter.js +5 -0
  56. package/dist/runtime/auth/rate-limiter.js.map +1 -1
  57. package/dist/runtime/auth/session.d.ts +2 -3
  58. package/dist/runtime/auth/session.d.ts.map +1 -1
  59. package/dist/runtime/auth/session.js +52 -21
  60. package/dist/runtime/auth/session.js.map +1 -1
  61. package/dist/runtime/content.d.ts.map +1 -1
  62. package/dist/runtime/content.js +4 -2
  63. package/dist/runtime/content.js.map +1 -1
  64. package/dist/runtime/middleware.d.ts.map +1 -1
  65. package/dist/runtime/middleware.js +21 -4
  66. package/dist/runtime/middleware.js.map +1 -1
  67. package/dist/runtime/mutations/contracts.d.ts +25 -1
  68. package/dist/runtime/mutations/contracts.d.ts.map +1 -1
  69. package/dist/runtime/mutations/contracts.js +67 -0
  70. package/dist/runtime/mutations/contracts.js.map +1 -1
  71. package/dist/runtime/mutations/engine.d.ts +6 -1
  72. package/dist/runtime/mutations/engine.d.ts.map +1 -1
  73. package/dist/runtime/mutations/engine.js +151 -42
  74. package/dist/runtime/mutations/engine.js.map +1 -1
  75. package/dist/runtime/providers.d.ts +9 -0
  76. package/dist/runtime/providers.d.ts.map +1 -1
  77. package/dist/runtime/providers.js +6 -0
  78. package/dist/runtime/providers.js.map +1 -1
  79. package/dist/runtime/publish.d.ts +15 -1
  80. package/dist/runtime/publish.d.ts.map +1 -1
  81. package/dist/runtime/publish.js +79 -4
  82. package/dist/runtime/publish.js.map +1 -1
  83. package/dist/runtime/rebuild-webhook.d.ts +29 -0
  84. package/dist/runtime/rebuild-webhook.d.ts.map +1 -0
  85. package/dist/runtime/rebuild-webhook.js +37 -0
  86. package/dist/runtime/rebuild-webhook.js.map +1 -0
  87. package/dist/runtime/request-context.d.ts +9 -1
  88. package/dist/runtime/request-context.d.ts.map +1 -1
  89. package/dist/runtime/request-context.js.map +1 -1
  90. package/dist/runtime/rewrite.d.ts +18 -0
  91. package/dist/runtime/rewrite.d.ts.map +1 -1
  92. package/dist/runtime/rewrite.js +118 -4
  93. package/dist/runtime/rewrite.js.map +1 -1
  94. package/dist/runtime/rich-allowlist.d.ts +3 -2
  95. package/dist/runtime/rich-allowlist.d.ts.map +1 -1
  96. package/dist/runtime/rich-allowlist.js +14 -4
  97. package/dist/runtime/rich-allowlist.js.map +1 -1
  98. package/dist/runtime/routes/_helpers.d.ts +7 -0
  99. package/dist/runtime/routes/_helpers.d.ts.map +1 -1
  100. package/dist/runtime/routes/_helpers.js +34 -1
  101. package/dist/runtime/routes/_helpers.js.map +1 -1
  102. package/dist/runtime/routes/admin-entry.d.ts +1 -0
  103. package/dist/runtime/routes/admin-entry.d.ts.map +1 -1
  104. package/dist/runtime/routes/admin-entry.js +3 -2
  105. package/dist/runtime/routes/admin-entry.js.map +1 -1
  106. package/dist/runtime/routes/admin.d.ts +1 -0
  107. package/dist/runtime/routes/admin.d.ts.map +1 -1
  108. package/dist/runtime/routes/admin.js +20 -13
  109. package/dist/runtime/routes/admin.js.map +1 -1
  110. package/dist/runtime/routes/auth-login.d.ts +1 -0
  111. package/dist/runtime/routes/auth-login.d.ts.map +1 -1
  112. package/dist/runtime/routes/auth-login.js +1 -0
  113. package/dist/runtime/routes/auth-login.js.map +1 -1
  114. package/dist/runtime/routes/auth-logout.d.ts +1 -0
  115. package/dist/runtime/routes/auth-logout.d.ts.map +1 -1
  116. package/dist/runtime/routes/auth-logout.js +1 -0
  117. package/dist/runtime/routes/auth-logout.js.map +1 -1
  118. package/dist/runtime/routes/auth-session.d.ts +1 -0
  119. package/dist/runtime/routes/auth-session.d.ts.map +1 -1
  120. package/dist/runtime/routes/auth-session.js +1 -0
  121. package/dist/runtime/routes/auth-session.js.map +1 -1
  122. package/dist/runtime/routes/collection-list.d.ts +1 -0
  123. package/dist/runtime/routes/collection-list.d.ts.map +1 -1
  124. package/dist/runtime/routes/collection-list.js +3 -2
  125. package/dist/runtime/routes/collection-list.js.map +1 -1
  126. package/dist/runtime/routes/collections-metadata.d.ts +1 -0
  127. package/dist/runtime/routes/collections-metadata.d.ts.map +1 -1
  128. package/dist/runtime/routes/collections-metadata.js +3 -2
  129. package/dist/runtime/routes/collections-metadata.js.map +1 -1
  130. package/dist/runtime/routes/draft.d.ts +5 -0
  131. package/dist/runtime/routes/draft.d.ts.map +1 -1
  132. package/dist/runtime/routes/draft.js +18 -1
  133. package/dist/runtime/routes/draft.js.map +1 -1
  134. package/dist/runtime/routes/editor-assets.d.ts +1 -0
  135. package/dist/runtime/routes/editor-assets.d.ts.map +1 -1
  136. package/dist/runtime/routes/editor-assets.js +1 -0
  137. package/dist/runtime/routes/editor-assets.js.map +1 -1
  138. package/dist/runtime/routes/entries.d.ts +1 -0
  139. package/dist/runtime/routes/entries.d.ts.map +1 -1
  140. package/dist/runtime/routes/entries.js +6 -4
  141. package/dist/runtime/routes/entries.js.map +1 -1
  142. package/dist/runtime/routes/history.d.ts +1 -0
  143. package/dist/runtime/routes/history.d.ts.map +1 -1
  144. package/dist/runtime/routes/history.js +50 -24
  145. package/dist/runtime/routes/history.js.map +1 -1
  146. package/dist/runtime/routes/mutate.d.ts +1 -0
  147. package/dist/runtime/routes/mutate.d.ts.map +1 -1
  148. package/dist/runtime/routes/mutate.js +42 -7
  149. package/dist/runtime/routes/mutate.js.map +1 -1
  150. package/dist/runtime/routes/publish.d.ts +1 -0
  151. package/dist/runtime/routes/publish.d.ts.map +1 -1
  152. package/dist/runtime/routes/publish.js +15 -3
  153. package/dist/runtime/routes/publish.js.map +1 -1
  154. package/dist/runtime/routes/schema.d.ts +1 -0
  155. package/dist/runtime/routes/schema.d.ts.map +1 -1
  156. package/dist/runtime/routes/schema.js +7 -3
  157. package/dist/runtime/routes/schema.js.map +1 -1
  158. package/dist/runtime/routes/studio-home.d.ts +1 -0
  159. package/dist/runtime/routes/studio-home.d.ts.map +1 -1
  160. package/dist/runtime/routes/studio-home.js +10 -9
  161. package/dist/runtime/routes/studio-home.js.map +1 -1
  162. package/dist/runtime/routes/theme-stylesheet.d.ts +1 -0
  163. package/dist/runtime/routes/theme-stylesheet.d.ts.map +1 -1
  164. package/dist/runtime/routes/theme-stylesheet.js +12 -1
  165. package/dist/runtime/routes/theme-stylesheet.js.map +1 -1
  166. package/dist/runtime/routes/upload.d.ts +1 -0
  167. package/dist/runtime/routes/upload.d.ts.map +1 -1
  168. package/dist/runtime/routes/upload.js +1 -0
  169. package/dist/runtime/routes/upload.js.map +1 -1
  170. package/dist/runtime/static-bake.d.ts +20 -0
  171. package/dist/runtime/static-bake.d.ts.map +1 -0
  172. package/dist/runtime/static-bake.js +58 -0
  173. package/dist/runtime/static-bake.js.map +1 -0
  174. package/dist/runtime/storage/atomic-write.d.ts.map +1 -1
  175. package/dist/runtime/storage/atomic-write.js +8 -3
  176. package/dist/runtime/storage/atomic-write.js.map +1 -1
  177. package/dist/runtime/storage/frontmatter-codec.d.ts.map +1 -1
  178. package/dist/runtime/storage/frontmatter-codec.js +8 -0
  179. package/dist/runtime/storage/frontmatter-codec.js.map +1 -1
  180. package/dist/runtime/storage/markdown-adapter.d.ts +19 -0
  181. package/dist/runtime/storage/markdown-adapter.d.ts.map +1 -1
  182. package/dist/runtime/storage/markdown-adapter.js +41 -0
  183. package/dist/runtime/storage/markdown-adapter.js.map +1 -1
  184. package/dist/runtime/storage/session-overlay-adapter.d.ts +8 -0
  185. package/dist/runtime/storage/session-overlay-adapter.d.ts.map +1 -1
  186. package/dist/runtime/storage/session-overlay-adapter.js +24 -2
  187. package/dist/runtime/storage/session-overlay-adapter.js.map +1 -1
  188. package/dist/runtime/utils.d.ts +10 -0
  189. package/dist/runtime/utils.d.ts.map +1 -1
  190. package/dist/runtime/utils.js +16 -0
  191. package/dist/runtime/utils.js.map +1 -1
  192. package/dist/runtime/views/studio-layout.d.ts.map +1 -1
  193. package/dist/runtime/views/studio-layout.js +11 -10
  194. package/dist/runtime/views/studio-layout.js.map +1 -1
  195. package/dist/types.d.ts +40 -0
  196. package/dist/types.d.ts.map +1 -1
  197. package/package.json +2 -2
  198. package/static/cms/admin-entry.js +36 -2
  199. package/static/cms/dev-toolbar/app.js +3 -1
  200. package/static/cms/editor/config.js +10 -0
  201. package/static/cms/editor/guards.js +1 -1
  202. package/static/cms/editor/helpers.js +5 -1
  203. package/static/cms/editor/highlight.js +4 -6
  204. package/static/cms/editor/image-edit.js +41 -11
  205. package/static/cms/editor/image.css +7 -1
  206. package/static/cms/editor/md-block-edit.js +176 -0
  207. package/static/cms/editor/md-serialize.js +301 -0
  208. package/static/cms/editor/panel.css +69 -25
  209. package/static/cms/editor/panel.js +39 -0
  210. package/static/cms/editor/rich-toolbar.js +4 -3
  211. package/static/cms/editor/sanitize.js +10 -5
  212. package/static/cms/editor/sync.js +1 -1
  213. package/static/cms/editor/text-edit.js +68 -17
  214. package/static/cms/editor/text-link-interactions.js +4 -4
  215. package/static/cms/editor/toast.css +114 -2
  216. package/static/cms/editor/toast.js +121 -22
  217. package/static/cms/editor/tokens-and-text.css +64 -3
  218. package/static/cms/editor/toolbar.css +76 -8
  219. package/static/cms/editor/toolbar.js +173 -64
  220. package/static/cms/editor.js +16 -3
  221. package/static/cms/studio-login.css +70 -0
  222. package/static/cms/studio.css +80 -13
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Sätteri mdast plugin that stamps `data-caret-md` bindings (Astro 7).
3
+ *
4
+ * Registered on `markdown.processor.options.mdastPlugins` by the integration
5
+ * when markdown storage is active. Position tracking is opt-in, so the plugin
6
+ * declares `options: { position: true }`. Attributes are written through the
7
+ * per-node `data.hProperties` bag, which Sätteri carries into the rendered
8
+ * HTML like remark-rehype.
9
+ *
10
+ * Type-only imports keep core free of a `satteri` runtime dependency — the
11
+ * package is present in the user's Astro build, never shipped by us.
12
+ */
13
+ import { computeStamp, planParagraph } from "./stamp.js";
14
+ // Sätteri (Rust / pulldown-cmark) reports positions as UTF-8 BYTE offsets,
15
+ // while our contracts, hashing, and the server-side splice all work in JS
16
+ // string (UTF-16 code unit) space. Convert once per document. Memoized because
17
+ // a document's blocks are visited consecutively against the same `ctx.source`.
18
+ let byteMapCache = null;
19
+ function byteToStringIndex(source, byteOffset) {
20
+ if (!byteMapCache || byteMapCache.source !== source) {
21
+ const prefix = new Uint32Array(source.length + 1);
22
+ let bytes = 0;
23
+ for (let i = 0; i < source.length;) {
24
+ const cp = source.codePointAt(i);
25
+ const units = cp > 0xffff ? 2 : 1;
26
+ prefix[i] = bytes;
27
+ if (units === 2)
28
+ prefix[i + 1] = bytes; // low surrogate: mid-char
29
+ bytes += cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4;
30
+ i += units;
31
+ }
32
+ prefix[source.length] = bytes;
33
+ byteMapCache = { source, prefix };
34
+ }
35
+ const { prefix } = byteMapCache;
36
+ // Smallest string index whose byte-prefix reaches byteOffset.
37
+ let lo = 0;
38
+ let hi = source.length;
39
+ while (lo < hi) {
40
+ const mid = (lo + hi) >> 1;
41
+ if (prefix[mid] < byteOffset)
42
+ lo = mid + 1;
43
+ else
44
+ hi = mid;
45
+ }
46
+ return lo;
47
+ }
48
+ /** Root-to-node child indexes (`indexOf` returns `undefined` at the root). */
49
+ function pathOf(node, ctx) {
50
+ const idx = [];
51
+ let cur = node;
52
+ while (cur) {
53
+ const i = ctx.indexOf(cur);
54
+ if (i === undefined)
55
+ break;
56
+ idx.unshift(i);
57
+ cur = ctx.parent(cur);
58
+ }
59
+ return idx;
60
+ }
61
+ /** Ancestor node types, nearest-first, excluding the node itself. */
62
+ function ancestorTypes(node, ctx) {
63
+ const out = [];
64
+ let cur = ctx.parent(node);
65
+ while (cur) {
66
+ out.push(cur.type);
67
+ cur = ctx.parent(cur);
68
+ }
69
+ return out;
70
+ }
71
+ function stamp(target, ctx, input) {
72
+ const attrs = computeStamp(input);
73
+ if (!attrs)
74
+ return;
75
+ const data = { ...(target.data ?? {}) };
76
+ data.hProperties = { ...data.hProperties, ...attrs };
77
+ ctx.setProperty(target, "data", data);
78
+ }
79
+ export function caretSatteriPlugin(options) {
80
+ const { contentRoot } = options;
81
+ const base = (node, ctx) => {
82
+ const startByte = node.position?.start?.offset;
83
+ const endByte = node.position?.end?.offset;
84
+ return {
85
+ source: ctx.source,
86
+ fileURL: ctx.fileURL,
87
+ contentRoot,
88
+ start: startByte == null ? undefined : byteToStringIndex(ctx.source, startByte),
89
+ end: endByte == null ? undefined : byteToStringIndex(ctx.source, endByte),
90
+ };
91
+ };
92
+ return {
93
+ name: "caretcms-stamp",
94
+ options: { position: true },
95
+ heading(node, ctx) {
96
+ const parentType = ctx.parent(node)?.type ?? "root";
97
+ stamp(node, ctx, {
98
+ ...base(node, ctx),
99
+ blockPath: pathOf(node, ctx),
100
+ ancestorTypes: ancestorTypes(node, ctx),
101
+ nested: parentType !== "root",
102
+ blockType: "heading",
103
+ });
104
+ },
105
+ paragraph(node, ctx) {
106
+ const parent = ctx.parent(node);
107
+ const plan = planParagraph(parent?.type ?? "root", ctx.indexOf(node));
108
+ if (plan.action === "skip")
109
+ return;
110
+ const target = plan.action === "parent" ? parent : node;
111
+ stamp(target, ctx, {
112
+ ...base(node, ctx), // the paragraph's (marker-free) offsets
113
+ blockPath: pathOf(target, ctx),
114
+ ancestorTypes: ancestorTypes(target, ctx),
115
+ nested: plan.action === "parent" ? true : plan.nested,
116
+ });
117
+ },
118
+ };
119
+ }
120
+ //# sourceMappingURL=satteri.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"satteri.js","sourceRoot":"","sources":["../../src/markdown/satteri.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * DOM-free markdown block serializer.
3
+ *
4
+ * Turns the inline content of ONE editable block into markdown source. The
5
+ * closed set is deliberately tiny — text, `strong`/`b`, `em`/`i`, `a[href]`,
6
+ * `code`, `br` — so serialization is a small, total, reversible function
7
+ * rather than a general HTML→markdown converter. Anything outside the set is a
8
+ * hard error: the browser sanitizes to this set before serializing, so a throw
9
+ * means a bug or an attack, never normal input.
10
+ *
11
+ * Pure and DOM-free by design: it operates on a minimal {@link SNode} tree so
12
+ * it can be property-tested in Node without a DOM, and the browser editor
13
+ * (`static/cms/editor/md-serialize.js`) supplies a matching tree from real DOM
14
+ * nodes. A parity test holds the two implementations to identical output.
15
+ *
16
+ * Known limitations (CommonMark/GFM constraints, not corruption — text is
17
+ * always preserved; only emphasis boundaries or auto-linking may shift):
18
+ * - Abutting emphasis whose first span ends in punctuation and is followed by
19
+ * a word char: asterisks fuse, underscore can't close (see `emphasisMarker`).
20
+ * - Emphasis that starts with punctuation-leading content (e.g. a link) while
21
+ * immediately preceded by a word char: the opening `*`/`_` is not
22
+ * left-flanking, so the emphasis can't open. Unrepresentable in CommonMark.
23
+ * - A bare email/URL in plain text (`a@b.com`, `www.x.com`) is auto-linked by
24
+ * GFM on render; a second edit then serializes it as an explicit link.
25
+ * - Links normalize to untitled inline form: editing a block rewrites
26
+ * reference-style links (`[x][1]`) as inline links and drops link titles
27
+ * (`"…"`) — text and destination are preserved, the definition lines
28
+ * elsewhere in the document are untouched. Title support needs `title` in
29
+ * the shared rich allowlist (v0.4 candidate).
30
+ * The editor doesn't produce these from normal selection-based formatting, so
31
+ * they are documented rather than special-cased.
32
+ */
33
+ /** A minimal, DOM-independent representation of inline content. */
34
+ export type SNode = {
35
+ type: "text";
36
+ value: string;
37
+ } | {
38
+ type: "element";
39
+ tag: string;
40
+ attrs: Record<string, string>;
41
+ children: SNode[];
42
+ };
43
+ /** Which block wraps the inline content — determines markers and break rules. */
44
+ export type BlockContext = {
45
+ block: "heading";
46
+ level: number;
47
+ } | {
48
+ block: "paragraph";
49
+ nested: boolean;
50
+ };
51
+ /** Thrown when the tree contains anything outside the closed inline set. */
52
+ export declare class SerializeError extends Error {
53
+ constructor(message: string);
54
+ }
55
+ /**
56
+ * Serialize the inline children of one block to markdown source, ready to
57
+ * splice into the block's source range.
58
+ */
59
+ export declare function serializeBlock(children: readonly SNode[], ctx: BlockContext): string;
60
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/markdown/serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,mEAAmE;AACnE,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC;AAEvF,iFAAiF;AACjF,MAAM,MAAM,YAAY,GACpB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5C,4EAA4E;AAC5E,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AA6ND;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAepF"}
@@ -0,0 +1,264 @@
1
+ /**
2
+ * DOM-free markdown block serializer.
3
+ *
4
+ * Turns the inline content of ONE editable block into markdown source. The
5
+ * closed set is deliberately tiny — text, `strong`/`b`, `em`/`i`, `a[href]`,
6
+ * `code`, `br` — so serialization is a small, total, reversible function
7
+ * rather than a general HTML→markdown converter. Anything outside the set is a
8
+ * hard error: the browser sanitizes to this set before serializing, so a throw
9
+ * means a bug or an attack, never normal input.
10
+ *
11
+ * Pure and DOM-free by design: it operates on a minimal {@link SNode} tree so
12
+ * it can be property-tested in Node without a DOM, and the browser editor
13
+ * (`static/cms/editor/md-serialize.js`) supplies a matching tree from real DOM
14
+ * nodes. A parity test holds the two implementations to identical output.
15
+ *
16
+ * Known limitations (CommonMark/GFM constraints, not corruption — text is
17
+ * always preserved; only emphasis boundaries or auto-linking may shift):
18
+ * - Abutting emphasis whose first span ends in punctuation and is followed by
19
+ * a word char: asterisks fuse, underscore can't close (see `emphasisMarker`).
20
+ * - Emphasis that starts with punctuation-leading content (e.g. a link) while
21
+ * immediately preceded by a word char: the opening `*`/`_` is not
22
+ * left-flanking, so the emphasis can't open. Unrepresentable in CommonMark.
23
+ * - A bare email/URL in plain text (`a@b.com`, `www.x.com`) is auto-linked by
24
+ * GFM on render; a second edit then serializes it as an explicit link.
25
+ * - Links normalize to untitled inline form: editing a block rewrites
26
+ * reference-style links (`[x][1]`) as inline links and drops link titles
27
+ * (`"…"`) — text and destination are preserved, the definition lines
28
+ * elsewhere in the document are untouched. Title support needs `title` in
29
+ * the shared rich allowlist (v0.4 candidate).
30
+ * The editor doesn't produce these from normal selection-based formatting, so
31
+ * they are documented rather than special-cased.
32
+ */
33
+ /** Thrown when the tree contains anything outside the closed inline set. */
34
+ export class SerializeError extends Error {
35
+ constructor(message) {
36
+ super(message);
37
+ this.name = "SerializeError";
38
+ }
39
+ }
40
+ /** ASCII punctuation that CommonMark/GFM lets a backslash escape; we escape the
41
+ * subset that can change inline parsing (`~` is GFM strikethrough). */
42
+ const INLINE_ESCAPE_RE = /[\\`*_[\]<&>~]/g;
43
+ function escapeText(value) {
44
+ // Collapse ASCII whitespace runs to a single space FIRST — this is exactly
45
+ // what HTML rendering does visually, and it makes `<br>` the serializer's
46
+ // only newline source. Without it, a raw `\n` in a text node emits a soft
47
+ // line break whose next line can open a block, and 4+ leading spaces form an
48
+ // indented code block when spliced. ` ` (nbsp) is deliberately NOT
49
+ // collapsed — HTML preserves it, so we do too.
50
+ return value.replace(/[ \t\r\n]+/g, " ").replace(INLINE_ESCAPE_RE, (c) => `\\${c}`);
51
+ }
52
+ /**
53
+ * Escape a leading block-marker so spliced paragraph text can't open a new
54
+ * block. Markers act only at line start, and a bullet / ordered marker triggers
55
+ * even with no following text (`+` alone is an empty list item), so the guard
56
+ * covers end-of-line too. Ordered markers escape the punctuation, not the digit
57
+ * (`\1` is not a valid escape; `1\.` is).
58
+ */
59
+ function escapeLineStart(md) {
60
+ const ws = /^\s*/.exec(md)[0];
61
+ const rest = md.slice(ws.length);
62
+ const ordered = /^(\d{1,9})([.)])(\s|$)/.exec(rest);
63
+ if (ordered) {
64
+ return `${ws}${ordered[1]}\\${ordered[2]}${rest.slice(ordered[1].length + 1)}`;
65
+ }
66
+ // Dash/equals runs cover three block constructs at once: setext underlines
67
+ // are ONE-or-more `-`/`=` (a lone `=` after a hard break turns the paragraph
68
+ // into an <h1>), and thematic breaks allow interior spaces (`-- -`). `*`/`_`
69
+ // variants are already neutralized by escapeText.
70
+ const marker = /^(?:#{1,6}(?=\s|$)|>|[-+*](?=\s|$)|-(?:[ \t]*-)*[ \t]*$|=(?:[ \t]*=)*[ \t]*$|~{3,}|`{3,}|\|)/.test(rest);
71
+ return marker ? `${ws}\\${rest}` : md;
72
+ }
73
+ function tagOf(node) {
74
+ const t = node.tag.toLowerCase();
75
+ if (t === "b")
76
+ return "strong";
77
+ if (t === "i")
78
+ return "em";
79
+ return t;
80
+ }
81
+ /** Concatenated text of a subtree (for code spans, whose content is literal). */
82
+ function rawText(nodes) {
83
+ let out = "";
84
+ for (const n of nodes) {
85
+ if (n.type === "text")
86
+ out += n.value;
87
+ else if (n.tag.toLowerCase() === "br")
88
+ out += " ";
89
+ else
90
+ out += rawText(n.children);
91
+ }
92
+ return out;
93
+ }
94
+ /** Render a code span with a backtick fence long enough to hold the content. */
95
+ function codeSpan(content) {
96
+ if (content === "")
97
+ return "``";
98
+ let runs = content.match(/`+/g) ?? [];
99
+ let fenceLen = 1;
100
+ while (runs.some((r) => r.length === fenceLen))
101
+ fenceLen++;
102
+ const fence = "`".repeat(fenceLen);
103
+ // Pad when the content touches a backtick edge or is all spaces (CommonMark rule).
104
+ const needsPad = content.startsWith("`") ||
105
+ content.endsWith("`") ||
106
+ (content.startsWith(" ") && content.endsWith(" ") && content.trim() !== "");
107
+ return needsPad ? `${fence} ${content} ${fence}` : `${fence}${content}${fence}`;
108
+ }
109
+ /** Represent a link destination, using the `<...>` form when it isn't bare-safe. */
110
+ function linkDestination(href) {
111
+ // Control characters (incl. \n, \r) have no representable escape in either
112
+ // destination form — a newline inside `<...>` terminates the destination and
113
+ // injects raw markdown structure. Hard-fail, per this file's philosophy.
114
+ // eslint-disable-next-line no-control-regex
115
+ if (/[\u0000-\u001f\u007f]/u.test(href)) {
116
+ throw new SerializeError("control character in link destination");
117
+ }
118
+ if (/^[^\s<>()\\]*$/.test(href))
119
+ return href;
120
+ return `<${href.replace(/([<>\\])/g, "\\$1")}>`;
121
+ }
122
+ /**
123
+ * Coalesce adjacent siblings that would otherwise emit colliding markdown:
124
+ * consecutive text nodes merge, and consecutive elements of the same
125
+ * (normalized) tag and attributes fuse their children. Without this,
126
+ * `<strong>a</strong><strong>b</strong>` serializes to `**a****b**`, whose
127
+ * `****` run CommonMark parses ambiguously. Merging renders identically and
128
+ * round-trips cleanly.
129
+ */
130
+ function mergeAdjacent(nodes) {
131
+ const out = [];
132
+ for (const node of nodes) {
133
+ const prev = out[out.length - 1];
134
+ if (node.type === "text" && prev?.type === "text") {
135
+ prev.value += node.value;
136
+ continue;
137
+ }
138
+ if (node.type === "element" &&
139
+ prev?.type === "element" &&
140
+ tagOf(prev) === tagOf(node) &&
141
+ tagOf(node) !== "br" &&
142
+ sameAttrs(prev.attrs, node.attrs)) {
143
+ prev.children = [...prev.children, ...node.children];
144
+ continue;
145
+ }
146
+ out.push(node.type === "text" ? { ...node } : { ...node, children: [...node.children] });
147
+ }
148
+ return out;
149
+ }
150
+ function sameAttrs(a, b) {
151
+ const ka = Object.keys(a);
152
+ const kb = Object.keys(b);
153
+ return ka.length === kb.length && ka.every((k) => a[k] === b[k]);
154
+ }
155
+ /** First raw character of the next sibling, or "" — used to keep an underscore
156
+ * emphasis from abutting a word character (CommonMark's intraword rule). */
157
+ function nextLeadChar(nodes, i) {
158
+ const next = nodes[i + 1];
159
+ if (!next)
160
+ return "";
161
+ if (next.type === "text")
162
+ return next.value[0] ?? "";
163
+ return "<"; // an element emits a delimiter/bracket — never a word char
164
+ }
165
+ /**
166
+ * Emphasis delimiter for the element at `i`. Consecutive `em`/`strong` siblings
167
+ * abut with no text between, so their `*` delimiters would fuse into an
168
+ * ambiguous run (CommonMark's rule of three). We alternate `*`↔`_` across such
169
+ * a run so neighbours never share a delimiter character. Underscore can't close
170
+ * against a following word character, so we fall back to `*` there (safe for
171
+ * every realistic case; see the serializer notes for the one excluded shape).
172
+ */
173
+ function emphasisMarker(nodes, i, prevMarker) {
174
+ if (prevMarker === null)
175
+ return "*";
176
+ const flipped = prevMarker === "*" ? "_" : "*";
177
+ if (flipped === "_" && /[A-Za-z0-9_]/.test(nextLeadChar(nodes, i)))
178
+ return "*";
179
+ return flipped;
180
+ }
181
+ function serializeChildren(rawNodes, opts) {
182
+ const nodes = mergeAdjacent(rawNodes);
183
+ let out = "";
184
+ let prevMarker = null;
185
+ for (let i = 0; i < nodes.length; i++) {
186
+ const node = nodes[i];
187
+ if (node.type === "text") {
188
+ out += escapeText(node.value);
189
+ prevMarker = null;
190
+ continue;
191
+ }
192
+ const tag = tagOf(node);
193
+ switch (tag) {
194
+ case "strong": {
195
+ const inner = serializeChildren(node.children, opts);
196
+ if (inner === "") {
197
+ prevMarker = null;
198
+ break;
199
+ }
200
+ const m = emphasisMarker(nodes, i, prevMarker);
201
+ out += `${m}${m}${inner}${m}${m}`;
202
+ prevMarker = m;
203
+ break;
204
+ }
205
+ case "em": {
206
+ const inner = serializeChildren(node.children, opts);
207
+ if (inner === "") {
208
+ prevMarker = null;
209
+ break;
210
+ }
211
+ const m = emphasisMarker(nodes, i, prevMarker);
212
+ out += `${m}${inner}${m}`;
213
+ prevMarker = m;
214
+ break;
215
+ }
216
+ case "code": {
217
+ prevMarker = null;
218
+ out += codeSpan(rawText(node.children));
219
+ break;
220
+ }
221
+ case "a": {
222
+ const href = node.attrs.href;
223
+ if (href === undefined)
224
+ throw new SerializeError("<a> without href");
225
+ prevMarker = null;
226
+ const inner = serializeChildren(node.children, opts);
227
+ out += `[${inner}](${linkDestination(href)})`;
228
+ break;
229
+ }
230
+ case "br": {
231
+ if (!opts.allowBreak) {
232
+ throw new SerializeError("hard break not allowed in a nested block");
233
+ }
234
+ prevMarker = null;
235
+ out += "\\\n";
236
+ break;
237
+ }
238
+ default:
239
+ throw new SerializeError(`unsupported inline element <${node.tag}>`);
240
+ }
241
+ }
242
+ return out;
243
+ }
244
+ /**
245
+ * Serialize the inline children of one block to markdown source, ready to
246
+ * splice into the block's source range.
247
+ */
248
+ export function serializeBlock(children, ctx) {
249
+ if (ctx.block === "heading") {
250
+ if (!Number.isInteger(ctx.level) || ctx.level < 1 || ctx.level > 6) {
251
+ throw new SerializeError(`invalid heading level: ${ctx.level}`);
252
+ }
253
+ const inline = serializeChildren(children, { allowBreak: false });
254
+ return `${"#".repeat(ctx.level)} ${inline}`;
255
+ }
256
+ const inline = serializeChildren(children, { allowBreak: !ctx.nested });
257
+ // Every LINE of a paragraph must be prevented from opening another block —
258
+ // CommonMark's block scanner runs before inline parsing, so a line after a
259
+ // hard break that starts with `#`/`>`/`- `/etc. would interrupt the
260
+ // paragraph. `escapeText` collapses raw newlines, so the hard-break sequence
261
+ // is the only line boundary the serializer can emit.
262
+ return inline.split("\\\n").map(escapeLineStart).join("\\\n");
263
+ }
264
+ //# sourceMappingURL=serialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/markdown/serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAYH,4EAA4E;AAC5E,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;wEACwE;AACxE,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAE3C,SAAS,UAAU,CAAC,KAAa;IAC/B,2EAA2E;IAC3E,0EAA0E;IAC1E,0EAA0E;IAC1E,6EAA6E;IAC7E,mEAAmE;IACnE,+CAA+C;IAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AACtF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,EAAU;IACjC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAE,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAEjC,MAAM,OAAO,GAAG,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;IACjF,CAAC;IAED,2EAA2E;IAC3E,6EAA6E;IAC7E,6EAA6E;IAC7E,kDAAkD;IAClD,MAAM,MAAM,GACV,8FAA8F,CAAC,IAAI,CACjG,IAAI,CACL,CAAC;IACJ,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,KAAK,CAAC,IAAyC;IACtD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC/B,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iFAAiF;AACjF,SAAS,OAAO,CAAC,KAAuB;IACtC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;YAAE,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC;aACjC,IAAI,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,IAAI;YAAE,GAAG,IAAI,GAAG,CAAC;;YAC7C,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,SAAS,QAAQ,CAAC,OAAe;IAC/B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACtC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;QAAE,QAAQ,EAAE,CAAC;IAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,mFAAmF;IACnF,MAAM,QAAQ,GACZ,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QACvB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACrB,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9E,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,EAAE,CAAC;AAClF,CAAC;AAED,oFAAoF;AACpF,SAAS,eAAe,CAAC,IAAY;IACnC,2EAA2E;IAC3E,6EAA6E;IAC7E,yEAAyE;IACzE,4CAA4C;IAC5C,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,cAAc,CAAC,uCAAuC,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC;AAClD,CAAC;AAMD;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,KAAuB;IAC5C,MAAM,GAAG,GAAY,EAAE,CAAC;IACxB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;YAClD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;YACzB,SAAS;QACX,CAAC;QACD,IACE,IAAI,CAAC,IAAI,KAAK,SAAS;YACvB,IAAI,EAAE,IAAI,KAAK,SAAS;YACxB,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI;YACpB,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EACjC,CAAC;YACD,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrD,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,SAAS,CAAC,CAAyB,EAAE,CAAyB;IACrE,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;6EAC6E;AAC7E,SAAS,YAAY,CAAC,KAAuB,EAAE,CAAS;IACtD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,OAAO,GAAG,CAAC,CAAC,2DAA2D;AACzE,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CACrB,KAAuB,EACvB,CAAS,EACT,UAA4B;IAE5B,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,GAAG,CAAC;IACpC,MAAM,OAAO,GAAG,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC/C,IAAI,OAAO,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/E,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,iBAAiB,CAAC,QAA0B,EAAE,IAAgB;IACrE,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,UAAU,GAAqB,IAAI,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9B,UAAU,GAAG,IAAI,CAAC;YAClB,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACxB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACrD,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;oBACjB,UAAU,GAAG,IAAI,CAAC;oBAClB,MAAM;gBACR,CAAC;gBACD,MAAM,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;gBAC/C,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,UAAU,GAAG,CAAC,CAAC;gBACf,MAAM;YACR,CAAC;YACD,KAAK,IAAI,CAAC,CAAC,CAAC;gBACV,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACrD,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;oBACjB,UAAU,GAAG,IAAI,CAAC;oBAClB,MAAM;gBACR,CAAC;gBACD,MAAM,CAAC,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;gBAC/C,GAAG,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC;gBAC1B,UAAU,GAAG,CAAC,CAAC;gBACf,MAAM;YACR,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,UAAU,GAAG,IAAI,CAAC;gBAClB,GAAG,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACxC,MAAM;YACR,CAAC;YACD,KAAK,GAAG,CAAC,CAAC,CAAC;gBACT,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC7B,IAAI,IAAI,KAAK,SAAS;oBAAE,MAAM,IAAI,cAAc,CAAC,kBAAkB,CAAC,CAAC;gBACrE,UAAU,GAAG,IAAI,CAAC;gBAClB,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACrD,GAAG,IAAI,IAAI,KAAK,KAAK,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC9C,MAAM;YACR,CAAC;YACD,KAAK,IAAI,CAAC,CAAC,CAAC;gBACV,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;oBACrB,MAAM,IAAI,cAAc,CAAC,0CAA0C,CAAC,CAAC;gBACvE,CAAC;gBACD,UAAU,GAAG,IAAI,CAAC;gBAClB,GAAG,IAAI,MAAM,CAAC;gBACd,MAAM;YACR,CAAC;YACD;gBACE,MAAM,IAAI,cAAc,CAAC,+BAA+B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAA0B,EAAE,GAAiB;IAC1E,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;YACnE,MAAM,IAAI,cAAc,CAAC,0BAA0B,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QAClE,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;IAC9C,CAAC;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACxE,2EAA2E;IAC3E,2EAA2E;IAC3E,oEAAoE;IACpE,6EAA6E;IAC7E,qDAAqD;IACrD,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Publish-time body splice: apply drafted block edits to a markdown source
3
+ * file. This is the ONLY code that rewrites user prose in place, so it is
4
+ * all-or-nothing by construction — every block's range is re-verified against
5
+ * the CURRENT file (hash + bounds + overlap) before a single byte moves, and
6
+ * any failure leaves the file untouched.
7
+ *
8
+ * Pure (string -> string) so it can be property-tested without a filesystem;
9
+ * `MarkdownAdapter.spliceBodyBlocks` wraps it with read + atomic write.
10
+ */
11
+ import { type MdSrc } from "./contracts.js";
12
+ export interface BodySplice {
13
+ /** Server-derived markdown to put in the block's place. */
14
+ md: string;
15
+ /** The verified source range the draft was made against. */
16
+ src: MdSrc;
17
+ }
18
+ export type SpliceResult = {
19
+ ok: true;
20
+ content: string;
21
+ } | {
22
+ ok: false;
23
+ reason: "stale" | "overlap";
24
+ };
25
+ /**
26
+ * Splice `blocks` into `fileSource`. Returns the new file content, or a
27
+ * failure (`stale` = a range no longer hashes, the file changed since the
28
+ * draft; `overlap` = two drafts claim intersecting ranges, which can only
29
+ * happen through a corrupted draft store — never write through it).
30
+ */
31
+ export declare function spliceBodyBlocks(fileSource: string, blocks: readonly BodySplice[]): SpliceResult;
32
+ //# sourceMappingURL=splice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splice.d.ts","sourceRoot":"","sources":["../../src/markdown/splice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,WAAW,UAAU;IACzB,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,GAAG,EAAE,KAAK,CAAC;CACZ;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,UAAU,EAAE,GAC5B,YAAY,CA0Bd"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Publish-time body splice: apply drafted block edits to a markdown source
3
+ * file. This is the ONLY code that rewrites user prose in place, so it is
4
+ * all-or-nothing by construction — every block's range is re-verified against
5
+ * the CURRENT file (hash + bounds + overlap) before a single byte moves, and
6
+ * any failure leaves the file untouched.
7
+ *
8
+ * Pure (string -> string) so it can be property-tested without a filesystem;
9
+ * `MarkdownAdapter.spliceBodyBlocks` wraps it with read + atomic write.
10
+ */
11
+ import { canonicalBody } from "./canonical-body.js";
12
+ import { fnv1a32 } from "./contracts.js";
13
+ /**
14
+ * Splice `blocks` into `fileSource`. Returns the new file content, or a
15
+ * failure (`stale` = a range no longer hashes, the file changed since the
16
+ * draft; `overlap` = two drafts claim intersecting ranges, which can only
17
+ * happen through a corrupted draft store — never write through it).
18
+ */
19
+ export function spliceBodyBlocks(fileSource, blocks) {
20
+ const { body, fileOffsetOf } = canonicalBody(fileSource);
21
+ for (const { src } of blocks) {
22
+ if (src.end > body.length)
23
+ return { ok: false, reason: "stale" };
24
+ if (fnv1a32(body.slice(src.start, src.end)) !== src.hash) {
25
+ return { ok: false, reason: "stale" };
26
+ }
27
+ }
28
+ const ordered = [...blocks].sort((a, b) => b.src.start - a.src.start);
29
+ for (let i = 1; i < ordered.length; i++) {
30
+ // Descending by start: the later block in the file comes first. Overlap
31
+ // exists when the previous (later-in-file) block starts before this one ends.
32
+ if (ordered[i - 1].src.start < ordered[i].src.end) {
33
+ return { ok: false, reason: "overlap" };
34
+ }
35
+ }
36
+ let content = fileSource;
37
+ for (const { md, src } of ordered) {
38
+ const start = fileOffsetOf(src.start);
39
+ const end = fileOffsetOf(src.end);
40
+ content = content.slice(0, start) + md + content.slice(end);
41
+ }
42
+ return { ok: true, content };
43
+ }
44
+ //# sourceMappingURL=splice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splice.js","sourceRoot":"","sources":["../../src/markdown/splice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAc,MAAM,gBAAgB,CAAC;AAarD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAkB,EAClB,MAA6B;IAE7B,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAEzD,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,MAAM,EAAE,CAAC;QAC7B,IAAI,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACjE,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;YACzD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACxC,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACtE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,wEAAwE;QACxE,8EAA8E;QAC9E,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;YAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,IAAI,OAAO,GAAG,UAAU,CAAC;IACzB,KAAK,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,OAAO,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Shared, pipeline-independent logic for stamping `data-caret-md` bindings.
3
+ *
4
+ * Two frontends drive this — a Sätteri mdast plugin (Astro 7) and a remark
5
+ * plugin (Astro 6) — walking their own trees but calling the SAME pure
6
+ * functions here so both emit byte-identical attributes (a parity test holds
7
+ * them together). Nothing in this module touches a tree or a pipeline type; it
8
+ * takes already-extracted node facts and returns attributes or `null`.
9
+ */
10
+ /**
11
+ * mdast node types that make their subtree non-editable: their inner text is
12
+ * either structured (tables), reference plumbing (footnote definitions), or
13
+ * raw/JSX passthrough that markdown block editing can't safely round-trip.
14
+ */
15
+ export declare const ISLAND_TYPES: ReadonlySet<string>;
16
+ export interface ResolvedEntry {
17
+ collection: string;
18
+ id: string;
19
+ }
20
+ /**
21
+ * Resolve a source file to its `{collection, id}` under the content root, or
22
+ * `null`. v1 scope: flat `<contentRoot>/<collection>/<id>.md` only — `.mdx`,
23
+ * nested slugs, and identifiers failing the id grammar are intentionally
24
+ * unmatched (and so never stamped).
25
+ */
26
+ export declare function resolveEntry(fileURL: string | URL | undefined, contentRoot: string): ResolvedEntry | null;
27
+ export type ParagraphPlan = {
28
+ action: "skip";
29
+ } | {
30
+ action: "self";
31
+ nested: boolean;
32
+ } | {
33
+ action: "parent";
34
+ };
35
+ /**
36
+ * Decide how a paragraph maps to a bound element. A list item renders its text
37
+ * on the `<li>` (a tight list drops the `<p>` entirely), so we bind the item —
38
+ * via its FIRST paragraph, using that paragraph's marker-free offsets. Other
39
+ * paragraphs bind themselves; `nested` marks those inside a container.
40
+ */
41
+ export declare function planParagraph(parentType: string, indexInParent: number | undefined): ParagraphPlan;
42
+ export interface StampInput {
43
+ /** The exact source string the pipeline parsed (offsets are relative to it). */
44
+ source: string;
45
+ /** The file being rendered. */
46
+ fileURL: string | URL | undefined;
47
+ /** Absolute content root the markdown adapter reads from. */
48
+ contentRoot: string;
49
+ /** unist offsets of the block whose text the binding edits. */
50
+ start: number | undefined;
51
+ end: number | undefined;
52
+ /** Root-to-element child indexes identifying the bound element. */
53
+ blockPath: readonly number[];
54
+ /** Types of the bound node's ancestors (island detection). */
55
+ ancestorTypes: readonly string[];
56
+ /** True when the block sits inside a container (blockquote / list item). */
57
+ nested: boolean;
58
+ /** mdast node type of the bound block ("heading" | "paragraph" | "listItem"). */
59
+ blockType?: string;
60
+ }
61
+ /**
62
+ * Compute the `{data-caret-md, data-caret-md-src}` attributes for one block, or
63
+ * `null` to leave it unstamped. Offsets are normalized to the canonical body
64
+ * base (frontmatter-stripped, trimmed) so a `.md` import, a content-collection
65
+ * entry, and Astro 6 remark all yield the same numbers.
66
+ */
67
+ export declare function computeStamp(input: StampInput): Record<string, string> | null;
68
+ //# sourceMappingURL=stamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stamp.d.ts","sourceRoot":"","sources":["../../src/markdown/stamp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,CAS3C,CAAC;AAEH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ;AAyBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,EACjC,WAAW,EAAE,MAAM,GAClB,aAAa,GAAG,IAAI,CAetB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEzB;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,GAAG,SAAS,GAChC,aAAa,CAKf;AAED,MAAM,WAAW,UAAU;IACzB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;IAClC,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,mEAAmE;IACnE,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,8DAA8D;IAC9D,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAC;IAChB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAmC7E"}