@growth-labs/cms 0.5.17 → 0.5.18

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 (67) hide show
  1. package/README.md +29 -0
  2. package/dist/engine/published-content.js +1 -1
  3. package/dist/engine/published-content.js.map +1 -1
  4. package/dist/engine/publisher.d.ts +6 -0
  5. package/dist/engine/publisher.d.ts.map +1 -1
  6. package/dist/engine/publisher.js +16 -7
  7. package/dist/engine/publisher.js.map +1 -1
  8. package/dist/engine/revisions.d.ts.map +1 -1
  9. package/dist/engine/revisions.js +1 -0
  10. package/dist/engine/revisions.js.map +1 -1
  11. package/dist/routes/content.d.ts.map +1 -1
  12. package/dist/routes/content.js +19 -1
  13. package/dist/routes/content.js.map +1 -1
  14. package/dist/schema/index.d.ts +1 -0
  15. package/dist/schema/index.d.ts.map +1 -1
  16. package/dist/schema/index.js +1 -0
  17. package/dist/schema/index.js.map +1 -1
  18. package/dist/schema/migrations.d.ts.map +1 -1
  19. package/dist/schema/migrations.js +7 -0
  20. package/dist/schema/migrations.js.map +1 -1
  21. package/dist/schema/portable-text.d.ts +52 -0
  22. package/dist/schema/portable-text.d.ts.map +1 -0
  23. package/dist/schema/portable-text.js +86 -0
  24. package/dist/schema/portable-text.js.map +1 -0
  25. package/dist/schema/types.d.ts +2 -0
  26. package/dist/schema/types.d.ts.map +1 -1
  27. package/dist/schema/types.js.map +1 -1
  28. package/dist/ui/editor/ContentForm.d.ts.map +1 -1
  29. package/dist/ui/editor/ContentForm.js +5 -3
  30. package/dist/ui/editor/ContentForm.js.map +1 -1
  31. package/dist/ui/editor/Rte.d.ts +12 -3
  32. package/dist/ui/editor/Rte.d.ts.map +1 -1
  33. package/dist/ui/editor/Rte.js +91 -10
  34. package/dist/ui/editor/Rte.js.map +1 -1
  35. package/dist/ui/editor/content-payload.d.ts +2 -0
  36. package/dist/ui/editor/content-payload.d.ts.map +1 -1
  37. package/dist/ui/editor/content-payload.js +1 -0
  38. package/dist/ui/editor/content-payload.js.map +1 -1
  39. package/dist/ui/editor/extensions.d.ts +1 -1
  40. package/dist/ui/editor/extensions.d.ts.map +1 -1
  41. package/dist/ui/editor/extensions.js +4 -0
  42. package/dist/ui/editor/extensions.js.map +1 -1
  43. package/dist/ui/editor/portable-text.d.ts +7 -0
  44. package/dist/ui/editor/portable-text.d.ts.map +1 -0
  45. package/dist/ui/editor/portable-text.js +461 -0
  46. package/dist/ui/editor/portable-text.js.map +1 -0
  47. package/dist/ui/editor/serialize.d.ts.map +1 -1
  48. package/dist/ui/editor/serialize.js +99 -3
  49. package/dist/ui/editor/serialize.js.map +1 -1
  50. package/dist/ui/styles/broadsheet.css +11 -0
  51. package/migrations/0024_article_portable_text.sql +6 -0
  52. package/package.json +2 -1
  53. package/src/engine/published-content.ts +1 -1
  54. package/src/engine/publisher.ts +22 -5
  55. package/src/engine/revisions.ts +2 -0
  56. package/src/routes/content.ts +20 -1
  57. package/src/schema/index.ts +8 -0
  58. package/src/schema/migrations.ts +7 -0
  59. package/src/schema/portable-text.ts +110 -0
  60. package/src/schema/types.ts +2 -0
  61. package/src/ui/editor/ContentForm.tsx +8 -2
  62. package/src/ui/editor/Rte.tsx +120 -10
  63. package/src/ui/editor/content-payload.ts +3 -0
  64. package/src/ui/editor/extensions.ts +4 -0
  65. package/src/ui/editor/portable-text.ts +523 -0
  66. package/src/ui/editor/serialize.ts +107 -3
  67. package/src/ui/styles/broadsheet.css +11 -0
