@portabletext/markdown 1.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,1098 @@
1
+ import { compileSchema, defineSchema, isTextBlock, isSpan } from "@portabletext/schema";
2
+ import { isPortableTextListItemBlock, isPortableTextToolkitSpan, isPortableTextBlock, isPortableTextToolkitTextNode, buildMarksTree, spanToPlainText } from "@portabletext/toolkit";
3
+ import markdownit from "markdown-it";
4
+ function defaultKeyGenerator() {
5
+ return randomKey(12);
6
+ }
7
+ const getByteHexTable = /* @__PURE__ */ (() => {
8
+ let table;
9
+ return () => {
10
+ if (table)
11
+ return table;
12
+ table = [];
13
+ for (let i = 0; i < 256; ++i)
14
+ table[i] = (i + 256).toString(16).slice(1);
15
+ return table;
16
+ };
17
+ })();
18
+ function whatwgRNG(length = 16) {
19
+ const rnds8 = new Uint8Array(length);
20
+ return crypto.getRandomValues(rnds8), rnds8;
21
+ }
22
+ function randomKey(length) {
23
+ const table = getByteHexTable();
24
+ return whatwgRNG(length).reduce((str, n) => str + table[n], "").slice(0, length);
25
+ }
26
+ const schema = compileSchema(defineSchema({}));
27
+ function buildListIndexMap(blocks) {
28
+ const levelIndexMaps = /* @__PURE__ */ new Map(), listIndexMap = /* @__PURE__ */ new Map();
29
+ let previousListItem;
30
+ for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) {
31
+ const block = blocks.at(blockIndex);
32
+ if (block === void 0)
33
+ continue;
34
+ if (block._key || (block._key = defaultKeyGenerator()), !isTextBlock({ schema }, block)) {
35
+ levelIndexMaps.clear(), previousListItem = void 0;
36
+ continue;
37
+ }
38
+ if (block.listItem === void 0 || block.level === void 0) {
39
+ levelIndexMaps.clear(), previousListItem = void 0;
40
+ continue;
41
+ }
42
+ if (!previousListItem) {
43
+ const levelIndexMap2 = levelIndexMaps.get(block.listItem) ?? /* @__PURE__ */ new Map();
44
+ levelIndexMap2.set(block.level, 1), levelIndexMaps.set(block.listItem, levelIndexMap2), listIndexMap.set(block._key, 1), previousListItem = {
45
+ listItem: block.listItem,
46
+ level: block.level
47
+ };
48
+ continue;
49
+ }
50
+ if (previousListItem.listItem === block.listItem && previousListItem.level < block.level) {
51
+ const levelIndexMap2 = levelIndexMaps.get(block.listItem) ?? /* @__PURE__ */ new Map();
52
+ levelIndexMap2.set(block.level, 1), levelIndexMaps.set(block.listItem, levelIndexMap2), listIndexMap.set(block._key, 1), previousListItem = {
53
+ listItem: block.listItem,
54
+ level: block.level
55
+ };
56
+ continue;
57
+ }
58
+ levelIndexMaps.forEach((levelIndexMap2, listItem) => {
59
+ if (listItem === block.listItem)
60
+ return;
61
+ const levelsToDelete = [];
62
+ levelIndexMap2.forEach((_, level) => {
63
+ level >= block.level && levelsToDelete.push(level);
64
+ }), levelsToDelete.forEach((level) => {
65
+ levelIndexMap2.delete(level);
66
+ });
67
+ });
68
+ const levelIndexMap = levelIndexMaps.get(block.listItem) ?? /* @__PURE__ */ new Map(), levelCounter = levelIndexMap.get(block.level) ?? 0;
69
+ levelIndexMap.set(block.level, levelCounter + 1), levelIndexMaps.set(block.listItem, levelIndexMap), listIndexMap.set(block._key, levelCounter + 1), previousListItem = {
70
+ listItem: block.listItem,
71
+ level: block.level
72
+ };
73
+ }
74
+ return listIndexMap;
75
+ }
76
+ const createRenderNode = (renderers, listIndexMap) => {
77
+ function renderNode(options) {
78
+ const { node, index, isInline } = options;
79
+ return isPortableTextListItemBlock(node) ? renderListItem(node, index) : isPortableTextToolkitSpan(node) ? renderSpan(node) : isPortableTextBlock(node) ? renderBlock(node, index, isInline) : isPortableTextToolkitTextNode(node) ? renderText(node) : renderCustomBlock(node, index, isInline);
80
+ }
81
+ function renderListItem(node, index) {
82
+ const renderer = renderers.listItem, itemHandler = (typeof renderer == "function" ? renderer : renderer[node.listItem]) || renderers.unknownListItem;
83
+ let children = buildMarksTree(node).map((child, i) => renderNode({ node: child, isInline: !0, index: i })).join("");
84
+ if (node.style && node.style !== "normal") {
85
+ const { listItem: _listItem, ...blockNode } = node;
86
+ children = renderNode({
87
+ node: blockNode,
88
+ index,
89
+ isInline: !1
90
+ }), children = children.replace(/\n+$/, "");
91
+ }
92
+ return itemHandler({
93
+ value: node,
94
+ index,
95
+ listIndex: node._key ? listIndexMap.get(node._key) : void 0,
96
+ isInline: !1,
97
+ renderNode,
98
+ children
99
+ });
100
+ }
101
+ function renderSpan(node) {
102
+ const { markDef, markType, markKey } = node, span = renderers.marks[markType] || renderers.unknownMark, children = node.children.map(
103
+ (child, childIndex) => renderNode({ node: child, index: childIndex, isInline: !0 })
104
+ );
105
+ return span({
106
+ text: spanToPlainText(node),
107
+ value: markDef,
108
+ markType,
109
+ markKey,
110
+ renderNode,
111
+ children: children.join("")
112
+ });
113
+ }
114
+ function renderBlock(node, index, isInline) {
115
+ const { _key, ...props } = serializeBlock({ node, index, isInline, renderNode }), style = props.node.style || "normal";
116
+ return ((typeof renderers.block == "function" ? renderers.block : renderers.block[style]) || renderers.unknownBlockStyle)({ ...props, value: props.node, renderNode });
117
+ }
118
+ function renderText(node) {
119
+ return node.text === `
120
+ ` ? renderers.hardBreak() : node.text;
121
+ }
122
+ function renderCustomBlock(value, index, isInline) {
123
+ return (renderers.types[value._type] ?? renderers.unknownType)({
124
+ value,
125
+ isInline,
126
+ index,
127
+ renderNode
128
+ });
129
+ }
130
+ return renderNode;
131
+ };
132
+ function serializeBlock(options) {
133
+ const { node, index, isInline, renderNode } = options, renderedChildren = buildMarksTree(node).map(
134
+ (child, i) => renderNode({ node: child, isInline: !0, index: i, renderNode })
135
+ );
136
+ return {
137
+ _key: node._key || defaultKeyGenerator(),
138
+ children: renderedChildren.join(""),
139
+ index,
140
+ isInline,
141
+ node
142
+ };
143
+ }
144
+ const DefaultBlockSpacingRenderer = ({
145
+ current,
146
+ next
147
+ }) => isPortableTextListItemBlock(current) && isPortableTextListItemBlock(next) ? `
148
+ ` : isPortableTextBlock(current) && isPortableTextBlock(next) && current.style === "blockquote" && next.style === "blockquote" ? `
149
+ >
150
+ ` : `
151
+
152
+ `, DefaultHardBreakRenderer = () => `
153
+ `, DefaultListItemRenderer = ({
154
+ children,
155
+ value,
156
+ listIndex
157
+ }) => {
158
+ const listStyle = value.listItem || "bullet", level = value.level || 1;
159
+ return listStyle === "number" ? `${" ".repeat(level - 1)}${listIndex ?? 1}. ${children}` : `${" ".repeat(level - 1)}- ${children}`;
160
+ }, DefaultUnknownListItemRenderer = ({
161
+ children
162
+ }) => `- ${children}
163
+ `, DefaultEmRenderer = ({ children }) => `_${children}_`, DefaultStrongRenderer = ({ children }) => `**${children}**`, DefaultCodeRenderer = ({ children }) => `\`${children}\``, DefaultUnderlineRenderer = ({
164
+ children
165
+ }) => `<u>${children}</u>`, DefaultStrikeThroughRenderer = ({
166
+ children
167
+ }) => `~~${children}~~`, DefaultLinkRenderer = ({
168
+ children,
169
+ value
170
+ }) => {
171
+ const href = value?.href || "", title = value?.title || "";
172
+ if (uriLooksSafe(href)) {
173
+ if (/["'][^"']*[<>]|[<>][^<>]*["']/.test(href)) {
174
+ const encodedHref = href.replace(/["<>() ]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
175
+ return `[${children}](${encodedHref})`;
176
+ }
177
+ return `[${children}](${href}${title ? ` "${title}"` : ""})`;
178
+ }
179
+ return children;
180
+ };
181
+ function uriLooksSafe(uri) {
182
+ const url = (uri || "").trim(), first = url.charAt(0);
183
+ if (first === "#" || first === "/")
184
+ return !0;
185
+ const colonIndex = url.indexOf(":");
186
+ if (colonIndex === -1)
187
+ return !0;
188
+ const allowedProtocols = ["http", "https", "mailto", "tel"], proto = url.slice(0, colonIndex).toLowerCase();
189
+ if (allowedProtocols.indexOf(proto) !== -1)
190
+ return !0;
191
+ const queryIndex = url.indexOf("?");
192
+ if (queryIndex !== -1 && colonIndex > queryIndex)
193
+ return !0;
194
+ const hashIndex = url.indexOf("#");
195
+ return hashIndex !== -1 && colonIndex > hashIndex;
196
+ }
197
+ const DefaultUnknownMarkRenderer = ({
198
+ children
199
+ }) => children, DefaultNormalRenderer = ({
200
+ children
201
+ }) => !children || children.trim() === "" ? "" : children, DefaultBlockquoteRenderer = ({
202
+ children
203
+ }) => children ? children.split(`
204
+ `).map((line) => `> ${line}`).join(`
205
+ `) : ">", DefaultH1Renderer = ({ children }) => `# ${children}`, DefaultH2Renderer = ({ children }) => `## ${children}`, DefaultH3Renderer = ({ children }) => `### ${children}`, DefaultH4Renderer = ({ children }) => `#### ${children}`, DefaultH5Renderer = ({ children }) => `##### ${children}`, DefaultH6Renderer = ({ children }) => `###### ${children}`, DefaultUnknownStyleRenderer = ({
206
+ children
207
+ }) => children ?? "", DefaultCodeBlockRenderer = ({ value }) => `\`\`\`${value.language ?? ""}
208
+ ${value.code}
209
+ \`\`\``, DefaultHorizontalRuleRenderer = () => "---", DefaultHtmlRenderer = ({ value }) => value.html, DefaultImageRenderer = ({ value }) => {
210
+ const alt = value.alt ?? "", title = value.title ? ` "${value.title}"` : "";
211
+ return `![${alt}](${value.src}${title})`;
212
+ }, DefaultTableRenderer = ({ value, renderNode }) => {
213
+ const headerRows = value.headerRows || 0, rows = value.rows, lines = [], getCellText = (cellBlocks) => cellBlocks.map(
214
+ (block, index) => renderNode({
215
+ node: block,
216
+ index,
217
+ isInline: !1,
218
+ renderNode
219
+ })
220
+ ).join(" ").trim();
221
+ for (let i = 0; i < headerRows; i++) {
222
+ const row = rows[i];
223
+ if (row) {
224
+ const cellTexts = row.cells.map((cell) => getCellText(cell.value));
225
+ lines.push(`| ${cellTexts.join(" | ")} |`);
226
+ }
227
+ }
228
+ if (headerRows > 0 && rows[0]) {
229
+ const separators = rows[0].cells.map(() => " --- ");
230
+ lines.push(`|${separators.join("|")}|`);
231
+ }
232
+ for (let i = headerRows; i < rows.length; i++) {
233
+ const row = rows[i];
234
+ if (row) {
235
+ const cellTexts = row.cells.map((cell) => getCellText(cell.value));
236
+ lines.push(`| ${cellTexts.join(" | ")} |`);
237
+ }
238
+ }
239
+ return lines.join(`
240
+ `);
241
+ }, DefaultUnknownTypeRenderer = ({
242
+ value,
243
+ isInline
244
+ }) => {
245
+ const json = `\`\`\`json
246
+ ${JSON.stringify(value, null, 2)}
247
+ \`\`\``;
248
+ return isInline ? `
249
+ ${json}
250
+ ` : json;
251
+ }, defaultRenderers = {
252
+ types: {},
253
+ block: {
254
+ normal: DefaultNormalRenderer,
255
+ blockquote: DefaultBlockquoteRenderer,
256
+ h1: DefaultH1Renderer,
257
+ h2: DefaultH2Renderer,
258
+ h3: DefaultH3Renderer,
259
+ h4: DefaultH4Renderer,
260
+ h5: DefaultH5Renderer,
261
+ h6: DefaultH6Renderer
262
+ },
263
+ marks: {
264
+ em: DefaultEmRenderer,
265
+ strong: DefaultStrongRenderer,
266
+ code: DefaultCodeRenderer,
267
+ underline: DefaultUnderlineRenderer,
268
+ "strike-through": DefaultStrikeThroughRenderer,
269
+ link: DefaultLinkRenderer
270
+ },
271
+ listItem: DefaultListItemRenderer,
272
+ hardBreak: DefaultHardBreakRenderer,
273
+ unknownType: DefaultUnknownTypeRenderer,
274
+ unknownMark: DefaultUnknownMarkRenderer,
275
+ unknownListItem: DefaultUnknownListItemRenderer,
276
+ unknownBlockStyle: DefaultUnknownStyleRenderer
277
+ };
278
+ function portableTextToMarkdown(blocks, options = {}) {
279
+ const renderers = {
280
+ block: {
281
+ ...defaultRenderers.block,
282
+ ...options.block
283
+ },
284
+ listItem: options.listItem ?? defaultRenderers.listItem,
285
+ marks: {
286
+ ...defaultRenderers.marks,
287
+ ...options.marks
288
+ },
289
+ types: {
290
+ ...defaultRenderers.types,
291
+ ...options.types
292
+ },
293
+ hardBreak: options.hardBreak ?? defaultRenderers.hardBreak,
294
+ unknownType: options.unknownType ?? defaultRenderers.unknownType,
295
+ unknownBlockStyle: options.unknownBlockStyle ?? defaultRenderers.unknownBlockStyle,
296
+ unknownListItem: options.unknownListItem ?? defaultRenderers.unknownListItem,
297
+ unknownMark: options.unknownMark ?? defaultRenderers.unknownMark
298
+ }, renderBlockSpacing = options.blockSpacing ?? DefaultBlockSpacingRenderer, listIndexMap = buildListIndexMap(blocks), renderNode = createRenderNode(renderers, listIndexMap);
299
+ return blocks.map((node, index) => {
300
+ const renderedNode = renderNode({
301
+ node,
302
+ index,
303
+ isInline: !1,
304
+ renderNode
305
+ });
306
+ if (index === blocks.length - 1)
307
+ return renderedNode;
308
+ const nextNode = blocks.at(index + 1);
309
+ if (!nextNode)
310
+ return renderedNode;
311
+ const blockSpacing = renderBlockSpacing({
312
+ current: node,
313
+ next: nextNode
314
+ }) ?? `
315
+
316
+ `;
317
+ return `${renderedNode}${blockSpacing}`;
318
+ }).join("");
319
+ }
320
+ const normalStyleDefinition = {
321
+ name: "normal"
322
+ }, h1StyleDefinition = {
323
+ name: "h1"
324
+ }, h2StyleDefinition = {
325
+ name: "h2"
326
+ }, h3StyleDefinition = {
327
+ name: "h3"
328
+ }, h4StyleDefinition = {
329
+ name: "h4"
330
+ }, h5StyleDefinition = {
331
+ name: "h5"
332
+ }, h6StyleDefinition = {
333
+ name: "h6"
334
+ }, blockquoteStyleDefinition = {
335
+ name: "blockquote"
336
+ }, defaultOrderedListItemDefinition = {
337
+ name: "number"
338
+ }, defaultUnorderedListItemDefinition = {
339
+ name: "bullet"
340
+ }, defaultStrongDecoratorDefinition = {
341
+ name: "strong"
342
+ }, defaultEmDecoratorDefinition = {
343
+ name: "em"
344
+ }, defaultCodeDecoratorDefinition = {
345
+ name: "code"
346
+ }, defaultStrikeThroughDecoratorDefinition = {
347
+ name: "strike-through"
348
+ }, defaultLinkObjectDefinition = {
349
+ name: "link",
350
+ fields: [
351
+ { name: "href", type: "string" },
352
+ { name: "title", type: "string" }
353
+ ]
354
+ }, defaultCodeObjectDefinition = {
355
+ name: "code",
356
+ fields: [
357
+ { name: "language", type: "string" },
358
+ { name: "code", type: "string" }
359
+ ]
360
+ }, defaultImageObjectDefinition = {
361
+ name: "image",
362
+ fields: [
363
+ { name: "src", type: "string" },
364
+ { name: "alt", type: "string" },
365
+ { name: "title", type: "string" }
366
+ ]
367
+ }, defaultHorizontalRuleObjectDefinition = {
368
+ name: "horizontal-rule"
369
+ }, defaultHtmlObjectDefinition = {
370
+ name: "html",
371
+ fields: [{ name: "html", type: "string" }]
372
+ }, defaultTableObjectDefinition = {
373
+ name: "table",
374
+ fields: [
375
+ { name: "headerRows", type: "number" },
376
+ { name: "rows", type: "array" }
377
+ ]
378
+ }, defaultSchema = compileSchema(
379
+ defineSchema({
380
+ styles: [
381
+ normalStyleDefinition,
382
+ h1StyleDefinition,
383
+ h2StyleDefinition,
384
+ h3StyleDefinition,
385
+ h4StyleDefinition,
386
+ h5StyleDefinition,
387
+ h6StyleDefinition,
388
+ blockquoteStyleDefinition
389
+ ],
390
+ lists: [
391
+ defaultOrderedListItemDefinition,
392
+ defaultUnorderedListItemDefinition
393
+ ],
394
+ decorators: [
395
+ defaultStrongDecoratorDefinition,
396
+ defaultEmDecoratorDefinition,
397
+ defaultCodeDecoratorDefinition,
398
+ defaultStrikeThroughDecoratorDefinition
399
+ ],
400
+ annotations: [defaultLinkObjectDefinition],
401
+ blockObjects: [
402
+ defaultCodeObjectDefinition,
403
+ defaultHorizontalRuleObjectDefinition,
404
+ defaultImageObjectDefinition,
405
+ defaultHtmlObjectDefinition,
406
+ defaultTableObjectDefinition
407
+ ],
408
+ inlineObjects: [defaultImageObjectDefinition]
409
+ })
410
+ );
411
+ function buildStyleMatcher(definition) {
412
+ return ({ context }) => {
413
+ const schemaDefinition = context.schema.styles.find(
414
+ (item) => item.name === definition.name
415
+ );
416
+ if (schemaDefinition)
417
+ return schemaDefinition.name;
418
+ };
419
+ }
420
+ function buildListItemMatcher(definition) {
421
+ return ({ context }) => {
422
+ const schemaDefinition = context.schema.lists.find(
423
+ (item) => item.name === definition.name
424
+ );
425
+ if (schemaDefinition)
426
+ return schemaDefinition.name;
427
+ };
428
+ }
429
+ function buildDecoratorMatcher(definition) {
430
+ return ({ context }) => {
431
+ const schemaDefinition = context.schema.decorators.find(
432
+ (item) => item.name === definition.name
433
+ );
434
+ if (schemaDefinition)
435
+ return schemaDefinition.name;
436
+ };
437
+ }
438
+ function buildAnnotationMatcher(definition) {
439
+ return ({ context, value }) => {
440
+ const schemaDefinition = context.schema.annotations.find(
441
+ (item) => item.name === definition.name
442
+ );
443
+ if (!schemaDefinition)
444
+ return;
445
+ const filteredValue = schemaDefinition.fields.reduce((filteredValue2, field) => {
446
+ const fieldValue = value[field.name];
447
+ return fieldValue !== void 0 && (filteredValue2[field.name] = fieldValue), filteredValue2;
448
+ }, {});
449
+ return {
450
+ _key: context.keyGenerator(),
451
+ _type: schemaDefinition.name,
452
+ ...filteredValue
453
+ };
454
+ };
455
+ }
456
+ function buildObjectMatcher(definition) {
457
+ return ({ context, value, isInline }) => {
458
+ const schemaDefinition = (isInline ? context.schema.inlineObjects : context.schema.blockObjects).find(
459
+ (item) => item.name === definition.name
460
+ );
461
+ if (!schemaDefinition)
462
+ return;
463
+ const filteredValue = schemaDefinition.fields.reduce((filteredValue2, field) => {
464
+ const fieldValue = value[field.name];
465
+ return fieldValue !== void 0 && (filteredValue2[field.name] = fieldValue), filteredValue2;
466
+ }, {});
467
+ return {
468
+ _key: context.keyGenerator(),
469
+ _type: schemaDefinition.name,
470
+ ...filteredValue
471
+ };
472
+ };
473
+ }
474
+ const codeBlockMatcher = ({ context, value, isInline }) => {
475
+ const codeObject = buildObjectMatcher(defaultCodeObjectDefinition)({ context, value, isInline });
476
+ if (codeObject && "code" in codeObject)
477
+ return codeObject;
478
+ }, imageBlockMatcher = ({ context, value, isInline }) => {
479
+ const imageObject = buildObjectMatcher(defaultImageObjectDefinition)({ context, value, isInline });
480
+ if (imageObject && "src" in imageObject)
481
+ return imageObject;
482
+ }, defaultOptions = {
483
+ block: {
484
+ normal: buildStyleMatcher(normalStyleDefinition),
485
+ blockquote: buildStyleMatcher(blockquoteStyleDefinition),
486
+ h1: buildStyleMatcher(h1StyleDefinition),
487
+ h2: buildStyleMatcher(h2StyleDefinition),
488
+ h3: buildStyleMatcher(h3StyleDefinition),
489
+ h4: buildStyleMatcher(h4StyleDefinition),
490
+ h5: buildStyleMatcher(h5StyleDefinition),
491
+ h6: buildStyleMatcher(h6StyleDefinition)
492
+ },
493
+ listItem: {
494
+ number: buildListItemMatcher(defaultOrderedListItemDefinition),
495
+ bullet: buildListItemMatcher(defaultUnorderedListItemDefinition)
496
+ },
497
+ marks: {
498
+ strong: buildDecoratorMatcher(defaultStrongDecoratorDefinition),
499
+ em: buildDecoratorMatcher(defaultEmDecoratorDefinition),
500
+ code: buildDecoratorMatcher(defaultCodeDecoratorDefinition),
501
+ strikeThrough: buildDecoratorMatcher(
502
+ defaultStrikeThroughDecoratorDefinition
503
+ ),
504
+ link: buildAnnotationMatcher(defaultLinkObjectDefinition)
505
+ },
506
+ types: {
507
+ code: codeBlockMatcher,
508
+ horizontalRule: buildObjectMatcher(defaultHorizontalRuleObjectDefinition),
509
+ html: buildObjectMatcher(defaultHtmlObjectDefinition),
510
+ image: imageBlockMatcher
511
+ }
512
+ };
513
+ function flattenTable(table, portableText) {
514
+ for (const row of table.rows)
515
+ for (const cell of row.cells)
516
+ for (const block of cell.value)
517
+ portableText.push(block);
518
+ }
519
+ function markdownToPortableText(markdown, options) {
520
+ const consolidatedOptions = {
521
+ schema: options?.schema ?? defaultSchema,
522
+ keyGenerator: options?.keyGenerator ?? defaultKeyGenerator,
523
+ html: {
524
+ inline: options?.html?.inline ?? "skip"
525
+ },
526
+ marks: {
527
+ ...defaultOptions.marks,
528
+ ...options?.marks
529
+ },
530
+ block: {
531
+ ...defaultOptions.block,
532
+ ...options?.block
533
+ },
534
+ listItem: {
535
+ ...defaultOptions.listItem,
536
+ ...options?.listItem
537
+ },
538
+ types: {
539
+ ...defaultOptions.types,
540
+ ...options?.types
541
+ }
542
+ }, tokens = markdownit({
543
+ html: !0,
544
+ linkify: !0,
545
+ typographer: !1
546
+ }).enable(["strikethrough", "table"]).parse(markdown, {}), portableText = [];
547
+ let currentBlock = null;
548
+ const currentListStack = [], markDefRefs = [];
549
+ let currentMarkDefs = [], currentBlockquoteStyle = null, inListItem = !1, currentTable = null, currentTableRow = null, inTableHead = !1;
550
+ const startBlock = (style) => {
551
+ flushBlock(), currentBlock = {
552
+ _type: "block",
553
+ style,
554
+ children: [],
555
+ _key: consolidatedOptions.keyGenerator(),
556
+ markDefs: []
557
+ }, currentMarkDefs = [];
558
+ }, flushBlock = () => {
559
+ currentBlock && (currentBlock.children.length === 0 && currentBlock.children.push({
560
+ _type: consolidatedOptions.schema.span.name,
561
+ _key: consolidatedOptions.keyGenerator(),
562
+ text: "",
563
+ marks: []
564
+ }), currentBlock.markDefs = currentMarkDefs, portableText.push(currentBlock), currentBlock = null, currentMarkDefs = []);
565
+ }, addSpan = (text) => {
566
+ if (text.length === 0)
567
+ return;
568
+ if (!currentBlock)
569
+ throw new Error("Expected current block");
570
+ const lastChild = currentBlock.children.at(-1);
571
+ isSpan({ schema: consolidatedOptions.schema }, lastChild) && lastChild.marks?.every((mark) => markDefRefs.includes(mark)) && markDefRefs.every((mark) => lastChild.marks?.includes(mark)) ? lastChild.text += text : currentBlock.children.push({
572
+ _type: consolidatedOptions.schema.span.name,
573
+ _key: consolidatedOptions.keyGenerator(),
574
+ text,
575
+ marks: [...markDefRefs]
576
+ });
577
+ }, listLevel = () => currentListStack.length, ensureListBlock = (listItem) => {
578
+ if (!currentBlock) {
579
+ const style = currentBlockquoteStyle ?? consolidatedOptions.block.normal({
580
+ context: { schema: consolidatedOptions.schema }
581
+ });
582
+ style ? startBlock(style) : (console.warn('No default style found, using "normal"'), startBlock("normal"));
583
+ }
584
+ if (!currentBlock)
585
+ throw new Error("Expected current block");
586
+ (currentBlock.listItem !== listItem || currentBlock.level !== listLevel()) && (currentBlock.listItem = listItem, currentBlock.level = listLevel());
587
+ };
588
+ for (const token of tokens)
589
+ switch (token.type) {
590
+ // Paragraphs
591
+ case "paragraph_open": {
592
+ if (inListItem)
593
+ break;
594
+ const style = currentBlockquoteStyle ?? consolidatedOptions.block.normal({
595
+ context: { schema: consolidatedOptions.schema }
596
+ });
597
+ if (!style) {
598
+ console.warn('No default style found, using "normal"'), startBlock("normal");
599
+ break;
600
+ }
601
+ startBlock(style);
602
+ break;
603
+ }
604
+ case "paragraph_close":
605
+ if (inListItem)
606
+ break;
607
+ flushBlock();
608
+ break;
609
+ // Headings
610
+ case "heading_open": {
611
+ const level = Number(token?.tag?.slice(1)), headingMatcher = {
612
+ 1: consolidatedOptions.block.h1,
613
+ 2: consolidatedOptions.block.h2,
614
+ 3: consolidatedOptions.block.h3,
615
+ 4: consolidatedOptions.block.h4,
616
+ 5: consolidatedOptions.block.h5,
617
+ 6: consolidatedOptions.block.h6
618
+ }[level], style = headingMatcher?.({
619
+ context: { schema: consolidatedOptions.schema }
620
+ }) ?? consolidatedOptions.block.normal({
621
+ context: { schema: consolidatedOptions.schema }
622
+ });
623
+ if (!style) {
624
+ console.warn('No heading style found, using "normal"'), startBlock("normal");
625
+ break;
626
+ }
627
+ startBlock(style);
628
+ break;
629
+ }
630
+ case "heading_close":
631
+ flushBlock();
632
+ break;
633
+ // Blockquote
634
+ case "blockquote_open": {
635
+ currentBlockquoteStyle = consolidatedOptions.block.blockquote({
636
+ context: { schema: consolidatedOptions.schema }
637
+ }) ?? consolidatedOptions.block.normal({
638
+ context: { schema: consolidatedOptions.schema }
639
+ }) ?? "normal";
640
+ break;
641
+ }
642
+ case "blockquote_close": {
643
+ currentBlockquoteStyle = null;
644
+ break;
645
+ }
646
+ // Lists
647
+ case "bullet_list_open": {
648
+ const listItem = consolidatedOptions.listItem.bullet({
649
+ context: { schema: consolidatedOptions.schema }
650
+ });
651
+ if (!listItem) {
652
+ currentListStack.push(null);
653
+ break;
654
+ }
655
+ currentListStack.push(listItem);
656
+ break;
657
+ }
658
+ case "ordered_list_open": {
659
+ const listItem = consolidatedOptions.listItem.number({
660
+ context: { schema: consolidatedOptions.schema }
661
+ });
662
+ if (!listItem) {
663
+ currentListStack.push(null);
664
+ break;
665
+ }
666
+ currentListStack.push(listItem);
667
+ break;
668
+ }
669
+ case "bullet_list_close":
670
+ case "ordered_list_close":
671
+ currentListStack.pop();
672
+ break;
673
+ case "list_item_open": {
674
+ const listType = currentListStack.at(-1);
675
+ if (listType === void 0)
676
+ throw new Error("Expected an open list");
677
+ if (currentBlock && flushBlock(), listType === null) {
678
+ const style = currentBlockquoteStyle ?? consolidatedOptions.block.normal({
679
+ context: { schema: consolidatedOptions.schema }
680
+ });
681
+ style ? startBlock(style) : (console.warn('No default style found, using "normal"'), startBlock("normal")), inListItem = !0;
682
+ break;
683
+ }
684
+ ensureListBlock(listType), inListItem = !0;
685
+ break;
686
+ }
687
+ case "list_item_close":
688
+ inListItem = !1, flushBlock();
689
+ break;
690
+ // Code fences / blocks
691
+ case "fence": {
692
+ flushBlock();
693
+ const language = token.info.trim() || void 0, code = token.content.replace(/\n$/, ""), codeObject = consolidatedOptions.types.code({
694
+ context: {
695
+ schema: consolidatedOptions.schema,
696
+ keyGenerator: consolidatedOptions.keyGenerator
697
+ },
698
+ value: { language, code },
699
+ isInline: !1
700
+ });
701
+ if (!codeObject) {
702
+ if (code.includes(`
703
+ `))
704
+ portableText.push({
705
+ _type: "code",
706
+ _key: consolidatedOptions.keyGenerator(),
707
+ code
708
+ });
709
+ else {
710
+ const style = consolidatedOptions.block.normal({
711
+ context: { schema: consolidatedOptions.schema }
712
+ });
713
+ style ? startBlock(style) : (console.warn('No default style found, using "normal"'), startBlock("normal")), addSpan(code);
714
+ }
715
+ break;
716
+ }
717
+ portableText.push(codeObject);
718
+ break;
719
+ }
720
+ // Horizontal rule
721
+ case "hr": {
722
+ flushBlock();
723
+ const hrObject = consolidatedOptions.types.horizontalRule({
724
+ context: {
725
+ schema: consolidatedOptions.schema,
726
+ keyGenerator: consolidatedOptions.keyGenerator
727
+ },
728
+ value: {},
729
+ isInline: !1
730
+ });
731
+ if (!hrObject) {
732
+ const style = consolidatedOptions.block.normal({
733
+ context: { schema: consolidatedOptions.schema }
734
+ });
735
+ style ? startBlock(style) : (console.warn('No default style found, using "normal"'), startBlock("normal")), addSpan("---"), flushBlock();
736
+ break;
737
+ }
738
+ portableText.push(hrObject);
739
+ break;
740
+ }
741
+ // HTML block
742
+ case "html_block": {
743
+ flushBlock();
744
+ const htmlContent = token.content.trim();
745
+ if (!htmlContent)
746
+ break;
747
+ const htmlObject = consolidatedOptions.types.html({
748
+ context: {
749
+ schema: consolidatedOptions.schema,
750
+ keyGenerator: consolidatedOptions.keyGenerator
751
+ },
752
+ value: { html: htmlContent },
753
+ isInline: !1
754
+ });
755
+ if (!htmlObject) {
756
+ const style = consolidatedOptions.block.normal({
757
+ context: { schema: consolidatedOptions.schema }
758
+ });
759
+ style ? startBlock(style) : (console.warn('No default style found, using "normal"'), startBlock("normal")), addSpan(htmlContent), flushBlock();
760
+ break;
761
+ }
762
+ portableText.push(htmlObject);
763
+ break;
764
+ }
765
+ case "code_block": {
766
+ flushBlock();
767
+ const code = token.content.replace(/\n$/, ""), codeObject = consolidatedOptions.types.code({
768
+ context: {
769
+ schema: consolidatedOptions.schema,
770
+ keyGenerator: consolidatedOptions.keyGenerator
771
+ },
772
+ value: { language: void 0, code },
773
+ isInline: !1
774
+ });
775
+ if (codeObject)
776
+ portableText.push(codeObject);
777
+ else if (code.includes(`
778
+ `))
779
+ portableText.push({
780
+ _type: "code",
781
+ _key: consolidatedOptions.keyGenerator(),
782
+ code
783
+ });
784
+ else {
785
+ const style = consolidatedOptions.block.normal({
786
+ context: { schema: consolidatedOptions.schema }
787
+ });
788
+ style ? startBlock(style) : (console.warn('No default style found, using "normal"'), startBlock("normal")), addSpan(code);
789
+ }
790
+ break;
791
+ }
792
+ // Tables
793
+ case "table_open":
794
+ flushBlock(), currentTable = { rows: [], headerRows: 0 };
795
+ break;
796
+ case "table_close": {
797
+ if (!currentTable)
798
+ break;
799
+ if (consolidatedOptions.types.table) {
800
+ const tableObject = consolidatedOptions.types.table({
801
+ context: {
802
+ schema: consolidatedOptions.schema,
803
+ keyGenerator: consolidatedOptions.keyGenerator
804
+ },
805
+ value: {
806
+ rows: currentTable.rows,
807
+ headerRows: currentTable.headerRows > 0 ? currentTable.headerRows : void 0
808
+ },
809
+ isInline: !1
810
+ });
811
+ tableObject ? portableText.push(tableObject) : flattenTable(currentTable, portableText);
812
+ } else
813
+ flattenTable(currentTable, portableText);
814
+ currentTable = null;
815
+ break;
816
+ }
817
+ case "thead_open":
818
+ inTableHead = !0;
819
+ break;
820
+ case "thead_close":
821
+ inTableHead = !1;
822
+ break;
823
+ case "tbody_open":
824
+ case "tbody_close":
825
+ break;
826
+ case "tr_open":
827
+ currentTableRow = [];
828
+ break;
829
+ case "tr_close":
830
+ currentTable && currentTableRow && (currentTable.rows.push({
831
+ _key: consolidatedOptions.keyGenerator(),
832
+ _type: "row",
833
+ cells: currentTableRow
834
+ }), inTableHead && currentTable.headerRows++), currentTableRow = null;
835
+ break;
836
+ case "th_open":
837
+ case "td_open": {
838
+ const style = consolidatedOptions.block.normal({
839
+ context: { schema: consolidatedOptions.schema }
840
+ });
841
+ style ? startBlock(style) : (console.warn('No default style found, using "normal"'), startBlock("normal"));
842
+ break;
843
+ }
844
+ case "th_close":
845
+ case "td_close": {
846
+ flushBlock();
847
+ const cellBlocks = [];
848
+ if (portableText.length > 0) {
849
+ const lastBlock = portableText.at(-1);
850
+ lastBlock && lastBlock._type === "block" && cellBlocks.push(portableText.pop());
851
+ }
852
+ cellBlocks.length === 0 && cellBlocks.push({
853
+ _type: "block",
854
+ style: consolidatedOptions.block.normal({
855
+ context: { schema: consolidatedOptions.schema }
856
+ }) || "normal",
857
+ children: [
858
+ {
859
+ _type: consolidatedOptions.schema.span.name,
860
+ _key: consolidatedOptions.keyGenerator(),
861
+ text: "",
862
+ marks: []
863
+ }
864
+ ],
865
+ _key: consolidatedOptions.keyGenerator(),
866
+ markDefs: []
867
+ });
868
+ const firstBlock = cellBlocks[0];
869
+ if (cellBlocks.length === 1 && firstBlock && firstBlock._type === "block" && "children" in firstBlock && Array.isArray(firstBlock.children) && firstBlock.children.length === 1) {
870
+ const onlyChild = firstBlock.children[0];
871
+ typeof onlyChild == "object" && onlyChild !== null && "_type" in onlyChild && onlyChild._type !== consolidatedOptions.schema.span.name && onlyChild._type === "image" && (cellBlocks[0] = onlyChild);
872
+ }
873
+ currentTableRow !== null && currentTableRow.push({
874
+ _type: "cell",
875
+ _key: consolidatedOptions.keyGenerator(),
876
+ value: cellBlocks
877
+ });
878
+ break;
879
+ }
880
+ // Inline container
881
+ case "inline": {
882
+ const inTableCell = currentTableRow !== null;
883
+ if (token.children?.length === 1 && token.children[0]?.type === "image") {
884
+ const imageToken = token.children[0];
885
+ if (!imageToken)
886
+ break;
887
+ const src = imageToken.attrs?.find(([name]) => name === "src")?.at(1) || "", alt = imageToken.content || "", title = imageToken.attrs?.find(([name]) => name === "title")?.at(1) || void 0, blockImageObject = consolidatedOptions.types.image({
888
+ context: {
889
+ schema: consolidatedOptions.schema,
890
+ keyGenerator: consolidatedOptions.keyGenerator
891
+ },
892
+ value: { src, alt, title },
893
+ isInline: !1
894
+ });
895
+ if (blockImageObject) {
896
+ inTableCell ? currentBlock && "children" in currentBlock && currentBlock.children.push(
897
+ blockImageObject
898
+ ) : (currentBlock = null, currentMarkDefs = [], portableText.push(blockImageObject));
899
+ break;
900
+ }
901
+ addSpan(`![${alt}](${src})`);
902
+ break;
903
+ }
904
+ for (const childToken of token.children ?? [])
905
+ switch (childToken.type) {
906
+ case "text":
907
+ addSpan(childToken.content);
908
+ break;
909
+ case "softbreak":
910
+ case "hardbreak":
911
+ addSpan(`
912
+ `);
913
+ break;
914
+ case "code_inline": {
915
+ const decorator = consolidatedOptions.marks.code({
916
+ context: { schema: consolidatedOptions.schema }
917
+ });
918
+ if (!decorator) {
919
+ addSpan(childToken.content);
920
+ break;
921
+ }
922
+ markDefRefs.push(decorator), addSpan(childToken.content);
923
+ const index = markDefRefs.lastIndexOf(decorator);
924
+ index !== -1 && markDefRefs.splice(index, 1);
925
+ break;
926
+ }
927
+ case "strong_open": {
928
+ const decorator = consolidatedOptions.marks.strong({
929
+ context: { schema: consolidatedOptions.schema }
930
+ });
931
+ if (!decorator)
932
+ break;
933
+ markDefRefs.push(decorator);
934
+ break;
935
+ }
936
+ case "strong_close": {
937
+ const decorator = consolidatedOptions.marks.strong({
938
+ context: { schema: consolidatedOptions.schema }
939
+ });
940
+ if (!decorator)
941
+ break;
942
+ const index = markDefRefs.lastIndexOf(decorator);
943
+ index !== -1 && markDefRefs.splice(index, 1);
944
+ break;
945
+ }
946
+ case "em_open": {
947
+ const decorator = consolidatedOptions.marks.em({
948
+ context: { schema: consolidatedOptions.schema }
949
+ });
950
+ if (!decorator)
951
+ break;
952
+ markDefRefs.push(decorator);
953
+ break;
954
+ }
955
+ case "em_close": {
956
+ const decorator = consolidatedOptions.marks.em({
957
+ context: { schema: consolidatedOptions.schema }
958
+ });
959
+ if (!decorator)
960
+ break;
961
+ const index = markDefRefs.lastIndexOf(decorator);
962
+ index !== -1 && markDefRefs.splice(index, 1);
963
+ break;
964
+ }
965
+ case "s_open": {
966
+ const decorator = consolidatedOptions.marks.strikeThrough({
967
+ context: { schema: consolidatedOptions.schema }
968
+ });
969
+ if (!decorator)
970
+ break;
971
+ markDefRefs.push(decorator);
972
+ break;
973
+ }
974
+ case "s_close": {
975
+ const decorator = consolidatedOptions.marks.strikeThrough({
976
+ context: { schema: consolidatedOptions.schema }
977
+ });
978
+ if (!decorator)
979
+ break;
980
+ const index = markDefRefs.lastIndexOf(decorator);
981
+ index !== -1 && markDefRefs.splice(index, 1);
982
+ break;
983
+ }
984
+ case "link_open": {
985
+ const href = childToken.attrs?.find(([name]) => name === "href")?.at(1);
986
+ if (!href)
987
+ break;
988
+ const title = childToken.attrs?.find(([name]) => name === "title")?.at(1), linkObject = consolidatedOptions.marks.link({
989
+ context: {
990
+ schema: consolidatedOptions.schema,
991
+ keyGenerator: consolidatedOptions.keyGenerator
992
+ },
993
+ value: { href, title }
994
+ });
995
+ if (!linkObject)
996
+ break;
997
+ currentMarkDefs.push(linkObject), markDefRefs.push(linkObject._key);
998
+ break;
999
+ }
1000
+ case "link_close": {
1001
+ const markDefKeys = new Set(currentMarkDefs.map((d) => d._key));
1002
+ let lastLinkIndex;
1003
+ for (const markDefRef of markDefRefs.reverse())
1004
+ if (markDefKeys.has(markDefRef)) {
1005
+ lastLinkIndex = markDefRefs.indexOf(markDefRef);
1006
+ break;
1007
+ }
1008
+ if (lastLinkIndex !== void 0) {
1009
+ const realIndex = markDefRefs.length - 1 - lastLinkIndex;
1010
+ markDefRefs.splice(realIndex, 1);
1011
+ }
1012
+ break;
1013
+ }
1014
+ case "image": {
1015
+ const src = childToken.attrs?.find(([name]) => name === "src")?.at(1) || "", alt = childToken.content || "", inlineImageObject = consolidatedOptions.types.image({
1016
+ context: {
1017
+ schema: consolidatedOptions.schema,
1018
+ keyGenerator: consolidatedOptions.keyGenerator
1019
+ },
1020
+ value: { src, alt, title: void 0 },
1021
+ isInline: !0
1022
+ });
1023
+ if (inlineImageObject) {
1024
+ if (!currentBlock) {
1025
+ const style2 = consolidatedOptions.block.normal({
1026
+ context: { schema: consolidatedOptions.schema }
1027
+ });
1028
+ style2 ? startBlock(style2) : (console.warn('No default style found, using "normal"'), startBlock("normal"));
1029
+ }
1030
+ if (!currentBlock)
1031
+ throw new Error("Expected current block after startBlock");
1032
+ currentBlock.children.push(
1033
+ inlineImageObject
1034
+ );
1035
+ break;
1036
+ }
1037
+ const blockImageObject = consolidatedOptions.types.image({
1038
+ context: {
1039
+ schema: consolidatedOptions.schema,
1040
+ keyGenerator: consolidatedOptions.keyGenerator
1041
+ },
1042
+ value: { src, alt, title: void 0 },
1043
+ isInline: !1
1044
+ });
1045
+ if (!blockImageObject) {
1046
+ addSpan(`![${alt}](${src})`);
1047
+ break;
1048
+ }
1049
+ if (inTableCell) {
1050
+ currentBlock && "children" in currentBlock && currentBlock.children.push(
1051
+ blockImageObject
1052
+ );
1053
+ break;
1054
+ }
1055
+ flushBlock(), portableText.push(blockImageObject);
1056
+ const style = consolidatedOptions.block.normal({
1057
+ context: { schema: consolidatedOptions.schema }
1058
+ });
1059
+ style && startBlock(style);
1060
+ break;
1061
+ }
1062
+ case "html_inline": {
1063
+ consolidatedOptions.html.inline === "text" && addSpan(childToken.content);
1064
+ break;
1065
+ }
1066
+ }
1067
+ break;
1068
+ }
1069
+ }
1070
+ return flushBlock(), portableText;
1071
+ }
1072
+ export {
1073
+ DefaultBlockSpacingRenderer,
1074
+ DefaultBlockquoteRenderer,
1075
+ DefaultCodeBlockRenderer,
1076
+ DefaultCodeRenderer,
1077
+ DefaultEmRenderer,
1078
+ DefaultH1Renderer,
1079
+ DefaultH2Renderer,
1080
+ DefaultH3Renderer,
1081
+ DefaultH4Renderer,
1082
+ DefaultH5Renderer,
1083
+ DefaultH6Renderer,
1084
+ DefaultHardBreakRenderer,
1085
+ DefaultHorizontalRuleRenderer,
1086
+ DefaultHtmlRenderer,
1087
+ DefaultImageRenderer,
1088
+ DefaultLinkRenderer,
1089
+ DefaultListItemRenderer,
1090
+ DefaultNormalRenderer,
1091
+ DefaultStrikeThroughRenderer,
1092
+ DefaultStrongRenderer,
1093
+ DefaultTableRenderer,
1094
+ DefaultUnderlineRenderer,
1095
+ markdownToPortableText,
1096
+ portableTextToMarkdown
1097
+ };
1098
+ //# sourceMappingURL=index.js.map