@@ -0,0 +1,461 @@
1
+ // src/ui/editor/portable-text.ts
2
+ // PURE Tiptap doc↔Portable Text serializer pair.
3
+ // Operates exclusively on the ProseMirror JSONContent shape — no Editor,
4
+ // no EditorView, no DOM, fully testable in vitest (Node env).
5
+ //
6
+ // Portable Text is the durable store (schema/portable-text.ts documents the
7
+ // version 1 vocabulary); markdown stays a derived view produced by
8
+ // serialize.ts from the same Tiptap doc. Both serializers here are total over
9
+ // the editor's node set — an unknown node degrades to its text content on the
10
+ // way out, and an unknown `_type` throws on the way in so a vocabulary drift
11
+ // fails loudly instead of silently dropping content.
12
+ //
13
+ // Mark mapping (Tiptap ↔ Portable Text):
14
+ // bold ↔ strong, italic ↔ em, strike ↔ strike-through, code ↔ code,
15
+ // link ↔ markDef annotation { _type: 'link', href, title?, target? }
16
+ // Lists are stored FLAT (listItem + level per block) per the Portable Text
17
+ // convention; nesting is reconstructed on load. Hard breaks are stored as
18
+ // newlines inside span text.
19
+ import { normalizeBoundaryMarks } from './trim-boundary-marks.js';
20
+ /** Deterministic 12-hex key sequence: identical docs serialize identically. */
21
+ function createKeyGenerator() {
22
+ let n = 0;
23
+ return () => {
24
+ n += 1;
25
+ return n.toString(16).padStart(12, '0');
26
+ };
27
+ }
28
+ // ─────────────────────────────────────────────────────────────────────────────
29
+ // docToPortableText — JSONContent → PortableTextObject[]
30
+ // ─────────────────────────────────────────────────────────────────────────────
31
+ const DECORATOR_BY_TIPTAP_MARK = {
32
+ bold: 'strong',
33
+ italic: 'em',
34
+ strike: 'strike-through',
35
+ code: 'code',
36
+ };
37
+ /** Serialise a Tiptap JSONContent document to a Portable Text array. */
38
+ export function docToPortableText(doc) {
39
+ const normalized = normalizeBoundaryMarks(doc);
40
+ const nextKey = createKeyGenerator();
41
+ return serializeBlocks(normalized.content ?? [], nextKey);
42
+ }
43
+ function serializeBlocks(nodes, nextKey) {
44
+ const out = [];
45
+ for (const node of nodes)
46
+ serializeBlockNode(node, out, nextKey, null);
47
+ return out;
48
+ }
49
+ function serializeBlockNode(node, out, nextKey, list) {
50
+ switch (node.type ?? 'paragraph') {
51
+ case 'paragraph':
52
+ out.push(buildTextBlock('normal', node.content ?? [], nextKey, list));
53
+ return;
54
+ case 'heading': {
55
+ const level = node.attrs?.level ?? 2;
56
+ out.push(buildTextBlock(`h${level}`, node.content ?? [], nextKey, list));
57
+ return;
58
+ }
59
+ case 'blockquote': {
60
+ for (const child of node.content ?? []) {
61
+ if (child.type === 'paragraph') {
62
+ out.push(buildTextBlock('blockquote', child.content ?? [], nextKey, list));
63
+ }
64
+ else {
65
+ serializeBlockNode(child, out, nextKey, list);
66
+ }
67
+ }
68
+ return;
69
+ }
70
+ case 'bulletList':
71
+ serializeList(node, out, nextKey, 'bullet', list ? list.level + 1 : 1);
72
+ return;
73
+ case 'orderedList':
74
+ serializeList(node, out, nextKey, 'number', list ? list.level + 1 : 1);
75
+ return;
76
+ case 'codeBlock': {
77
+ const code = (node.content ?? []).map((child) => child.text ?? '').join('');
78
+ out.push({
79
+ _type: 'code',
80
+ _key: nextKey(),
81
+ language: node.attrs?.language ?? null,
82
+ code,
83
+ });
84
+ return;
85
+ }
86
+ case 'image':
87
+ out.push(imageObject(node, nextKey));
88
+ return;
89
+ case 'tweetEmbed':
90
+ out.push({
91
+ _type: 'tweetEmbed',
92
+ _key: nextKey(),
93
+ url: node.attrs?.url ?? '',
94
+ });
95
+ return;
96
+ case 'horizontalRule':
97
+ out.push({ _type: 'horizontalRule', _key: nextKey() });
98
+ return;
99
+ case 'table':
100
+ out.push(serializeTable(node, nextKey));
101
+ return;
102
+ default: {
103
+ // Unknown block: keep its text content rather than dropping it.
104
+ const inline = node.content ?? [];
105
+ if (inline.length > 0)
106
+ out.push(buildTextBlock('normal', inline, nextKey, list));
107
+ }
108
+ }
109
+ }
110
+ function serializeList(node, out, nextKey, kind, level) {
111
+ for (const item of node.content ?? []) {
112
+ for (const child of item.content ?? []) {
113
+ if (child.type === 'paragraph') {
114
+ out.push(buildTextBlock('normal', child.content ?? [], nextKey, { kind, level }));
115
+ }
116
+ else if (child.type === 'bulletList') {
117
+ serializeList(child, out, nextKey, 'bullet', level + 1);
118
+ }
119
+ else if (child.type === 'orderedList') {
120
+ serializeList(child, out, nextKey, 'number', level + 1);
121
+ }
122
+ else {
123
+ serializeBlockNode(child, out, nextKey, { kind, level });
124
+ }
125
+ }
126
+ }
127
+ }
128
+ function imageObject(node, nextKey) {
129
+ return {
130
+ _type: 'image',
131
+ _key: nextKey(),
132
+ src: node.attrs?.src ?? '',
133
+ alt: node.attrs?.alt ?? '',
134
+ title: node.attrs?.title ?? null,
135
+ };
136
+ }
137
+ function buildTextBlock(style, inline, nextKey, list) {
138
+ const markDefs = [];
139
+ const pending = [];
140
+ const pushText = (text, marks) => {
141
+ const previous = pending[pending.length - 1];
142
+ if (previous &&
143
+ !('_type' in previous) &&
144
+ JSON.stringify(previous.marks) === JSON.stringify(marks)) {
145
+ previous.text += text;
146
+ }
147
+ else {
148
+ pending.push({ marks, text });
149
+ }
150
+ };
151
+ for (const node of inline) {
152
+ if (node.type === 'hardBreak') {
153
+ pushText('\n', []);
154
+ continue;
155
+ }
156
+ if (node.type === 'image') {
157
+ pending.push(imageObject(node, nextKey));
158
+ continue;
159
+ }
160
+ const text = node.text ?? '';
161
+ if (text === '' && (node.marks ?? []).length === 0 && node.type !== 'text')
162
+ continue;
163
+ const marks = [];
164
+ for (const mark of node.marks ?? []) {
165
+ const decorator = DECORATOR_BY_TIPTAP_MARK[mark.type ?? ''];
166
+ if (decorator) {
167
+ marks.push(decorator);
168
+ continue;
169
+ }
170
+ if (mark.type === 'link') {
171
+ marks.push(linkMarkDefKey(mark, markDefs, nextKey));
172
+ }
173
+ // Marks without a Portable Text form (legacy underline) are dropped,
174
+ // matching the markdown serializer.
175
+ }
176
+ pushText(text, marks);
177
+ }
178
+ const children = pending.map((entry) => '_type' in entry
179
+ ? entry
180
+ : { _type: 'span', _key: nextKey(), text: entry.text, marks: entry.marks });
181
+ if (children.length === 0) {
182
+ children.push({ _type: 'span', _key: nextKey(), text: '', marks: [] });
183
+ }
184
+ const block = {
185
+ _type: 'block',
186
+ _key: nextKey(),
187
+ style,
188
+ markDefs,
189
+ children,
190
+ };
191
+ if (list) {
192
+ block.listItem = list.kind;
193
+ block.level = list.level;
194
+ }
195
+ return block;
196
+ }
197
+ function linkMarkDefKey(mark, markDefs, nextKey) {
198
+ const href = mark.attrs?.href ?? '';
199
+ const title = mark.attrs?.title ?? null;
200
+ const target = mark.attrs?.target ?? null;
201
+ const existing = markDefs.find((def) => def._type === 'link' &&
202
+ def.href === href &&
203
+ (def.title ?? null) === title &&
204
+ (def.target ?? null) === target);
205
+ if (existing)
206
+ return existing._key;
207
+ const def = { _key: nextKey(), _type: 'link', href };
208
+ if (title !== null)
209
+ def.title = title;
210
+ if (target !== null)
211
+ def.target = target;
212
+ markDefs.push(def);
213
+ return def._key;
214
+ }
215
+ function serializeTable(node, nextKey) {
216
+ const rows = (node.content ?? []).filter((row) => row.type === 'tableRow');
217
+ let headerRows = 0;
218
+ for (const row of rows) {
219
+ const cells = row.content ?? [];
220
+ if (cells.length > 0 && cells.every((cell) => cell.type === 'tableHeader'))
221
+ headerRows += 1;
222
+ else
223
+ break;
224
+ }
225
+ return {
226
+ _type: 'table',
227
+ _key: nextKey(),
228
+ headerRows,
229
+ rows: rows.map((row, rowIndex) => ({
230
+ _type: 'row',
231
+ _key: nextKey(),
232
+ cells: (row.content ?? []).map((cell) => serializeTableCell(cell, rowIndex, headerRows, nextKey)),
233
+ })),
234
+ };
235
+ }
236
+ function serializeTableCell(cell, rowIndex, headerRows, nextKey) {
237
+ const out = {
238
+ _type: 'cell',
239
+ _key: nextKey(),
240
+ value: serializeBlocks(cell.content ?? [], nextKey),
241
+ };
242
+ if (cell.type === 'tableHeader' && rowIndex >= headerRows)
243
+ out.header = true;
244
+ const colspan = cell.attrs?.colspan ?? 1;
245
+ const rowspan = cell.attrs?.rowspan ?? 1;
246
+ const colwidth = cell.attrs?.colwidth ?? null;
247
+ const align = cell.attrs?.align ?? null;
248
+ if (colspan !== 1)
249
+ out.colspan = colspan;
250
+ if (rowspan !== 1)
251
+ out.rowspan = rowspan;
252
+ if (colwidth !== null)
253
+ out.colwidth = colwidth;
254
+ if (align !== null)
255
+ out.align = align;
256
+ return out;
257
+ }
258
+ // ─────────────────────────────────────────────────────────────────────────────
259
+ // portableTextToDoc — PortableTextObject[] → JSONContent
260
+ // ─────────────────────────────────────────────────────────────────────────────
261
+ const TIPTAP_MARK_BY_DECORATOR = {
262
+ strong: 'bold',
263
+ em: 'italic',
264
+ 'strike-through': 'strike',
265
+ code: 'code',
266
+ };
267
+ /** Parse a Portable Text array back into a Tiptap JSONContent document. */
268
+ export function portableTextToDoc(blocks) {
269
+ return { type: 'doc', content: parseBlocks(blocks) };
270
+ }
271
+ function parseBlocks(blocks) {
272
+ const out = [];
273
+ let index = 0;
274
+ while (index < blocks.length) {
275
+ const block = blocks[index];
276
+ if (block._type === 'block' && typeof block.listItem === 'string') {
277
+ const run = [];
278
+ while (index < blocks.length &&
279
+ blocks[index]._type === 'block' &&
280
+ typeof blocks[index].listItem === 'string') {
281
+ run.push(blocks[index]);
282
+ index += 1;
283
+ }
284
+ out.push(...buildListNodes(run));
285
+ continue;
286
+ }
287
+ if (block._type === 'block' && block.style === 'blockquote') {
288
+ const paragraphs = [];
289
+ while (index < blocks.length &&
290
+ blocks[index]._type === 'block' &&
291
+ blocks[index].style === 'blockquote' &&
292
+ typeof blocks[index].listItem !== 'string') {
293
+ paragraphs.push({ type: 'paragraph', content: parseInline(blocks[index]) });
294
+ index += 1;
295
+ }
296
+ out.push({ type: 'blockquote', content: paragraphs });
297
+ continue;
298
+ }
299
+ out.push(parseObject(block));
300
+ index += 1;
301
+ }
302
+ return out;
303
+ }
304
+ function parseObject(block) {
305
+ switch (block._type) {
306
+ case 'block': {
307
+ const style = block.style ?? 'normal';
308
+ const heading = /^h([1-6])$/.exec(style);
309
+ if (heading) {
310
+ return {
311
+ type: 'heading',
312
+ attrs: { level: Number(heading[1]) },
313
+ content: parseInline(block),
314
+ };
315
+ }
316
+ return { type: 'paragraph', content: parseInline(block) };
317
+ }
318
+ case 'code': {
319
+ const code = block.code ?? '';
320
+ return {
321
+ type: 'codeBlock',
322
+ attrs: { language: block.language ?? null },
323
+ content: code ? [{ type: 'text', text: code }] : [],
324
+ };
325
+ }
326
+ case 'image':
327
+ return {
328
+ type: 'image',
329
+ attrs: {
330
+ src: block.src ?? '',
331
+ alt: block.alt ?? '',
332
+ title: block.title ?? null,
333
+ },
334
+ };
335
+ case 'tweetEmbed':
336
+ return { type: 'tweetEmbed', attrs: { url: block.url ?? '' } };
337
+ case 'horizontalRule':
338
+ return { type: 'horizontalRule' };
339
+ case 'table':
340
+ return parseTable(block);
341
+ default:
342
+ throw new Error(`portableTextToDoc: unknown Portable Text _type "${block._type}" — the stored content is newer than this serializer`);
343
+ }
344
+ }
345
+ function buildListNodes(run) {
346
+ const roots = [];
347
+ const stack = [];
348
+ for (const block of run) {
349
+ const kind = block.listItem === 'number' ? 'number' : 'bullet';
350
+ const level = typeof block.level === 'number' && block.level > 0 ? block.level : 1;
351
+ const listType = kind === 'number' ? 'orderedList' : 'bulletList';
352
+ while (stack.length > 0 && stack[stack.length - 1].level > level)
353
+ stack.pop();
354
+ let top = stack[stack.length - 1];
355
+ if (top && top.level === level && top.kind !== kind) {
356
+ stack.pop();
357
+ top = stack[stack.length - 1];
358
+ }
359
+ if (!top || top.level < level) {
360
+ const list = { type: listType, content: [] };
361
+ if (top && top.level < level) {
362
+ const items = top.list.content ?? [];
363
+ const lastItem = items[items.length - 1];
364
+ if (lastItem) {
365
+ lastItem.content = [...(lastItem.content ?? []), list];
366
+ }
367
+ else {
368
+ roots.push(list);
369
+ }
370
+ }
371
+ else {
372
+ roots.push(list);
373
+ }
374
+ stack.push({ list, kind, level });
375
+ top = stack[stack.length - 1];
376
+ }
377
+ top.list.content = [
378
+ ...(top.list.content ?? []),
379
+ { type: 'listItem', content: [{ type: 'paragraph', content: parseInline(block) }] },
380
+ ];
381
+ }
382
+ return roots;
383
+ }
384
+ function parseInline(block) {
385
+ const markDefs = block.markDefs ?? [];
386
+ const out = [];
387
+ for (const child of block.children ?? []) {
388
+ if (child._type === 'span') {
389
+ out.push(...parseSpan(child, markDefs));
390
+ }
391
+ else if (child._type === 'image') {
392
+ out.push(parseObject(child));
393
+ }
394
+ else {
395
+ throw new Error(`portableTextToDoc: unknown inline Portable Text _type "${child._type}"`);
396
+ }
397
+ }
398
+ return out;
399
+ }
400
+ function parseSpan(span, markDefs) {
401
+ const marks = [];
402
+ for (const name of span.marks ?? []) {
403
+ const def = markDefs.find((candidate) => candidate._key === name);
404
+ if (def) {
405
+ if (def._type === 'link') {
406
+ marks.push({
407
+ type: 'link',
408
+ attrs: {
409
+ href: def.href ?? '',
410
+ title: def.title ?? null,
411
+ target: def.target ?? null,
412
+ },
413
+ });
414
+ }
415
+ // Unknown annotation types have no Tiptap node yet; drop the mark but
416
+ // keep the text.
417
+ continue;
418
+ }
419
+ const tiptapMark = TIPTAP_MARK_BY_DECORATOR[name];
420
+ if (tiptapMark)
421
+ marks.push({ type: tiptapMark });
422
+ }
423
+ const text = span.text ?? '';
424
+ const segments = text.split('\n');
425
+ const out = [];
426
+ segments.forEach((segment, index) => {
427
+ if (index > 0)
428
+ out.push({ type: 'hardBreak' });
429
+ if (segment !== '') {
430
+ const node = { type: 'text', text: segment };
431
+ if (marks.length > 0)
432
+ node.marks = marks.map((mark) => ({ ...mark }));
433
+ out.push(node);
434
+ }
435
+ });
436
+ return out;
437
+ }
438
+ function parseTable(block) {
439
+ const headerRows = typeof block.headerRows === 'number' ? block.headerRows : 0;
440
+ const rows = block.rows ?? [];
441
+ return {
442
+ type: 'table',
443
+ content: rows.map((row, rowIndex) => ({
444
+ type: 'tableRow',
445
+ content: (row.cells ?? []).map((cell) => {
446
+ const isHeader = rowIndex < headerRows || cell.header === true;
447
+ return {
448
+ type: isHeader ? 'tableHeader' : 'tableCell',
449
+ attrs: {
450
+ colspan: cell.colspan ?? 1,
451
+ rowspan: cell.rowspan ?? 1,
452
+ colwidth: cell.colwidth ?? null,
453
+ align: cell.align ?? null,
454
+ },
455
+ content: parseBlocks(cell.value ?? []),
456
+ };
457
+ }),
458
+ })),
459
+ };
460
+ }
461
+ //# sourceMappingURL=portable-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portable-text.js","sourceRoot":"","sources":["../../../src/ui/editor/portable-text.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/ui/editor/serialize.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAO/C,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAKtD;AA8JD,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAOrD"}
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/ui/editor/serialize.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAO/C,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAKtD;AA+LD,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAOrD"}
@@ -3,9 +3,10 @@
3
3
  // Operates exclusively on the ProseMirror JSONContent shape — no Editor,
4
4
  // no EditorView, no DOM, fully testable in vitest (Node env).
5
5
  //
6
- // Supported nodes (StarterKit set + TweetEmbed):
6
+ // Supported nodes (StarterKit set + TweetEmbed + tables):
7
7
  // block: doc, paragraph, heading (h1–h6), bulletList, orderedList,
8
- // listItem, blockquote, codeBlock, image, tweetEmbed, hardBreak
8
+ // listItem, blockquote, codeBlock, image, tweetEmbed, hardBreak,
9
+ // table (tableRow / tableHeader / tableCell)
9
10
  // inline marks: bold, italic, strike, code, link
10
11
  // (underline is retired: no markdown form exists — `_text_` is emphasis)
11
12
  //
@@ -18,6 +19,9 @@
18
19
  // ![alt](src) image
19
20
  // [text](href) link
20
21
  // :::tweet\n<url>\n::: tweet-embed directive
22
+ // | GFM | pipe | tables | (header row + `| --- |` separator; `\|` escapes a
23
+ // literal pipe; colspan/rowspan/colwidth/align do NOT survive markdown —
24
+ // Portable Text is the durable store, markdown is the derived lossy view)
21
25
  import { normalizeBoundaryMarks } from './trim-boundary-marks.js';
22
26
  // ─────────────────────────────────────────────────────────────────────────────
23
27
  // docToMarkdown — JSONContent → string
@@ -89,6 +93,9 @@ function serializeBlock(node) {
89
93
  case 'horizontalRule': {
90
94
  return '---';
91
95
  }
96
+ case 'table': {
97
+ return serializeTableMarkdown(node);
98
+ }
92
99
  default: {
93
100
  // Fall back to serializing any text content
94
101
  const fallback = serializeInlineContent(node.content ?? []);
@@ -135,6 +142,34 @@ function serializeListItem(item, bullet) {
135
142
  }
136
143
  return parts.join('\n');
137
144
  }
145
+ function serializeTableMarkdown(node) {
146
+ const rows = (node.content ?? []).filter((row) => row.type === 'tableRow');
147
+ if (rows.length === 0)
148
+ return '';
149
+ const cellText = (cell) => (cell.content ?? [])
150
+ .map((child) => serializeInlineContent(child.content ?? []))
151
+ .join(' ')
152
+ .replace(/\n/g, ' ')
153
+ .replace(/\|/g, '\\|');
154
+ const rowLine = (row) => `| ${(row.content ?? []).map(cellText).join(' | ')} |`;
155
+ const firstCells = rows[0].content ?? [];
156
+ const hasHeader = firstCells.length > 0 && firstCells.every((c) => c.type === 'tableHeader');
157
+ const columns = firstCells.length || 1;
158
+ const separator = `| ${Array.from({ length: columns }, () => '---').join(' | ')} |`;
159
+ const lines = [];
160
+ if (hasHeader) {
161
+ lines.push(rowLine(rows[0]), separator);
162
+ for (const row of rows.slice(1))
163
+ lines.push(rowLine(row));
164
+ }
165
+ else {
166
+ // GFM requires a header row; emit an empty one so body rows survive.
167
+ lines.push(`| ${Array.from({ length: columns }, () => '').join(' | ')} |`, separator);
168
+ for (const row of rows)
169
+ lines.push(rowLine(row));
170
+ }
171
+ return lines.join('\n');
172
+ }
138
173
  function serializeInlineContent(nodes) {
139
174
  return nodes.map((n) => serializeInlineNode(n)).join('');
140
175
  }
@@ -261,6 +296,13 @@ function parseBlocks(md) {
261
296
  i++;
262
297
  continue;
263
298
  }
299
+ // GFM pipe table (header row followed by a `| --- |` separator line)
300
+ if (isTableStart(lines, i)) {
301
+ const { node, next } = parseMarkdownTable(lines, i);
302
+ nodes.push(node);
303
+ i = next;
304
+ continue;
305
+ }
264
306
  // Bullet list
265
307
  if (/^[-*+]\s/.test(line)) {
266
308
  const { node, next } = parseBulletList(lines, i);
@@ -294,7 +336,8 @@ function parseBlocks(md) {
294
336
  !/^#{1,6}\s/.test(lines[i]) &&
295
337
  !/^[-*+]\s/.test(lines[i]) &&
296
338
  !/^\d+\.\s/.test(lines[i]) &&
297
- !/^---+$/.test(lines[i].trim())) {
339
+ !/^---+$/.test(lines[i].trim()) &&
340
+ !isTableStart(lines, i)) {
298
341
  paraLines.push(lines[i]);
299
342
  i++;
300
343
  }
@@ -305,6 +348,59 @@ function parseBlocks(md) {
305
348
  }
306
349
  return nodes;
307
350
  }
351
+ // ── Table parser ─────────────────────────────────────────────────────────────
352
+ function isTableStart(lines, index) {
353
+ if (!/^\|/.test(lines[index] ?? ''))
354
+ return false;
355
+ return /^\|(?:\s*:?-{3,}:?\s*\|)+\s*$/.test(lines[index + 1] ?? '');
356
+ }
357
+ function splitTableRow(line) {
358
+ let inner = line.trim();
359
+ if (inner.startsWith('|'))
360
+ inner = inner.slice(1);
361
+ if (inner.endsWith('|'))
362
+ inner = inner.slice(0, -1);
363
+ const cells = [];
364
+ let current = '';
365
+ for (let i = 0; i < inner.length; i++) {
366
+ const ch = inner[i];
367
+ if (ch === '\\' && inner[i + 1] === '|') {
368
+ current += '\\|';
369
+ i++;
370
+ continue;
371
+ }
372
+ if (ch === '|') {
373
+ cells.push(current);
374
+ current = '';
375
+ continue;
376
+ }
377
+ current += ch;
378
+ }
379
+ cells.push(current);
380
+ return cells.map((cell) => cell.trim().replace(/\\\|/g, '|'));
381
+ }
382
+ function parseMarkdownTable(lines, start) {
383
+ const makeCell = (kind, text) => ({
384
+ type: kind,
385
+ attrs: { colspan: 1, rowspan: 1, colwidth: null, align: null },
386
+ content: [{ type: 'paragraph', content: parseInline(text) }],
387
+ });
388
+ const rows = [
389
+ {
390
+ type: 'tableRow',
391
+ content: splitTableRow(lines[start]).map((text) => makeCell('tableHeader', text)),
392
+ },
393
+ ];
394
+ let i = start + 2; // skip the header row and the separator line
395
+ while (i < lines.length && /^\|/.test(lines[i])) {
396
+ rows.push({
397
+ type: 'tableRow',
398
+ content: splitTableRow(lines[i]).map((text) => makeCell('tableCell', text)),
399
+ });
400
+ i++;
401
+ }
402
+ return { node: { type: 'table', content: rows }, next: i };
403
+ }
308
404
  // ── List parsers ─────────────────────────────────────────────────────────────
309
405
  function parseBulletList(lines, start) {
310
406
  const items = [];