@portabletext/markdown 1.4.7 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,14 +72,14 @@ const markdown = portableTextToMarkdown([
72
72
  | Unordered lists | ✅ | ✅ |
73
73
  | Task lists | ✅\* | ✅\* |
74
74
  | Nested lists | ✅ | ✅ |
75
- | Code blocks | ✅ | ✅\* |
76
- | Horizontal rules | ✅ | ✅\* |
77
- | Images | ✅ | ✅\* |
78
- | Tables | ✅\* | ✅\* |
79
- | HTML blocks | ✅ | ✅\* |
80
- | Callouts | ✅\* | ✅\* |
75
+ | Code blocks | ✅ | |
76
+ | Horizontal rules | ✅ | |
77
+ | Images | ✅ | |
78
+ | Tables | | |
79
+ | HTML blocks | ✅ | |
80
+ | Callouts | | |
81
81
 
82
- \* Requires custom configuration (see usage below)
82
+ \* Requires a schema that declares a `task` list; the default schema does not (see [GFM task lists](#configuring-matchers) below)
83
83
 
84
84
  ## Usage
85
85
 
@@ -162,14 +162,14 @@ Out of the box, the library includes sensible defaults for both. Customize them
162
162
 
163
163
  The default schema includes the following definitions:
164
164
 
165
- | Type | Values |
166
- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
167
- | `styles` | `'normal'`, `'h1'`, `'h2'`, `'h3'`, `'h4'`, `'h5'`, `'h6'`, `'blockquote'` |
168
- | `lists` | `'number'`, `'bullet'` |
169
- | `decorators` | `'strong'`, `'em'`, `'code'`, `'strike-through'` |
170
- | `annotations` | `'link'` (fields: `'href'`, `'title'`) |
171
- | `blockObjects` | `'code'` (fields: `'language'`, `'code'`), `'image'` (fields: `'src'`, `'alt'`, `'title'`), `'horizontal-rule'`, `'html'` (fields: `'html'`), `'table'` (fields: `'headerRows'`, `'rows'`), `'callout'` (fields: `'tone'`, `'content'`) |
172
- | `inlineObjects` | `'image'` (fields: `'src'`, `'alt'`, `'title'`) |
165
+ | Type | Values |
166
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
167
+ | `styles` | `'normal'`, `'h1'`, `'h2'`, `'h3'`, `'h4'`, `'h5'`, `'h6'`, `'blockquote'` |
168
+ | `lists` | `'number'`, `'bullet'` |
169
+ | `decorators` | `'strong'`, `'em'`, `'code'`, `'strike-through'` |
170
+ | `annotations` | `'link'` (fields: `'href'`, `'title'`) |
171
+ | `blockObjects` | `'code'` (fields: `'language'`, `'code'`), `'image'` (fields: `'src'`, `'alt'`, `'title'`), `'horizontal-rule'`, `'html'` (fields: `'html'`), `'table'` (the canonical nested shape, see [Default behavior](#default-behavior)), `'callout'` (fields: `'tone'`, `'content'`) |
172
+ | `inlineObjects` | `'image'` (fields: `'src'`, `'alt'`, `'title'`) |
173
173
 
174
174
  To use a custom Schema, import `compileSchema` and `defineSchema` from `@portabletext/schema`:
175
175
 
@@ -218,8 +218,38 @@ Matchers map Markdown concepts to Portable Text types defined in the Schema. Eac
218
218
  | | `image` | `![alt](src)` | `'image'` |
219
219
  | | `html` | HTML blocks | `'html'` |
220
220
  | | `callout` | `> [!NOTE]`, etc. | `'callout'` |
221
- | | `blockquote` | `>` blockquotes | `'blockquote'` |
222
- | | `list` | `- ` or `1. ` lists | `'list'` |
221
+ | | `table` | GFM pipe tables | `'table'` |
222
+ | | `blockquote`\* | `>` blockquotes | `'blockquote'` |
223
+ | | `list`\* | `- ` or `1. ` lists | `'list'` |
224
+
225
+ \* Opt-in, not registered by default: `blockquote` and `list` map onto structural container shapes, and the parser only produces those shapes when you register the matcher (see [Configuring matchers](#configuring-matchers)). Without them, blockquotes and lists parse to flat text blocks, which is the standard Portable Text shape for both, not a degraded fallback.
226
+
227
+ #### Default behavior
228
+
229
+ **Tables** (GFM pipe tables) convert by default, in the canonical shape `@portabletext/plugin-table` expects: a `table` block object (`headerRows`, `rows`), each row a `row` object (`cells`), each cell a `cell` object (`value`, an array of Portable Text blocks; a cell holding a single image becomes a standalone block-level `image` object instead of a text block wrapping it). `alignment` is a `@portabletext/markdown` extension field; `@portabletext/plugin-table` ignores it. This needs no configuration when the schema declares a `table` block object with a `rows` field (see `blockObjects` above). A schema whose `table` doesn't declare `rows`, or that doesn't declare `table` at all, produces no table object at all: the table's cell content flattens into top-level blocks, in reading order, and the table structure is discarded.
230
+
231
+ **Images** are handled based on context:
232
+
233
+ - Standalone images (a paragraph containing only an image) become block-level `'image'` objects
234
+ - Images mixed with text become inline `'image'` objects (if the schema includes `'image'` in `inlineObjects`)
235
+ - If neither is supported, falls back to plain text: `![alt](src)`
236
+
237
+ The default image matcher requires the schema type to have a `'src'` field. If your `'image'` type doesn't include this field, the matcher returns `undefined`.
238
+
239
+ **Code** is handled based on the Markdown syntax:
240
+
241
+ - Fenced code blocks (` ``` `) become `'code'` block objects with `language` and `code` fields
242
+ - Inline code (`` ` ``) applies the `'code'` decorator to a span
243
+
244
+ The default code block matcher requires the schema type to have a `'code'` field. If your `'code'` type doesn't include this field, the matcher returns `undefined`.
245
+
246
+ **Links** support optional titles using `[text](url "title")` syntax. The title is captured in the `'title'` field of the `'link'` annotation.
247
+
248
+ **Nested lists** are handled automatically. Each list item block includes a `level` property indicating its nesting depth (1 for top-level, 2 for nested, etc.).
249
+
250
+ **HTML blocks** (like `<div>...</div>`) become `'html'` block objects with the raw HTML in the `'html'` field. Inline HTML is controlled by the `html.inline` option.
251
+
252
+ **Callouts** use the `> [!TYPE]` syntax (GFM alerts) where `TYPE` is one of `NOTE`, `TIP`, `WARNING`, `CAUTION`, or `IMPORTANT`. They become `'callout'` block objects with a `'tone'` field (the lowercased type name) and a `'content'` field (an array of Portable Text blocks). When the schema doesn't include a `'callout'` block object, the content falls back to blockquote-styled blocks.
223
253
 
224
254
  #### Configuring matchers
225
255
 
@@ -246,7 +276,7 @@ markdownToPortableText(markdown, {
246
276
 
247
277
  > **Note:** Checking if the type exists in the schema isn't required, but it's good practice. Returning `undefined` gracefully skips unsupported types.
248
278
 
249
- **Table matcher:** Markdown tables are parsed but there's no default matcher. Provide one if your schema includes tables:
279
+ **Table matcher:** GFM pipe tables convert by default (see [Default behavior](#default-behavior)). Provide your own matcher to map onto a differently-shaped `table` type:
250
280
 
251
281
  ```ts
252
282
  markdownToPortableText(markdown, {
@@ -348,31 +378,6 @@ Matchers receive:
348
378
 
349
379
  Return `undefined` to skip the element (e.g., if the type isn't in the schema).
350
380
 
351
- #### Default behavior for images and code
352
-
353
- **Images** are handled based on context:
354
-
355
- - Standalone images (a paragraph containing only an image) become block-level `'image'` objects
356
- - Images mixed with text become inline `'image'` objects (if the schema includes `'image'` in `inlineObjects`)
357
- - If neither is supported, falls back to plain text: `![alt](src)`
358
-
359
- The default image matcher requires the schema type to have a `'src'` field. If your `'image'` type doesn't include this field, the matcher returns `undefined`.
360
-
361
- **Code** is handled based on the Markdown syntax:
362
-
363
- - Fenced code blocks (` ``` `) become `'code'` block objects with `language` and `code` fields
364
- - Inline code (`` ` ``) applies the `'code'` decorator to a span
365
-
366
- The default code block matcher requires the schema type to have a `'code'` field. If your `'code'` type doesn't include this field, the matcher returns `undefined`.
367
-
368
- **Links** support optional titles using `[text](url "title")` syntax. The title is captured in the `'title'` field of the `'link'` annotation.
369
-
370
- **Nested lists** are handled automatically. Each list item block includes a `level` property indicating its nesting depth (1 for top-level, 2 for nested, etc.).
371
-
372
- **HTML blocks** (like `<div>...</div>`) become `'html'` block objects with the raw HTML in the `'html'` field. Inline HTML is controlled by the `html.inline` option.
373
-
374
- **Callouts** use the `> [!TYPE]` syntax (GFM alerts) where `TYPE` is one of `NOTE`, `TIP`, `WARNING`, `CAUTION`, or `IMPORTANT`. They become `'callout'` block objects with a `'tone'` field (the lowercased type name) and a `'content'` field (an array of Portable Text blocks). When the schema doesn't include a `'callout'` block object, the content falls back to blockquote-styled blocks.
375
-
376
381
  #### Other options
377
382
 
378
383
  ```ts
@@ -449,34 +454,42 @@ The conversion is driven by **Renderers**: functions that render Portable Text e
449
454
 
450
455
  #### Default renderers
451
456
 
452
- | Group | Renderer | Renders | Output |
453
- | ------------------- | ---------------- | --------------------------------- | ------------------------ |
454
- | `block` | `normal` | Paragraphs | `{children}` |
455
- | | `h1`–`h6` | Headings | `# `–`###### ` |
456
- | | `blockquote` | Blockquotes | `> {children}` |
457
- | `marks` | `strong` | Bold text | `**{children}**` |
458
- | | `em` | Italic text | `_{children}_` |
459
- | | `code` | Inline code | `` `{children}` `` |
460
- | | `underline` | Underlined text | `<u>{children}</u>` |
461
- | | `strike-through` | Strikethrough | `~~{children}~~` |
462
- | | `link` | Links | `[{children}](url)` |
463
- | `listItem` | | List items (bullet, number, task) | `- `, `1. `, or `- [x] ` |
464
- | `hardBreak` | | Line breaks within blocks | ` \n` (two spaces) |
465
- | `blockSpacing` | | Spacing between blocks | `\n\n`, `\n`, `\n>\n` |
466
- | `unknownType` | | Unknown block types | JSON code block |
467
- | `unknownBlockStyle` | | Unknown block styles | `{children}` |
468
- | `unknownListItem` | | Unknown list item types | `- {children}` |
469
- | `unknownMark` | | Unknown marks | `{children}` |
457
+ | Group | Renderer | Renders | Output |
458
+ | ------------------- | ----------------- | --------------------------------- | ------------------------ |
459
+ | `types` | `callout` | `callout` block objects | `> [!TYPE]\n> content` |
460
+ | | `code` | `code` block objects | Fenced code block |
461
+ | | `horizontal-rule` | `horizontal-rule` block objects | `---` |
462
+ | | `html` | `html` block objects | Raw HTML |
463
+ | | `image` | `image` block/inline objects | `![alt](src "title")` |
464
+ | | `table` | `table` block objects | Markdown table |
465
+ | `block` | `normal` | Paragraphs | `{children}` |
466
+ | | `h1`–`h6` | Headings | `# `–`###### ` |
467
+ | | `blockquote` | Blockquotes | `> {children}` |
468
+ | `marks` | `strong` | Bold text | `**{children}**` |
469
+ | | `em` | Italic text | `_{children}_` |
470
+ | | `code` | Inline code | `` `{children}` `` |
471
+ | | `underline` | Underlined text | `<u>{children}</u>` |
472
+ | | `strike-through` | Strikethrough | `~~{children}~~` |
473
+ | | `link` | Links | `[{children}](url)` |
474
+ | `listItem` | | List items (bullet, number, task) | `- `, `1. `, or `- [x] ` |
475
+ | `hardBreak` | | Line breaks within blocks | ` \n` (two spaces) |
476
+ | `blockSpacing` | | Spacing between blocks | `\n\n`, `\n`, `\n>\n` |
477
+ | `unknownType` | | Unknown block types | JSON code block |
478
+ | `unknownBlockStyle` | | Unknown block styles | `{children}` |
479
+ | `unknownListItem` | | Unknown list item types | `- {children}` |
480
+ | `unknownMark` | | Unknown marks | `{children}` |
470
481
 
471
482
  Unknown types render as JSON code blocks by default; unknown styles, list items, and marks pass through their children.
472
483
 
484
+ The default type renderers are collision-safe: because the serializer dispatches on the `_type` name alone, `code`, `html`, `image`, `callout`, and `table` fall back to the `unknownType` renderer (a JSON code block) when a value doesn't match the shape their renderer expects (say, your own differently-shaped `code` type); `horizontal-rule` has no shape to check and always renders `---`. Register your own `types.<name>` renderer to override how any of them serialize, or to handle a same-named type of a different shape.
485
+
473
486
  > **Note:** The `underline` renderer is included for Portable Text that uses it, but there's no standard Markdown syntax for underline, so it renders as HTML.
474
487
 
475
488
  #### Configuring renderers
476
489
 
477
490
  Provide custom renderers to control how Portable Text renders to Markdown.
478
491
 
479
- **Custom type renderers:** Render custom block types (objects in the blocks array):
492
+ **Custom type renderers:** Render custom block types (objects in the blocks array). A custom renderer under a default's name (see [Default renderers](#default-renderers)) replaces that default:
480
493
 
481
494
  ```ts
482
495
  portableTextToMarkdown(blocks, {
@@ -500,31 +513,19 @@ portableTextToMarkdown(blocks, {
500
513
  })
501
514
  ```
502
515
 
503
- **Built-in type renderers:** The library exports default renderers for common block types:
516
+ **Built-in type renderers:** the library exports every built-in type renderer, in case you want to compose one into a different renderer or reuse it under a different type name. Two of them are exported but not registered by default: `DefaultBlockquoteObjectRenderer` and `DefaultListRenderer` render the structural container shapes (`types.blockquote`/`types.list` on the parser side) and stay opt-in, since the parser only produces those shapes when a matcher is registered for them:
504
517
 
505
518
  ```ts
506
519
  import {
507
520
  DefaultBlockquoteObjectRenderer,
508
- DefaultCalloutRenderer,
509
- DefaultCodeBlockRenderer,
510
- DefaultHorizontalRuleRenderer,
511
- DefaultHtmlRenderer,
512
- DefaultImageRenderer,
513
521
  DefaultListRenderer,
514
- DefaultTableRenderer,
515
522
  portableTextToMarkdown,
516
523
  } from '@portabletext/markdown'
517
524
 
518
525
  portableTextToMarkdown(blocks, {
519
526
  types: {
520
- 'blockquote': DefaultBlockquoteObjectRenderer,
521
- 'callout': DefaultCalloutRenderer,
522
- 'code': DefaultCodeBlockRenderer,
523
- 'horizontal-rule': DefaultHorizontalRuleRenderer,
524
- 'html': DefaultHtmlRenderer,
525
- 'image': DefaultImageRenderer,
526
- 'list': DefaultListRenderer,
527
- 'table': DefaultTableRenderer,
527
+ blockquote: DefaultBlockquoteObjectRenderer,
528
+ list: DefaultListRenderer,
528
529
  },
529
530
  })
530
531
  ```
package/dist/index.d.ts CHANGED
@@ -454,13 +454,13 @@ declare const DefaultImageRenderer: PortableTextTypeRenderer<{
454
454
  /**
455
455
  * Renders a Portable Text table block-object back to Markdown.
456
456
  *
457
- * The PT `headerRows` field decides the header. `headerRows === 0` is an
458
- * explicit headerless table: GFM has no headerless form, so an empty header
459
- * row is emitted and every row goes in the body (that empty header reads back
460
- * as `headerRows: 0` via `markdownToPortableText`). Any other value
461
- * (`undefined` or `>= 1`) promotes `rows[0]` to the header. GFM allows exactly
462
- * one header row, so header rows beyond the first flatten into the body,
463
- * lossy, but the extra rows stay on the Portable Text side.
457
+ * The PT `headerRows` field decides the header. Missing `headerRows` and
458
+ * `headerRows === 0` both render headerless: GFM has no headerless form, so
459
+ * an empty header row is emitted and every row goes in the body (that empty
460
+ * header reads back as `headerRows: 0` via `markdownToPortableText`).
461
+ * `headerRows >= 1` promotes `rows[0]` to the header. GFM allows exactly one
462
+ * header row, so header rows beyond the first flatten into the body, lossy,
463
+ * but the extra rows stay on the Portable Text side.
464
464
  *
465
465
  * Asymmetric tables (rows of varying cell counts) are widened to match
466
466
  * the row with the most cells. Narrower rows are padded with empty cells
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../node_modules/.pnpm/@portabletext+types@4.0.2/node_modules/@portabletext/types/dist/index.d.ts","../src/from-portable-text/renderers/block-spacing.ts","../src/from-portable-text/types.ts","../src/from-portable-text/portable-text-to-markdown.ts","../src/from-portable-text/renderers/hard-break.ts","../src/from-portable-text/renderers/list-item.ts","../src/from-portable-text/renderers/style.ts","../src/from-portable-text/renderers/marks.ts","../src/from-portable-text/renderers/type.ts","../src/to-portable-text/matchers.ts","../src/to-portable-text/markdown-to-portable-text.ts"],"x_google_ignoreList":[0],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../node_modules/.pnpm/@portabletext+types@4.0.2/node_modules/@portabletext/types/dist/index.d.ts","../src/from-portable-text/renderers/block-spacing.ts","../src/from-portable-text/types.ts","../src/from-portable-text/portable-text-to-markdown.ts","../src/from-portable-text/renderers/hard-break.ts","../src/from-portable-text/renderers/list-item.ts","../src/from-portable-text/renderers/style.ts","../src/from-portable-text/renderers/marks.ts","../src/from-portable-text/renderers/type.ts","../src/to-portable-text/matchers.ts","../src/to-portable-text/markdown-to-portable-text.ts"],"x_google_ignoreList":[0],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { compileSchema, defineSchema, isSpan, isTextBlock } from "@portabletext/schema";
1
+ import { compileSchema, defineSchema, isSpan, isTextBlock, isTypedObject } from "@portabletext/schema";
2
2
  import { buildMarksTree, isPortableTextBlock, isPortableTextListItemBlock, isPortableTextToolkitSpan, isPortableTextToolkitTextNode, spanToPlainText } from "@portabletext/toolkit";
3
3
  import { alert } from "@mdit/plugin-alert";
4
4
  import markdownit from "markdown-it";
@@ -255,11 +255,75 @@ function uriLooksSafe(uri) {
255
255
  /**
256
256
  * @public
257
257
  */
258
- const DefaultUnknownMarkRenderer = ({ children }) => children, DefaultNormalRenderer = ({ children }) => !children || children.trim() === "" ? "" : children, DefaultBlockquoteRenderer = ({ children }) => children ? children.split("\n").map((line) => `> ${line}`).join("\n") : ">", DefaultH1Renderer = ({ children }) => `# ${children}`, DefaultH2Renderer = ({ children }) => `## ${children}`, DefaultH3Renderer = ({ children }) => `### ${children}`, DefaultH4Renderer = ({ children }) => `#### ${children}`, DefaultH5Renderer = ({ children }) => `##### ${children}`, DefaultH6Renderer = ({ children }) => `###### ${children}`, DefaultUnknownStyleRenderer = ({ children }) => children ?? "", DefaultCodeBlockRenderer = ({ value }) => `\`\`\`${value.language ?? ""}\n${value.code}\n\`\`\``, DefaultHorizontalRuleRenderer = () => "---", DefaultHtmlRenderer = ({ value }) => value.html, DefaultImageRenderer = ({ value }) => {
259
- let alt = escapeImageAndLinkText(value.alt ?? ""), title = value.title ? ` "${escapeImageAndLinkTitle(value.title)}"` : "";
260
- return `![${alt}](${value.src}${title})`;
261
- }, DefaultTableRenderer = ({ value, renderNode }) => {
262
- let rows = value.rows, alignment = value.alignment, headerRow = rows.at(0);
258
+ const DefaultUnknownMarkRenderer = ({ children }) => children, DefaultNormalRenderer = ({ children }) => !children || children.trim() === "" ? "" : children, DefaultBlockquoteRenderer = ({ children }) => children ? children.split("\n").map((line) => `> ${line}`).join("\n") : ">", DefaultH1Renderer = ({ children }) => `# ${children}`, DefaultH2Renderer = ({ children }) => `## ${children}`, DefaultH3Renderer = ({ children }) => `### ${children}`, DefaultH4Renderer = ({ children }) => `#### ${children}`, DefaultH5Renderer = ({ children }) => `##### ${children}`, DefaultH6Renderer = ({ children }) => `###### ${children}`, DefaultUnknownStyleRenderer = ({ children }) => children ?? "", DefaultCodeBlockRenderer = (options) => isCodeShaped(options.value) ? `\`\`\`${normalizeLanguage(options.value.language)}\n${options.value.code}\n\`\`\`` : DefaultUnknownTypeRenderer(options);
259
+ function isCodeShaped(value) {
260
+ return typeof value?.code == "string";
261
+ }
262
+ /**
263
+ * A fence info string is everything after the opening fence on the same
264
+ * line, so a real `language` can never contain a newline, and the parser
265
+ * only ever produces a string. Junk in this optional field should not send
266
+ * an otherwise valid code block to the fenced-JSON path, so it is treated
267
+ * as absent instead of guarded.
268
+ */
269
+ function normalizeLanguage(language) {
270
+ return typeof language != "string" || language.includes("\n") ? "" : language;
271
+ }
272
+ /**
273
+ * @public
274
+ */
275
+ const DefaultHorizontalRuleRenderer = () => "---", DefaultHtmlRenderer = (options) => isHtmlShaped(options.value) ? options.value.html : DefaultUnknownTypeRenderer(options);
276
+ function isHtmlShaped(value) {
277
+ return typeof value?.html == "string";
278
+ }
279
+ /**
280
+ * @public
281
+ */
282
+ const DefaultImageRenderer = (options) => {
283
+ if (!isImageShaped(options.value)) return DefaultUnknownTypeRenderer(options);
284
+ let alt = escapeImageAndLinkText(options.value.alt ?? ""), title = options.value.title ? ` "${escapeImageAndLinkTitle(options.value.title)}"` : "";
285
+ return `![${alt}](${options.value.src}${title})`;
286
+ };
287
+ function isImageShaped(value) {
288
+ let image = value;
289
+ return typeof image?.src == "string" && (image.alt == null || typeof image.alt == "string") && (image.title == null || typeof image.title == "string");
290
+ }
291
+ /**
292
+ * A table is table-shaped when everything the renderer dereferences is
293
+ * there: `rows` an array of typed objects with a `cells` array, every cell
294
+ * a typed object whose `value` array holds typed objects (`renderNode`'s
295
+ * input contract). The predicate narrows to exactly what `renderTable`
296
+ * consumes, so the renderer needs no casts. A malformed `table` value
297
+ * (e.g. a consumer's differently-shaped `table` type) falls back to the
298
+ * fenced-JSON path instead of throwing.
299
+ */
300
+ function isTableShaped(value) {
301
+ let rows = value?.rows;
302
+ return Array.isArray(rows) && rows.every((row) => isTypedObject(row) && Array.isArray(row.cells) && row.cells.every((cell) => isTypedObject(cell) && Array.isArray(cell.value) && cell.value.every(isTypedObject)));
303
+ }
304
+ /**
305
+ * Renders a Portable Text table block-object back to Markdown.
306
+ *
307
+ * The PT `headerRows` field decides the header. Missing `headerRows` and
308
+ * `headerRows === 0` both render headerless: GFM has no headerless form, so
309
+ * an empty header row is emitted and every row goes in the body (that empty
310
+ * header reads back as `headerRows: 0` via `markdownToPortableText`).
311
+ * `headerRows >= 1` promotes `rows[0]` to the header. GFM allows exactly one
312
+ * header row, so header rows beyond the first flatten into the body, lossy,
313
+ * but the extra rows stay on the Portable Text side.
314
+ *
315
+ * Asymmetric tables (rows of varying cell counts) are widened to match
316
+ * the row with the most cells. Narrower rows are padded with empty cells
317
+ * so a GFM parser doesn't silently drop the extra cells in wider rows.
318
+ *
319
+ * @public
320
+ */
321
+ const DefaultTableRenderer = (options) => {
322
+ let { value, renderNode } = options;
323
+ return isTableShaped(value) ? renderTable(value, renderNode) : DefaultUnknownTypeRenderer(options);
324
+ };
325
+ function renderTable(value, renderNode) {
326
+ let rows = value.rows, alignment = Array.isArray(value.alignment) ? value.alignment : void 0, headerRow = rows.at(0);
263
327
  if (!headerRow) return "";
264
328
  let getCellText = (cellBlocks) => cellBlocks.map((block, index) => renderNode({
265
329
  node: block,
@@ -274,33 +338,55 @@ const DefaultUnknownMarkRenderer = ({ children }) => children, DefaultNormalRend
274
338
  let align = alignment?.at(index);
275
339
  return align === "left" ? " :--- " : align === "center" ? " :---: " : align === "right" ? " ---: " : " --- ";
276
340
  }).join("|")}|`;
277
- if (value.headerRows === 0) {
278
- lines.push(renderCells([])), lines.push(delimiter);
279
- for (let row of rows) lines.push(renderRow(row.cells));
280
- } else {
341
+ if ((Number(value.headerRows) || 0) >= 1) {
281
342
  lines.push(renderRow(headerRow.cells)), lines.push(delimiter);
282
343
  for (let i = 1; i < rows.length; i++) {
283
344
  let row = rows.at(i);
284
345
  row && lines.push(renderRow(row.cells));
285
346
  }
347
+ } else {
348
+ lines.push(renderCells([])), lines.push(delimiter);
349
+ for (let row of rows) lines.push(renderRow(row.cells));
286
350
  }
287
351
  return lines.join("\n");
288
- }, DefaultCalloutRenderer = ({ value, renderNode }) => {
289
- let prefixed = value.content.map((block, index) => renderNode({
290
- node: {
352
+ }
353
+ /**
354
+ * @public
355
+ */
356
+ const DefaultCalloutRenderer = (options) => {
357
+ if (!isCalloutShaped(options.value)) return DefaultUnknownTypeRenderer(options);
358
+ let { renderNode } = options, prefixed = options.value.content.map((block, index) => renderNode({
359
+ node: block._type === "block" ? {
291
360
  ...block,
292
361
  style: "normal"
293
- },
362
+ } : block,
294
363
  index,
295
364
  isInline: !1,
296
365
  renderNode
297
366
  })).join("\n\n").split("\n").map((line) => line === "" ? ">" : `> ${line}`).join("\n");
298
- return `> [!${value.tone.toUpperCase()}]\n${prefixed}`;
299
- }, DefaultBlockquoteObjectRenderer = ({ value, renderNode }) => value.content.map((block, index) => renderNode({
300
- node: {
367
+ return `> [!${options.value.tone.toUpperCase()}]\n${prefixed}`;
368
+ };
369
+ function isCalloutShaped(value) {
370
+ let callout = value;
371
+ return typeof callout?.tone == "string" && Array.isArray(callout.content) && callout.content.every(isTypedObject);
372
+ }
373
+ /**
374
+ * Renders a structural blockquote block-object (the `types.blockquote` shape
375
+ * produced by `markdownToPortableText` when a `types.blockquote` matcher is
376
+ * provided) back to Markdown. Each content block is rendered via the
377
+ * recursive renderer pipeline, joined with blank lines, and every line is
378
+ * prefixed with `> ` to form a Markdown blockquote.
379
+ *
380
+ * Distinct from `DefaultBlockquoteRenderer`, which renders flat-path text
381
+ * blocks with `style: 'blockquote'`.
382
+ *
383
+ * @public
384
+ */
385
+ const DefaultBlockquoteObjectRenderer = ({ value, renderNode }) => value.content.map((block, index) => renderNode({
386
+ node: block._type === "block" ? {
301
387
  ...block,
302
388
  style: "normal"
303
- },
389
+ } : block,
304
390
  index,
305
391
  isInline: !1,
306
392
  renderNode
@@ -332,7 +418,14 @@ const DefaultUnknownTypeRenderer = ({ value, isInline }) => {
332
418
  let json = `\`\`\`json\n${JSON.stringify(value, null, 2)}\n\`\`\``;
333
419
  return isInline ? `\n${json}\n` : json;
334
420
  }, defaultRenderers = {
335
- types: {},
421
+ types: {
422
+ callout: DefaultCalloutRenderer,
423
+ code: DefaultCodeBlockRenderer,
424
+ "horizontal-rule": DefaultHorizontalRuleRenderer,
425
+ html: DefaultHtmlRenderer,
426
+ image: DefaultImageRenderer,
427
+ table: DefaultTableRenderer
428
+ },
336
429
  block: {
337
430
  normal: DefaultNormalRenderer,
338
431
  blockquote: DefaultBlockquoteRenderer,
@@ -453,7 +546,24 @@ const normalStyleDefinition = { name: "normal" }, h1StyleDefinition = { name: "h
453
546
  },
454
547
  {
455
548
  name: "rows",
456
- type: "array"
549
+ type: "array",
550
+ of: [{
551
+ type: "object",
552
+ name: "row",
553
+ fields: [{
554
+ name: "cells",
555
+ type: "array",
556
+ of: [{
557
+ type: "object",
558
+ name: "cell",
559
+ fields: [{
560
+ name: "value",
561
+ type: "array",
562
+ of: [{ type: "block" }, { type: "image" }]
563
+ }]
564
+ }]
565
+ }]
566
+ }]
457
567
  }
458
568
  ]
459
569
  }, defaultCalloutObjectDefinition = {
@@ -564,6 +674,13 @@ const codeBlockMatcher = ({ context, value, isInline }) => {
564
674
  isInline
565
675
  });
566
676
  if (imageObject && "src" in imageObject) return imageObject;
677
+ }, tableBlockMatcher = ({ context, value, isInline }) => {
678
+ let tableObject = buildObjectMatcher(defaultTableObjectDefinition)({
679
+ context,
680
+ value,
681
+ isInline
682
+ });
683
+ if (tableObject && "rows" in tableObject) return tableObject;
567
684
  }, defaultOptions = {
568
685
  schema: defaultSchema,
569
686
  keyGenerator: defaultKeyGenerator,
@@ -595,7 +712,8 @@ const codeBlockMatcher = ({ context, value, isInline }) => {
595
712
  horizontalRule: buildObjectMatcher(defaultHorizontalRuleObjectDefinition),
596
713
  html: buildObjectMatcher(defaultHtmlObjectDefinition),
597
714
  image: imageBlockMatcher,
598
- callout: buildObjectMatcher(defaultCalloutObjectDefinition)
715
+ callout: buildObjectMatcher(defaultCalloutObjectDefinition),
716
+ table: tableBlockMatcher
599
717
  }
600
718
  };
601
719
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/key-generator.ts","../src/from-portable-text/build-list-index-map.ts","../src/from-portable-text/render-node.ts","../src/from-portable-text/renderers/block-spacing.ts","../src/from-portable-text/renderers/hard-break.ts","../src/from-portable-text/renderers/list-item.ts","../src/escape.ts","../src/from-portable-text/renderers/marks.ts","../src/from-portable-text/renderers/style.ts","../src/from-portable-text/renderers/type.ts","../src/from-portable-text/portable-text-to-markdown.ts","../src/default-schema.ts","../src/to-portable-text/matchers.ts","../src/to-portable-text/markdown-to-portable-text.ts"],"sourcesContent":["export function defaultKeyGenerator() {\n return randomKey(12)\n}\n\nconst getByteHexTable = (() => {\n let table: any[]\n return () => {\n if (table) {\n return table\n }\n\n table = []\n for (let i = 0; i < 256; ++i) {\n table[i] = (i + 0x100).toString(16).slice(1)\n }\n return table\n }\n})()\n\n// WHATWG crypto RNG - https://w3c.github.io/webcrypto/Overview.html\nfunction whatwgRNG(length = 16) {\n const rnds8 = new Uint8Array(length)\n crypto.getRandomValues(rnds8)\n return rnds8\n}\n\nfunction randomKey(length?: number): string {\n const table = getByteHexTable()\n return whatwgRNG(length)\n .reduce((str, n) => str + table[n], '')\n .slice(0, length)\n}\n","import {\n compileSchema,\n defineSchema,\n isTextBlock,\n type PortableTextBlock,\n} from '@portabletext/schema'\nimport type {ArbitraryTypedObject, TypedObject} from '@portabletext/types'\nimport {defaultKeyGenerator} from '../key-generator'\n\nconst schema = compileSchema(defineSchema({}))\n\n/**\n * Builds a map of list item `_key`s to their index, and a map of list item\n * `_key`s to the depth they should be rendered at.\n *\n * The depth is not the same as the block's `level`. A list can start at a level\n * deeper than 1, and can skip levels, but Markdown has no way to express either:\n * indentation is relative to the list item above, and indenting a first item by\n * four spaces or more makes it a code block rather than a list. So each jump to a\n * deeper level counts as a single step of nesting, however many levels it spans.\n *\n * Mutates the blocks in place by adding a `_key` if necessary.\n */\nexport function buildListIndexMap<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(\n blocks: Array<Block>,\n): {listIndexMap: Map<string, number>; listDepthMap: Map<string, number>} {\n const levelIndexMaps = new Map<string, Map<number, number>>()\n const listIndexMap = new Map<string, number>()\n const listDepthMap = new Map<string, number>()\n\n // Levels of the list items this one is nested inside, shallowest first\n let levelStack: Array<number> = []\n\n function depthOf(level: number): number {\n let deepest = levelStack.at(-1)\n\n while (deepest !== undefined && deepest > level) {\n levelStack.pop()\n deepest = levelStack.at(-1)\n }\n\n if (deepest !== level) {\n levelStack.push(level)\n }\n\n return levelStack.length - 1\n }\n\n let previousListItem:\n | {\n listItem: string\n depth: number\n }\n | undefined\n\n for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) {\n const block = blocks.at(blockIndex)\n\n if (block === undefined) {\n continue\n }\n\n if (!block._key) {\n block._key = defaultKeyGenerator()\n }\n\n // Clear the state if we encounter a non-text block\n if (!isTextBlock({schema}, block)) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n // Clear the state if we encounter a non-list text block\n if (block.listItem === undefined || block.level === undefined) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n const depth = depthOf(block.level)\n listDepthMap.set(block._key, depth)\n\n // If we encounter a new list item, we set the initial index to 1 for the\n // list type on that level.\n if (!previousListItem) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // If the previous list item is of the same type but on a lower level, we\n // need to reset the level index map for that type.\n if (\n previousListItem.listItem === block.listItem &&\n previousListItem.depth < depth\n ) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // Reset other list types at current depth and deeper\n levelIndexMaps.forEach((levelIndexMap, listItem) => {\n if (listItem === block.listItem) {\n return\n }\n\n // Reset all levels that are >= current level\n const depthsToDelete: number[] = []\n\n levelIndexMap.forEach((_, existingDepth) => {\n if (existingDepth >= depth) {\n depthsToDelete.push(existingDepth)\n }\n })\n\n depthsToDelete.forEach((depthToDelete) => {\n levelIndexMap.delete(depthToDelete)\n })\n })\n\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n const levelCounter = levelIndexMap.get(depth) ?? 0\n levelIndexMap.set(depth, levelCounter + 1)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, levelCounter + 1)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n }\n\n return {listIndexMap, listDepthMap}\n}\n","import {\n buildMarksTree,\n isPortableTextBlock,\n isPortableTextListItemBlock,\n isPortableTextToolkitSpan,\n isPortableTextToolkitTextNode,\n spanToPlainText,\n type ToolkitNestedPortableTextSpan,\n type ToolkitTextNode,\n} from '@portabletext/toolkit'\nimport type {\n PortableTextBlock,\n PortableTextListItemBlock,\n PortableTextMarkDefinition,\n PortableTextSpan,\n TypedObject,\n} from '@portabletext/types'\nimport {defaultKeyGenerator} from '../key-generator'\nimport type {PortableTextRenderers, RenderNode, Serializable} from './types'\n\ninterface SerializedBlock {\n _key: string\n children: string\n index: number\n isInline: boolean\n node: PortableTextBlock | PortableTextListItemBlock\n}\n\nexport const createRenderNode = (\n renderers: PortableTextRenderers,\n listIndexMap: Map<string, number>,\n listDepthMap: Map<string, number>,\n): RenderNode => {\n function renderNode<N extends TypedObject>(options: Serializable<N>): string {\n const {node, index, isInline} = options\n\n if (isPortableTextListItemBlock(node)) {\n return renderListItem(node, index)\n }\n\n if (isPortableTextToolkitSpan(node)) {\n return renderSpan(node)\n }\n\n if (isPortableTextBlock(node)) {\n return renderBlock(node, index, isInline)\n }\n\n if (isPortableTextToolkitTextNode(node)) {\n return renderText(node)\n }\n\n return renderCustomBlock(node, index, isInline)\n }\n\n function renderListItem(\n node: PortableTextListItemBlock<\n PortableTextMarkDefinition,\n PortableTextSpan\n >,\n index: number,\n ): string {\n const renderer = renderers.listItem\n const handler =\n typeof renderer === 'function' ? renderer : renderer[node.listItem]\n const itemHandler = handler || renderers.unknownListItem\n\n // Build the text content from the block\n const tree = buildMarksTree(node)\n const textContent = tree\n .map((child, i) => {\n return renderNode({node: child, isInline: true, index: i, renderNode})\n })\n .join('')\n\n let children = textContent\n\n if (node.style && node.style !== 'normal') {\n // Wrap any other style in whatever the block component says to use\n const {listItem: _listItem, ...blockNode} = node\n children = renderNode({\n node: blockNode,\n index,\n isInline: false,\n renderNode,\n })\n // Strip trailing newlines from block styles - list item component handles spacing\n children = children.replace(/\\n+$/, '')\n }\n\n return itemHandler({\n value: node,\n index,\n listIndex: node._key ? listIndexMap.get(node._key) : undefined,\n listDepth: node._key ? listDepthMap.get(node._key) : undefined,\n isInline: false,\n renderNode,\n children,\n })\n }\n\n function renderSpan(node: ToolkitNestedPortableTextSpan): string {\n const {markDef, markType, markKey} = node\n const span = renderers.marks[markType] || renderers.unknownMark\n const children = node.children.map((child, childIndex) =>\n renderNode({node: child, index: childIndex, isInline: true, renderNode}),\n )\n\n return span({\n text: spanToPlainText(node),\n value: markDef,\n markType,\n markKey,\n renderNode,\n children: children.join(''),\n })\n }\n\n function renderBlock(\n node: PortableTextBlock,\n index: number,\n isInline: boolean,\n ): string {\n const {_key, ...props} = serializeBlock({node, index, isInline, renderNode})\n const style = props.node.style || 'normal'\n const handler =\n typeof renderers.block === 'function'\n ? renderers.block\n : renderers.block[style]\n const block = handler || renderers.unknownBlockStyle\n\n return block({...props, value: props.node, renderNode})\n }\n\n function renderText(node: ToolkitTextNode): string {\n if (node.text === '\\n') {\n return renderers.hardBreak()\n }\n\n return node.text\n }\n\n function renderCustomBlock(\n value: TypedObject,\n index: number,\n isInline: boolean,\n ): string {\n const component = renderers.types[value._type] ?? renderers.unknownType\n\n return component({\n value,\n isInline,\n index,\n renderNode,\n })\n }\n\n return renderNode\n}\n\nfunction serializeBlock(\n options: Serializable<PortableTextBlock>,\n): SerializedBlock {\n const {node, index, isInline, renderNode} = options\n const tree = buildMarksTree(node)\n\n const renderedChildren = tree.map((child, i) =>\n renderNode({node: child, isInline: true, index: i, renderNode}),\n )\n\n return {\n _key: node._key || defaultKeyGenerator(),\n children: renderedChildren.join(''),\n index,\n isInline,\n node,\n }\n}\n","import {\n isPortableTextBlock,\n isPortableTextListItemBlock,\n} from '@portabletext/toolkit'\nimport type {TypedObject} from '@portabletext/types'\n\n/**\n * @public\n */\nexport type BlockSpacingRenderer = (options: {\n current: TypedObject\n next: TypedObject\n}) => string | undefined\n\n/**\n * @public\n */\nexport const DefaultBlockSpacingRenderer: BlockSpacingRenderer = ({\n current,\n next,\n}) => {\n if (\n isPortableTextListItemBlock(current) &&\n isPortableTextListItemBlock(next)\n ) {\n return '\\n'\n }\n\n if (\n isPortableTextBlock(current) &&\n isPortableTextBlock(next) &&\n current.style === 'blockquote' &&\n next.style === 'blockquote'\n ) {\n return '\\n>\\n'\n }\n\n return '\\n\\n'\n}\n","/**\n * @public\n */\nexport const DefaultHardBreakRenderer = (): string => ' \\n'\n","import type {PortableTextListItemRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultListItemRenderer: PortableTextListItemRenderer = ({\n children,\n value,\n listIndex,\n listDepth,\n}) => {\n const listStyle = value.listItem || 'bullet'\n const depth = listDepth ?? (value.level || 1) - 1\n const indent = ' '.repeat(depth)\n\n if (listStyle === 'number') {\n return `${indent}${listIndex ?? 1}. ${children}`\n }\n\n if (listStyle === 'task') {\n const checked =\n 'checked' in value && typeof value.checked === 'boolean'\n ? value.checked\n : false\n const marker = checked ? '[x]' : '[ ]'\n return `${indent}- ${marker} ${children}`\n }\n\n return `${indent}- ${children}`\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownListItemRenderer: PortableTextListItemRenderer = ({\n children,\n}) => {\n return `- ${children}\\n`\n}\n","/**\n * Escapes special characters in image alt texts and link texts.\n */\nexport function escapeImageAndLinkText(text: string): string {\n return text.replace(/([[\\]\\\\])/g, '\\\\$1')\n}\n\n/**\n * Unescapes special characters in image alt texts and link texts.\n */\nexport function unescapeImageAndLinkText(text: string): string {\n return text.replace(/\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g, '$1')\n}\n\n/**\n * Escapes special characters in image/link titles (the part inside quotes).\n */\nexport function escapeImageAndLinkTitle(text: string): string {\n return text.replace(/([\\\\\"])/g, '\\\\$1')\n}\n\n/**\n * Escapes characters that have special meaning at the row level of a GFM\n * table cell.\n *\n * A literal `|` ends the cell, so unescaped pipes are replaced with `\\|`.\n * Newlines end the row, so they are replaced with `<br>` to keep the\n * visible line break inside the cell. Already-escaped pipes (`\\|`) are\n * left intact so that escapes introduced by mark renderers survive the\n * pass.\n *\n * Backslashes are intentionally not escaped here so that other escapes\n * already in the rendered cell (such as `\\[` and `\\]` in link text) are\n * not double-escaped.\n */\nexport function escapeTableCell(text: string): string {\n return text.replace(/(?<!\\\\)\\|/g, '\\\\|').replace(/\\n/g, '<br>')\n}\n","import type {TypedObject} from '@portabletext/types'\nimport {escapeImageAndLinkText, escapeImageAndLinkTitle} from '../../escape'\nimport type {PortableTextMarkRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultEmRenderer: PortableTextMarkRenderer = ({children}) =>\n `_${children}_`\n\n/**\n * @public\n */\nexport const DefaultStrongRenderer: PortableTextMarkRenderer = ({children}) =>\n `**${children}**`\n\n/**\n * @public\n */\nexport const DefaultCodeRenderer: PortableTextMarkRenderer = ({children}) =>\n `\\`${children}\\``\n\n/**\n * @public\n */\nexport const DefaultUnderlineRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `<u>${children}</u>`\n\n/**\n * @public\n */\nexport const DefaultStrikeThroughRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `~~${children}~~`\n\ninterface DefaultLink extends TypedObject {\n _type: 'link'\n href: string\n title: string | undefined\n}\n\n/**\n * @public\n */\nexport const DefaultLinkRenderer: PortableTextMarkRenderer<DefaultLink> = ({\n children,\n value,\n}) => {\n const href = value?.href || ''\n const title = value?.title || ''\n const looksSafe = uriLooksSafe(href)\n\n if (looksSafe) {\n // Check if the URL looks like an HTML injection attempt\n // If it has quotes AND angle brackets, or other suspicious patterns, encode more aggressively\n const looksLikeInjection = /[\"'][^\"']*[<>]|[<>][^<>]*[\"']/.test(href)\n\n if (looksLikeInjection) {\n // Encode all special characters that could be used for injection\n const encodedHref = href.replace(/[\"<>() ]/g, (char) => {\n return `%${char.charCodeAt(0).toString(16).toUpperCase()}`\n })\n return `[${escapeImageAndLinkText(children)}](${encodedHref})`\n }\n\n // For normal URLs, don't encode parentheses - Markdown handles balanced parens fine\n return `[${escapeImageAndLinkText(children)}](${href}${title ? ` \"${escapeImageAndLinkTitle(title)}\"` : ''})`\n }\n\n // Return children without link when URL is unsafe\n return children\n}\n\nfunction uriLooksSafe(uri: string): boolean {\n const url = (uri || '').trim()\n const first = url.charAt(0)\n\n if (first === '#' || first === '/') {\n return true\n }\n\n const colonIndex = url.indexOf(':')\n if (colonIndex === -1) {\n return true\n }\n\n const allowedProtocols = ['http', 'https', 'mailto', 'tel']\n const proto = url.slice(0, colonIndex).toLowerCase()\n if (allowedProtocols.indexOf(proto) !== -1) {\n return true\n }\n\n const queryIndex = url.indexOf('?')\n if (queryIndex !== -1 && colonIndex > queryIndex) {\n return true\n }\n\n const hashIndex = url.indexOf('#')\n if (hashIndex !== -1 && colonIndex > hashIndex) {\n return true\n }\n\n return false\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownMarkRenderer: PortableTextMarkRenderer = ({\n children,\n}) => {\n return children\n}\n","import type {PortableTextBlock} from '@portabletext/types'\nimport type {PortableTextRenderer} from '../types'\n\ntype PortableTextBlockRenderer = PortableTextRenderer<PortableTextBlock>\n\n/**\n * @public\n */\nexport const DefaultNormalRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Empty blocks should not add extra spacing\n if (!children || children.trim() === '') {\n return ''\n }\n\n return children\n}\n\n/**\n * @public\n */\nexport const DefaultBlockquoteRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Prefix each line with \"> \" for proper blockquote formatting\n // This handles multi-line content and preserves empty lines\n if (!children) {\n return '>'\n }\n\n return children\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultH1Renderer: PortableTextBlockRenderer = ({children}) =>\n `# ${children}`\n\n/**\n * @public\n */\nexport const DefaultH2Renderer: PortableTextBlockRenderer = ({children}) =>\n `## ${children}`\n\n/**\n * @public\n */\nexport const DefaultH3Renderer: PortableTextBlockRenderer = ({children}) =>\n `### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH4Renderer: PortableTextBlockRenderer = ({children}) =>\n `#### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH5Renderer: PortableTextBlockRenderer = ({children}) =>\n `##### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH6Renderer: PortableTextBlockRenderer = ({children}) =>\n `###### ${children}`\n\n/**\n * @public\n */\nexport const DefaultUnknownStyleRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n return children ?? ''\n}\n","import type {PortableTextBlock, TypedObject} from '@portabletext/types'\nimport {\n escapeImageAndLinkText,\n escapeImageAndLinkTitle,\n escapeTableCell,\n} from '../../escape'\nimport type {PortableTextTypeRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultCodeBlockRenderer: PortableTextTypeRenderer<{\n _type: 'code'\n code: string\n language: string | undefined\n}> = ({value}) => {\n return `\\`\\`\\`${value.language ?? ''}\\n${value.code}\\n\\`\\`\\``\n}\n\n/**\n * @public\n */\nexport const DefaultHorizontalRuleRenderer: PortableTextTypeRenderer = () => {\n return '---'\n}\n\n/**\n * @public\n */\nexport const DefaultHtmlRenderer: PortableTextTypeRenderer<{\n _type: 'html'\n html: string\n}> = ({value}) => {\n return value.html\n}\n\n/**\n * @public\n */\nexport const DefaultImageRenderer: PortableTextTypeRenderer<{\n _type: 'image'\n src: string\n alt: string | undefined\n title: string | undefined\n}> = ({value}) => {\n const alt = escapeImageAndLinkText(value.alt ?? '')\n const title = value.title ? ` \"${escapeImageAndLinkTitle(value.title)}\"` : ''\n return `![${alt}](${value.src}${title})`\n}\n\n/**\n * Renders a Portable Text table block-object back to Markdown.\n *\n * The PT `headerRows` field decides the header. `headerRows === 0` is an\n * explicit headerless table: GFM has no headerless form, so an empty header\n * row is emitted and every row goes in the body (that empty header reads back\n * as `headerRows: 0` via `markdownToPortableText`). Any other value\n * (`undefined` or `>= 1`) promotes `rows[0]` to the header. GFM allows exactly\n * one header row, so header rows beyond the first flatten into the body,\n * lossy, but the extra rows stay on the Portable Text side.\n *\n * Asymmetric tables (rows of varying cell counts) are widened to match\n * the row with the most cells. Narrower rows are padded with empty cells\n * so a GFM parser doesn't silently drop the extra cells in wider rows.\n *\n * @public\n */\nexport const DefaultTableRenderer: PortableTextTypeRenderer<{\n _type: 'table'\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n cells: Array<{\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n}> = ({value, renderNode}) => {\n const rows = value.rows as Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<{_type: string; children?: Array<unknown>}>\n }>\n }>\n const alignment = value.alignment\n\n const headerRow = rows.at(0)\n\n if (!headerRow) {\n return ''\n }\n\n // Helper to extract text from cell blocks\n const getCellText = (\n cellBlocks: Array<{_type: string; children?: Array<unknown>}>,\n ): string => {\n return cellBlocks\n .map((block, index) =>\n renderNode({\n node: block as {_type: string},\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join(' ')\n .trim()\n }\n\n const lines: string[] = []\n\n // GFM requires every row to have the same number of cells as the header row\n // and the delimiter row. Parsers silently drop excess cells from body rows\n // that are wider than the header, so we widen the table to the widest row\n // and pad narrower rows with empty cells to keep all data visible.\n const columnCount = rows.reduce(\n (max, row) => Math.max(max, row.cells.length),\n 0,\n )\n\n const renderCells = (texts: Array<string>): string => {\n const padded = [...texts]\n while (padded.length < columnCount) {\n padded.push('')\n }\n return `| ${padded.join(' | ')} |`\n }\n\n const renderRow = (cells: typeof headerRow.cells): string =>\n renderCells(cells.map((cell) => escapeTableCell(getCellText(cell.value))))\n\n // Delimiter row, sized to the column count. Each cell's colons encode the\n // column's alignment as defined by `value.alignment[columnIndex]`.\n const separators = Array.from({length: columnCount}, (_, index) => {\n const align = alignment?.at(index)\n if (align === 'left') {\n return ' :--- '\n }\n if (align === 'center') {\n return ' :---: '\n }\n if (align === 'right') {\n return ' ---: '\n }\n return ' --- '\n })\n const delimiter = `|${separators.join('|')}|`\n\n if (value.headerRows === 0) {\n // Explicit headerless table: emit an empty header row and keep every row\n // in the body.\n lines.push(renderCells([]))\n lines.push(delimiter)\n for (const row of rows) {\n lines.push(renderRow(row.cells))\n }\n } else {\n // `rows[0]` is the header. Header rows beyond the first flatten into the\n // body (GFM has a single header row).\n lines.push(renderRow(headerRow.cells))\n lines.push(delimiter)\n for (let i = 1; i < rows.length; i++) {\n const row = rows.at(i)\n if (row) {\n lines.push(renderRow(row.cells))\n }\n }\n }\n\n return lines.join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultCalloutRenderer: PortableTextTypeRenderer<{\n _type: 'callout'\n tone: string\n content: Array<PortableTextBlock>\n}> = ({value, renderNode}) => {\n const renderedContent = value.content\n .map((block, index) =>\n renderNode({\n node: {...block, style: 'normal'},\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n const prefixed = renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n\n return `> [!${value.tone.toUpperCase()}]\\n${prefixed}`\n}\n\n/**\n * Renders a structural blockquote block-object (the `types.blockquote` shape\n * produced by `markdownToPortableText` when a `types.blockquote` matcher is\n * provided) back to Markdown. Each content block is rendered via the\n * recursive renderer pipeline, joined with blank lines, and every line is\n * prefixed with `> ` to form a Markdown blockquote.\n *\n * Distinct from `DefaultBlockquoteRenderer`, which renders flat-path text\n * blocks with `style: 'blockquote'`.\n *\n * @public\n */\nexport const DefaultBlockquoteObjectRenderer: PortableTextTypeRenderer<{\n _type: 'blockquote'\n content: Array<PortableTextBlock>\n}> = ({value, renderNode}) => {\n const renderedContent = value.content\n .map((block, index) =>\n renderNode({\n node: {...block, style: 'normal'},\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n return renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n}\n\n/**\n * Renders a structural list block-object (the `types.list` shape produced by\n * `markdownToPortableText` when a `types.list` matcher is provided) back to\n * Markdown. Items render as `- ` for `kind: 'bullet'`, `1. `/`2. ` for `'number'`,\n * and `- [x] ` / `- [ ] ` for `'task'`. Items can hold any blocks - text blocks,\n * code blocks, callouts, images, and nested lists - and content other than the\n * leading text block is indented to keep it inside the item.\n *\n * @public\n */\nexport const DefaultListRenderer: PortableTextTypeRenderer<{\n _type: 'list'\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | TypedObject>\n }>\n}> = ({value, renderNode}) => {\n // A list is \"loose\" when any item carries multiple non-list-block\n // content entries (a continuation paragraph, a code block, etc).\n // CommonMark uses blank lines between items in loose lists; tight lists\n // pack items together with single newlines. A nested list as a second\n // child of an item does NOT make the list loose, so we ignore those when\n // counting.\n const isLoose = value.items.some((item) => {\n const nonNestedBlocks = item.content.filter(\n (block) => (block as TypedObject)._type !== 'list',\n )\n return nonNestedBlocks.length > 1\n })\n const itemSeparator = isLoose ? '\\n\\n' : '\\n'\n\n const lines = value.items.map((item, itemIndex) => {\n const marker = getListMarker(value.kind, itemIndex, item.checked)\n // Continuation indent matches the marker's width so that subsequent\n // blocks attach to this item under CommonMark's lazy-continuation rule.\n // Bullet `- ` indents to 2; ordered `1. ` indents to 3, `10. ` to 4.\n // Task `- [x] ` is conceptually `- ` + a `[x] ` content prefix at the\n // markdown-it level, so its continuation indent stays at 2.\n const indentWidth = value.kind === 'task' ? 2 : marker.length\n const indent = ' '.repeat(indentWidth)\n\n const renderedBlocks = item.content.map((block, blockIndex) => ({\n isNestedList: (block as TypedObject)._type === 'list',\n text: renderNode({\n node: block as TypedObject,\n index: blockIndex,\n isInline: false,\n renderNode,\n }),\n }))\n\n const [first, ...rest] = renderedBlocks\n // Trim trailing whitespace from empty items so `- ` becomes `-`.\n const head = `${marker}${first?.text ?? ''}`.trimEnd()\n if (rest.length === 0) {\n return head\n }\n\n const tail = rest\n .map((rendered) => {\n const indented = rendered.text\n .split('\\n')\n .map((line) => (line === '' ? '' : `${indent}${line}`))\n .join('\\n')\n // Nested lists hug the previous block (tight list); other content\n // gets a blank line separator (paragraph break).\n return rendered.isNestedList ? `\\n${indented}` : `\\n\\n${indented}`\n })\n .join('')\n\n return `${head}${tail}`\n })\n\n return lines.join(itemSeparator)\n}\n\nfunction getListMarker(\n kind: 'bullet' | 'number' | 'task',\n itemIndex: number,\n checked: boolean | undefined,\n): string {\n if (kind === 'number') {\n return `${itemIndex + 1}. `\n }\n if (kind === 'task') {\n return checked ? '- [x] ' : '- [ ] '\n }\n return '- '\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownTypeRenderer: PortableTextTypeRenderer = ({\n value,\n isInline,\n}) => {\n const json = `\\`\\`\\`json\\n${JSON.stringify(value, null, 2)}\\n\\`\\`\\``\n // For inline unknown types, add newlines to break them out of the text flow\n return isInline ? `\\n${json}\\n` : json\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n TypedObject,\n} from '@portabletext/types'\nimport {buildListIndexMap} from './build-list-index-map'\nimport {createRenderNode} from './render-node'\nimport {\n DefaultBlockSpacingRenderer,\n type BlockSpacingRenderer,\n} from './renderers/block-spacing'\nimport {DefaultHardBreakRenderer} from './renderers/hard-break'\nimport {\n DefaultListItemRenderer,\n DefaultUnknownListItemRenderer,\n} from './renderers/list-item'\nimport {\n DefaultCodeRenderer,\n DefaultEmRenderer,\n DefaultLinkRenderer,\n DefaultStrikeThroughRenderer,\n DefaultStrongRenderer,\n DefaultUnderlineRenderer,\n DefaultUnknownMarkRenderer,\n} from './renderers/marks'\nimport {\n DefaultBlockquoteRenderer,\n DefaultH1Renderer,\n DefaultH2Renderer,\n DefaultH3Renderer,\n DefaultH4Renderer,\n DefaultH5Renderer,\n DefaultH6Renderer,\n DefaultNormalRenderer,\n DefaultUnknownStyleRenderer,\n} from './renderers/style'\nimport {DefaultUnknownTypeRenderer} from './renderers/type'\nimport type {PortableTextRenderers} from './types'\n\nconst defaultRenderers: PortableTextRenderers = {\n types: {},\n\n block: {\n normal: DefaultNormalRenderer,\n blockquote: DefaultBlockquoteRenderer,\n h1: DefaultH1Renderer,\n h2: DefaultH2Renderer,\n h3: DefaultH3Renderer,\n h4: DefaultH4Renderer,\n h5: DefaultH5Renderer,\n h6: DefaultH6Renderer,\n },\n marks: {\n 'em': DefaultEmRenderer,\n 'strong': DefaultStrongRenderer,\n 'code': DefaultCodeRenderer,\n 'underline': DefaultUnderlineRenderer,\n 'strike-through': DefaultStrikeThroughRenderer,\n 'link': DefaultLinkRenderer,\n },\n listItem: DefaultListItemRenderer,\n hardBreak: DefaultHardBreakRenderer,\n\n unknownType: DefaultUnknownTypeRenderer,\n unknownMark: DefaultUnknownMarkRenderer,\n unknownListItem: DefaultUnknownListItemRenderer,\n unknownBlockStyle: DefaultUnknownStyleRenderer,\n}\n\ntype Options = Partial<PortableTextRenderers> & {\n blockSpacing?: BlockSpacingRenderer\n}\n\n/**\n * @public\n */\nexport function portableTextToMarkdown<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(blocks: Array<Block>, options: Options = {}): string {\n const renderers = {\n block: {\n ...defaultRenderers.block,\n ...options.block,\n },\n listItem: options.listItem ?? defaultRenderers.listItem,\n marks: {\n ...defaultRenderers.marks,\n ...options.marks,\n },\n types: {\n ...defaultRenderers.types,\n ...options.types,\n },\n hardBreak: options.hardBreak ?? defaultRenderers.hardBreak,\n unknownType: options.unknownType ?? defaultRenderers.unknownType,\n unknownBlockStyle:\n options.unknownBlockStyle ?? defaultRenderers.unknownBlockStyle,\n unknownListItem:\n options.unknownListItem ?? defaultRenderers.unknownListItem,\n unknownMark: options.unknownMark ?? defaultRenderers.unknownMark,\n }\n const renderBlockSpacing = options.blockSpacing ?? DefaultBlockSpacingRenderer\n\n const {listIndexMap, listDepthMap} = buildListIndexMap(blocks)\n const renderNode = createRenderNode(renderers, listIndexMap, listDepthMap)\n\n return blocks\n .map((node, index) => {\n const renderedNode = renderNode({\n node,\n index,\n isInline: false,\n renderNode,\n })\n\n if (index === blocks.length - 1) {\n return renderedNode\n }\n\n const nextNode = blocks.at(index + 1)\n\n if (!nextNode) {\n return renderedNode\n }\n\n const blockSpacing =\n renderBlockSpacing({\n current: node,\n next: nextNode,\n }) ?? '\\n\\n'\n\n return `${renderedNode}${blockSpacing}`\n })\n .join('')\n}\n","import {\n compileSchema,\n defineSchema,\n type AnnotationDefinition,\n type BlockObjectDefinition,\n type DecoratorDefinition,\n type ListDefinition,\n type StyleDefinition,\n} from '@portabletext/schema'\n\n/********************\n * Default style definitions\n ********************/\n\nexport const normalStyleDefinition = {\n name: 'normal',\n} as const satisfies StyleDefinition\n\nexport const h1StyleDefinition = {\n name: 'h1',\n} as const satisfies StyleDefinition\n\nexport const h2StyleDefinition = {\n name: 'h2',\n} as const satisfies StyleDefinition\n\nexport const h3StyleDefinition = {\n name: 'h3',\n} as const satisfies StyleDefinition\n\nexport const h4StyleDefinition = {\n name: 'h4',\n} as const satisfies StyleDefinition\n\nexport const h5StyleDefinition = {\n name: 'h5',\n} as const satisfies StyleDefinition\n\nexport const h6StyleDefinition = {\n name: 'h6',\n} as const satisfies StyleDefinition\n\nexport const blockquoteStyleDefinition = {\n name: 'blockquote',\n} as const satisfies StyleDefinition\n\n/********************\n * Default list definitions\n ********************/\n\nexport const defaultOrderedListItemDefinition = {\n name: 'number',\n} as const satisfies ListDefinition\n\nexport const defaultUnorderedListItemDefinition = {\n name: 'bullet',\n} as const satisfies ListDefinition\n\nexport const defaultTaskListItemDefinition = {\n name: 'task',\n} as const satisfies ListDefinition\n\n/********************\n * Default decorator definitions\n ********************/\n\nexport const defaultStrongDecoratorDefinition = {\n name: 'strong',\n} as const satisfies DecoratorDefinition\n\nexport const defaultEmDecoratorDefinition = {\n name: 'em',\n} as const satisfies DecoratorDefinition\n\nexport const defaultCodeDecoratorDefinition = {\n name: 'code',\n} as const satisfies DecoratorDefinition\n\nexport const defaultStrikeThroughDecoratorDefinition = {\n name: 'strike-through',\n} as const satisfies DecoratorDefinition\n\n/********************\n * Default annotation definitions\n ********************/\n\nexport const defaultLinkObjectDefinition = {\n name: 'link',\n fields: [\n {name: 'href', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies AnnotationDefinition\n\n/********************\n * Default object definitions\n ********************/\n\nexport const defaultCodeObjectDefinition = {\n name: 'code',\n fields: [\n {name: 'language', type: 'string'},\n {name: 'code', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultImageObjectDefinition = {\n name: 'image',\n fields: [\n {name: 'src', type: 'string'},\n {name: 'alt', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHorizontalRuleObjectDefinition = {\n name: 'horizontal-rule',\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHtmlObjectDefinition = {\n name: 'html',\n fields: [{name: 'html', type: 'string'}],\n} as const satisfies BlockObjectDefinition\n\nconst defaultTableObjectDefinition = {\n name: 'table',\n fields: [\n {name: 'headerRows', type: 'number'},\n {name: 'alignment', type: 'array'},\n {name: 'rows', type: 'array'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultCalloutObjectDefinition = {\n name: 'callout',\n fields: [\n {name: 'tone', type: 'string'},\n {name: 'content', type: 'array'},\n ],\n} as const satisfies BlockObjectDefinition\n\n/**\n * The default schema for converting markdown to Portable Text.\n *\n * @public\n */\nexport const defaultSchema = compileSchema(\n defineSchema({\n block: {\n fields: [{name: 'checked', type: 'boolean'}],\n },\n styles: [\n normalStyleDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n blockquoteStyleDefinition,\n ],\n lists: [\n defaultOrderedListItemDefinition,\n defaultUnorderedListItemDefinition,\n defaultTaskListItemDefinition,\n ],\n decorators: [\n defaultStrongDecoratorDefinition,\n defaultEmDecoratorDefinition,\n defaultCodeDecoratorDefinition,\n defaultStrikeThroughDecoratorDefinition,\n ],\n annotations: [defaultLinkObjectDefinition],\n blockObjects: [\n defaultCalloutObjectDefinition,\n defaultCodeObjectDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultTableObjectDefinition,\n ],\n inlineObjects: [defaultImageObjectDefinition],\n }),\n)\n","import type {\n PortableTextObject,\n Schema,\n SchemaDefinition,\n} from '@portabletext/schema'\n\n/**\n * Matcher function for mapping markdown elements to Portable Text block styles.\n *\n * @public\n */\nexport type StyleMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildStyleMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): StyleMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.styles.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown list items to Portable Text list types.\n *\n * @public\n */\nexport type ListItemMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildListItemMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ListItemMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.lists.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown inline formatting to Portable Text decorators.\n *\n * @public\n */\nexport type DecoratorMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildDecoratorMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): DecoratorMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.decorators.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown links to Portable Text annotations.\n *\n * @public\n */\nexport type AnnotationMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n}) => PortableTextObject | undefined\n\nexport function buildAnnotationMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): AnnotationMatcher<ExtractValue<TDefinition>> {\n return ({context, value}) => {\n const schemaDefinition = context.schema.annotations.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n const filteredValue = schemaDefinition.fields.reduce<\n Record<string, unknown>\n >((filteredValue, field) => {\n const fieldValue = value[field.name as keyof typeof value]\n\n if (fieldValue !== undefined) {\n filteredValue[field.name] = fieldValue\n }\n\n return filteredValue\n }, {})\n\n return {\n _key: context.keyGenerator(),\n _type: schemaDefinition.name,\n ...filteredValue,\n }\n }\n}\n\n/**\n * Matcher function for mapping markdown objects to Portable Text block or inline objects.\n *\n * @public\n */\nexport type ObjectMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n isInline,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n isInline: boolean\n}) => PortableTextObject | undefined\n\nexport function buildObjectMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ObjectMatcher<ExtractValue<TDefinition>> {\n return ({context, value, isInline}) => {\n const schemaCollection = isInline\n ? context.schema.inlineObjects\n : context.schema.blockObjects\n\n const schemaDefinition = schemaCollection.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n const filteredValue = schemaDefinition.fields.reduce<\n Record<string, unknown>\n >((filteredValue, field) => {\n const fieldValue = value[field.name as keyof typeof value]\n\n if (fieldValue !== undefined) {\n filteredValue[field.name] = fieldValue\n }\n\n return filteredValue\n }, {})\n\n return {\n _key: context.keyGenerator(),\n _type: schemaDefinition.name,\n ...filteredValue,\n }\n }\n}\n\nexport type ExtractValue<\n TDefinition extends NonNullable<SchemaDefinition['blockObjects']>[0],\n> = TDefinition extends {fields: ReadonlyArray<{name: infer TNames}>}\n ? Record<TNames & string, unknown>\n : Record<string, never>\n","import {alert} from '@mdit/plugin-alert'\nimport {\n isSpan,\n isTextBlock,\n type PortableTextBlock,\n type PortableTextObject,\n type PortableTextTextBlock,\n type Schema,\n} from '@portabletext/schema'\nimport markdownit from 'markdown-it'\nimport {\n blockquoteStyleDefinition,\n defaultCalloutObjectDefinition,\n defaultCodeDecoratorDefinition,\n defaultCodeObjectDefinition,\n defaultEmDecoratorDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultLinkObjectDefinition,\n defaultOrderedListItemDefinition,\n defaultSchema,\n defaultStrikeThroughDecoratorDefinition,\n defaultStrongDecoratorDefinition,\n defaultTaskListItemDefinition,\n defaultUnorderedListItemDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n normalStyleDefinition,\n} from '../default-schema'\nimport {unescapeImageAndLinkText} from '../escape'\nimport {defaultKeyGenerator} from '../key-generator'\nimport {\n buildAnnotationMatcher,\n buildDecoratorMatcher,\n buildListItemMatcher,\n buildObjectMatcher,\n buildStyleMatcher,\n type AnnotationMatcher,\n type DecoratorMatcher,\n type ExtractValue,\n type ListItemMatcher,\n type ObjectMatcher,\n type StyleMatcher,\n} from './matchers'\n\ntype Options = {\n schema?: Schema\n keyGenerator?: () => string\n marks?: {\n strong?: DecoratorMatcher\n em?: DecoratorMatcher\n code?: DecoratorMatcher\n strikeThrough?: DecoratorMatcher\n link?: AnnotationMatcher<{href: string; title: string | undefined}>\n }\n block?: {\n normal?: StyleMatcher\n blockquote?: StyleMatcher\n h1?: StyleMatcher\n h2?: StyleMatcher\n h3?: StyleMatcher\n h4?: StyleMatcher\n h5?: StyleMatcher\n h6?: StyleMatcher\n }\n listItem?: {\n number?: ListItemMatcher\n bullet?: ListItemMatcher\n task?: ListItemMatcher\n }\n types?: {\n code?: ObjectMatcher<{language: string | undefined; code: string}>\n horizontalRule?: ObjectMatcher\n html?: ObjectMatcher<{html: string}>\n table?: ObjectMatcher<{\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n }>\n image?: ObjectMatcher<{src: string; alt: string; title: string | undefined}>\n callout?: ObjectMatcher<{tone: string; content: Array<PortableTextBlock>}>\n blockquote?: ObjectMatcher<{content: Array<PortableTextBlock>}>\n list?: ObjectMatcher<{\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }>\n }>\n }\n html?: {\n /**\n * How to handle inline HTML.\n * - 'skip': Ignore inline HTML (default)\n * - 'text': Convert inline HTML to plain text\n *\n * @defaultValue 'skip'\n */\n inline?: 'skip' | 'text'\n }\n}\n\nconst codeBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultCodeObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultCodeObjectDefinition)\n const codeObject = defaultMatcher({context, value, isInline})\n\n if (!codeObject) {\n return undefined\n }\n\n if (!('code' in codeObject)) {\n return undefined\n }\n\n return codeObject\n}\n\nconst imageBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultImageObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultImageObjectDefinition)\n const imageObject = defaultMatcher({context, value, isInline})\n\n if (!imageObject) {\n return undefined\n }\n\n if (!('src' in imageObject)) {\n return undefined\n }\n\n return imageObject\n}\n\nconst defaultOptions = {\n schema: defaultSchema,\n keyGenerator: defaultKeyGenerator,\n html: {\n inline: 'skip',\n },\n block: {\n normal: buildStyleMatcher(normalStyleDefinition),\n blockquote: buildStyleMatcher(blockquoteStyleDefinition),\n h1: buildStyleMatcher(h1StyleDefinition),\n h2: buildStyleMatcher(h2StyleDefinition),\n h3: buildStyleMatcher(h3StyleDefinition),\n h4: buildStyleMatcher(h4StyleDefinition),\n h5: buildStyleMatcher(h5StyleDefinition),\n h6: buildStyleMatcher(h6StyleDefinition),\n },\n listItem: {\n number: buildListItemMatcher(defaultOrderedListItemDefinition),\n bullet: buildListItemMatcher(defaultUnorderedListItemDefinition),\n task: buildListItemMatcher(defaultTaskListItemDefinition),\n },\n marks: {\n strong: buildDecoratorMatcher(defaultStrongDecoratorDefinition),\n em: buildDecoratorMatcher(defaultEmDecoratorDefinition),\n code: buildDecoratorMatcher(defaultCodeDecoratorDefinition),\n strikeThrough: buildDecoratorMatcher(\n defaultStrikeThroughDecoratorDefinition,\n ),\n link: buildAnnotationMatcher(defaultLinkObjectDefinition),\n },\n types: {\n code: codeBlockMatcher,\n horizontalRule: buildObjectMatcher(defaultHorizontalRuleObjectDefinition),\n html: buildObjectMatcher(defaultHtmlObjectDefinition),\n image: imageBlockMatcher,\n callout: buildObjectMatcher(defaultCalloutObjectDefinition),\n },\n} as const satisfies Options\n\n/**\n * Reads GFM column alignment from a markdown-it cell token's `style`\n * attribute. Tolerates other CSS declarations sharing the value.\n */\nexport function extractAlignmentFromStyleAttr(\n styleAttr: string | null,\n): 'left' | 'center' | 'right' | null {\n if (!styleAttr) {\n return null\n }\n const match = styleAttr.match(/text-align\\s*:\\s*(left|center|right)/)\n if (!match) {\n return null\n }\n return match[1] as 'left' | 'center' | 'right'\n}\n\n/**\n * A table row is empty when every cell holds only blank spans, no non-empty\n * text, no inline objects, no non-text blocks. Used to detect a headerless\n * GFM table: `portableTextToMarkdown` emits an empty header row for\n * `headerRows: 0`, and an empty header must round-trip back to\n * `headerRows: 0` rather than a phantom header row.\n */\nfunction isEmptyTableRow(\n cells: Array<{value: Array<PortableTextBlock>}>,\n context: {schema: Schema},\n): boolean {\n return cells.every((cell) =>\n cell.value.every(\n (block) =>\n isTextBlock(context, block) &&\n block.children.every(\n (child) => isSpan(context, child) && (child.text ?? '').trim() === '',\n ),\n ),\n )\n}\n\n/**\n * Flattens a table structure by lifting all blocks from all cells.\n */\nfunction flattenTable(\n table: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n },\n portableText: Array<PortableTextBlock>,\n): void {\n // Flatten the table by lifting all blocks from all cells\n for (const row of table.rows) {\n for (const cell of row.cells) {\n for (const block of cell.value) {\n portableText.push(block)\n }\n }\n }\n}\n\n/**\n * Converts a markdown string to an array of Portable Text blocks.\n *\n * @public\n */\nexport function markdownToPortableText(\n markdown: string,\n options?: Options,\n): Array<PortableTextBlock> {\n const consolidatedOptions = {\n schema: options?.schema ?? defaultSchema,\n keyGenerator: options?.keyGenerator ?? defaultKeyGenerator,\n html: {\n inline: options?.html?.inline ?? 'skip',\n },\n marks: {\n ...defaultOptions.marks,\n ...options?.marks,\n },\n block: {\n ...defaultOptions.block,\n ...options?.block,\n },\n listItem: {\n ...defaultOptions.listItem,\n ...options?.listItem,\n },\n types: {\n ...defaultOptions.types,\n ...options?.types,\n },\n }\n\n const md = markdownit({\n html: true,\n linkify: true,\n typographer: false,\n })\n .enable(['strikethrough', 'table'])\n .use(alert)\n\n const tokens = md.parse(markdown, {})\n\n // Pre-pass: detect GFM task-list checkbox prefixes (`[ ]`, `[x]`, `[X]`)\n // on the first inline content of each list item. Strip the prefix from the\n // inline content and remember which list items are tasks (and their checked\n // state) so the main walk can apply `listItem: 'task'` and `checked` when\n // processing the corresponding `list_item_open` token.\n const taskCheckedByListItemIndex = new Map<number, boolean>()\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]\n if (token?.type !== 'list_item_open') {\n continue\n }\n // Find the first inline token within this list item.\n let inlineIndex = -1\n for (let j = i + 1; j < tokens.length; j++) {\n const candidate = tokens[j]\n if (!candidate) {\n continue\n }\n if (candidate.type === 'list_item_close') {\n break\n }\n if (candidate.type === 'inline') {\n inlineIndex = j\n break\n }\n }\n if (inlineIndex === -1) {\n continue\n }\n const inlineToken = tokens[inlineIndex]\n if (!inlineToken) {\n continue\n }\n const match = inlineToken.content.match(/^\\[([ xX])\\] /)\n if (!match) {\n continue\n }\n const checked = match[1] !== ' '\n taskCheckedByListItemIndex.set(i, checked)\n // Strip the prefix from the content and the first child text token so the\n // resulting span doesn't include the checkbox marker.\n inlineToken.content = inlineToken.content.slice(match[0].length)\n const firstChild = inlineToken.children?.[0]\n if (firstChild && typeof firstChild.content === 'string') {\n firstChild.content = firstChild.content.slice(match[0].length)\n }\n }\n\n const portableText: Array<PortableTextBlock> = []\n\n // State\n let currentBlock: PortableTextTextBlock | null = null\n const currentListStack: Array<string | null> = []\n const markDefRefs: Array<string> = [] // mark keys: 'strong', 'em', 'code', or link keys\n let currentMarkDefs: Array<PortableTextObject> = []\n let currentBlockquoteStyle: string | null = null // Track blockquote style when inside blockquote\n let inListItem = false // Track if we're inside a list item\n\n // Callout state\n let calloutStartIndex: number | null = null\n let calloutStartTarget: Array<PortableTextBlock | PortableTextObject> | null =\n null\n let calloutType: string | null = null\n\n // Blockquote container state. When `types.blockquote` is defined and the\n // parser enters a `blockquote_open`, a frame is pushed here. Block\n // emissions inside the surrounding open/close pair are captured and\n // spliced out at close to wrap them in a `blockquote` block-object.\n // Nested blockquotes push additional frames; `blockTarget()` already\n // routes correctly because the splice happens against the same target.\n const blockquoteStack: Array<{\n startTarget: Array<PortableTextBlock | PortableTextObject>\n startIndex: number\n }> = []\n\n // Table state\n let currentTable: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n emptyHeaderDropped: boolean\n alignment: Array<'left' | 'center' | 'right' | null>\n } | null = null\n let currentTableRow: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }> | null = null\n let inTableHead = false\n\n // List container state. When `types.list` is defined and the parser enters\n // a `bullet_list_open` / `ordered_list_open`, a structural-list frame is\n // pushed here. Block emissions inside the surrounding `list_item_open` /\n // `list_item_close` pair are diverted into the item's `content` array\n // instead of the top-level `portableText`. At list-close, the matcher is\n // called to materialize a `list` block-object, which is pushed into the\n // enclosing target (parent list item's content if nested, else top-level).\n type ListContainerItem = {\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }\n type ListContainerFrame = {\n kind: 'bullet' | 'number' | 'task'\n items: Array<ListContainerItem>\n currentItem: ListContainerItem | null\n }\n // A null entry marks a list that is being handled by the flat path (either\n // because `types.list` is undefined, or because a nested list inside a\n // flat-path list should also stay flat). Parallel to `currentListStack`.\n const listContainerStack: Array<ListContainerFrame | null> = []\n\n /**\n * Returns the array that block emissions should land in. If the innermost\n * structural list frame has an open `currentItem`, blocks land in that\n * item's `content`. Otherwise blocks land at the top level.\n */\n const blockTarget = (): Array<PortableTextBlock | PortableTextObject> => {\n for (let i = listContainerStack.length - 1; i >= 0; i--) {\n const frame = listContainerStack[i]\n if (frame && frame.currentItem) {\n return frame.currentItem.content\n }\n }\n return portableText\n }\n\n /**\n * Pushes a block into the current target (innermost open list item, or\n * top-level `portableText` if none). Use instead of direct\n * `portableText.push(...)` for any block emission that should be captured\n * by an enclosing list container.\n */\n const pushBlock = (block: PortableTextBlock | PortableTextObject): void => {\n blockTarget().push(block as PortableTextBlock)\n }\n\n const startBlock = (style: string) => {\n flushBlock()\n currentBlock = {\n _type: 'block' as const,\n style,\n children: [],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n }\n currentMarkDefs = []\n }\n\n const flushBlock = () => {\n if (!currentBlock) {\n return\n }\n\n // Text blocks must have at least one child span\n if (currentBlock.children.length === 0) {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n })\n }\n\n // Assign accumulated markDefs to the block\n currentBlock.markDefs = currentMarkDefs\n\n pushBlock(currentBlock)\n\n currentBlock = null\n currentMarkDefs = []\n }\n\n const addSpan = (text: string) => {\n if (text.length === 0) {\n return\n }\n\n if (!currentBlock) {\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n const lastChild = currentBlock.children.at(-1)\n\n if (\n isSpan({schema: consolidatedOptions.schema}, lastChild) &&\n lastChild.marks?.every((mark) => markDefRefs.includes(mark)) &&\n markDefRefs.every((mark) => lastChild.marks?.includes(mark))\n ) {\n // Merge with previous span if marks match\n lastChild.text += text\n } else {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: text,\n marks: [...markDefRefs],\n })\n }\n }\n\n // Helpers for lists\n const listLevel = () => currentListStack.length\n const ensureListBlock = (listItem: string, checked?: boolean) => {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n if (\n currentBlock.listItem !== listItem ||\n currentBlock.level !== listLevel()\n ) {\n currentBlock.listItem = listItem\n currentBlock.level = listLevel()\n }\n\n if (checked !== undefined) {\n ;(currentBlock as PortableTextTextBlock & {checked?: boolean}).checked =\n checked\n }\n }\n\n // Walk tokens\n for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {\n const token = tokens[tokenIndex]\n if (!token) {\n continue\n }\n\n switch (token.type) {\n // Paragraphs\n case 'paragraph_open': {\n // If we're in a list item but have no current block (e.g., after a code block),\n // we need to create a new list item block\n if (inListItem) {\n // Structural list path: start a plain text block; the paragraph\n // lands in the current list item's `content` via `pushBlock`.\n if (listContainerStack.at(-1)) {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ??\n 'normal'\n startBlock(style)\n }\n break\n }\n\n // Flat list path: ensure the current text block carries\n // `listItem` + `level` fields.\n if (!currentBlock) {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n\n break\n }\n\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n break\n }\n\n startBlock(style)\n break\n }\n case 'paragraph_close':\n // In a flat list item: skip flushing, list_item_close will flush.\n // In a structural list item: flush so multiple paragraphs in one\n // item land as separate text blocks.\n if (inListItem) {\n if (listContainerStack.at(-1)) {\n flushBlock()\n }\n break\n }\n flushBlock()\n break\n\n // Headings\n case 'heading_open': {\n const level = Number(token?.tag?.slice(1))\n\n // Map level to the appropriate heading matcher\n const headingMatchers = {\n 1: consolidatedOptions.block.h1,\n 2: consolidatedOptions.block.h2,\n 3: consolidatedOptions.block.h3,\n 4: consolidatedOptions.block.h4,\n 5: consolidatedOptions.block.h5,\n 6: consolidatedOptions.block.h6,\n } as const\n\n const headingMatcher =\n headingMatchers[level as keyof typeof headingMatchers]\n\n const style =\n headingMatcher?.({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No heading style found, using \"normal\"')\n startBlock('normal')\n break\n }\n\n startBlock(style)\n break\n }\n case 'heading_close':\n flushBlock()\n break\n\n // Blockquote\n case 'blockquote_open': {\n // Flush any current block before entering blockquote\n flushBlock()\n\n // Structural-blockquote path: when the consumer registers a\n // `types.blockquote` matcher, plain blockquotes (NOT GFM alerts -\n // those use separate `alert_open`/`alert_close` tokens) become\n // block-objects with an explicit `content` array. Block emissions\n // inside the open/close pair are spliced out at close time and\n // wrapped in a `blockquote` block-object.\n if (consolidatedOptions.types.blockquote) {\n const startTarget = blockTarget()\n blockquoteStack.push({\n startTarget,\n startIndex: startTarget.length,\n })\n break\n }\n\n // Flat path: set the blockquote style for paragraphs inside the\n // blockquote so they emit text blocks with `style: 'blockquote'`.\n const style =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n case 'blockquote_close': {\n // Flush any blockquote content before exiting\n flushBlock()\n\n // Structural path: pop the topmost frame and splice its captured\n // content into a `blockquote` block-object via the matcher. If the\n // matcher returns undefined, fall back to flat-style by re-emitting\n // the content blocks with `style: 'blockquote'`.\n if (\n consolidatedOptions.types.blockquote &&\n blockquoteStack.length > 0\n ) {\n const frame = blockquoteStack.pop()\n if (frame) {\n const contentBlocks = frame.startTarget.splice(\n frame.startIndex,\n ) as Array<PortableTextBlock>\n\n const blockquoteObject = consolidatedOptions.types.blockquote({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {content: contentBlocks},\n isInline: false,\n })\n\n if (blockquoteObject) {\n pushBlock(blockquoteObject)\n } else {\n // Matcher returned undefined: fall back to flat-style by\n // re-emitting each content block with `style: 'blockquote'`.\n const blockquoteStyle =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ??\n 'blockquote'\n for (const block of contentBlocks) {\n if (block._type === 'block') {\n pushBlock({\n ...(block as PortableTextTextBlock),\n style: blockquoteStyle,\n })\n } else {\n pushBlock(block)\n }\n }\n }\n }\n break\n }\n\n currentBlockquoteStyle = null\n break\n }\n // Lists\n case 'bullet_list_open': {\n flushBlock()\n\n // Structural-container path: when the consumer registers a\n // `types.list` matcher, lists become block-objects with explicit\n // `items` arrays. Block emissions inside list items are diverted\n // into `currentItem.content` via `blockTarget()`. Mirrors the\n // `types.table` pattern.\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'bullet',\n items: [],\n currentItem: null,\n })\n currentListStack.push(null)\n break\n }\n\n // Flat path: lists are reconstructed from text blocks with\n // `listItem` + `level` fields at render time.\n const listItem = consolidatedOptions.listItem.bullet({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n currentListStack.push(null)\n break\n }\n currentListStack.push(listItem)\n break\n }\n case 'ordered_list_open': {\n flushBlock()\n\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'number',\n items: [],\n currentItem: null,\n })\n currentListStack.push(null)\n break\n }\n\n const listItem = consolidatedOptions.listItem.number({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n currentListStack.push(null)\n break\n }\n currentListStack.push(listItem)\n break\n }\n case 'bullet_list_close':\n case 'ordered_list_close': {\n const frame = listContainerStack.pop()\n currentListStack.pop()\n\n // Structural close: materialize the list block-object and push it\n // into the enclosing target (parent list item's content if nested,\n // else top-level).\n if (frame && consolidatedOptions.types.list) {\n // Promote `kind` to 'task' if any item carries a checked state.\n const kind: 'bullet' | 'number' | 'task' = frame.items.some(\n (item) => 'checked' in item,\n )\n ? 'task'\n : frame.kind\n\n const listObject = consolidatedOptions.types.list({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {kind, items: frame.items},\n isInline: false,\n })\n\n if (listObject) {\n pushBlock(listObject)\n } else {\n // Matcher returned undefined: fall back to the flat path by\n // re-emitting each item's content. Text blocks get the same\n // `listItem` + `level` fields the flat path would produce so\n // adjacent blocks form a list at render time. Non-text-block\n // content (code blocks, etc.) gets pushed as-is, mirroring\n // how the flat path handles those when they appear inside a\n // list item.\n const flatListItem =\n (kind === 'task'\n ? consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n })\n : kind === 'number'\n ? consolidatedOptions.listItem.number({\n context: {schema: consolidatedOptions.schema},\n })\n : consolidatedOptions.listItem.bullet({\n context: {schema: consolidatedOptions.schema},\n })) ?? null\n // The just-popped list was nested at depth = remaining stack\n // length + 1 (since we already popped).\n const level = listContainerStack.length + 1\n for (const item of frame.items) {\n for (const block of item.content) {\n if (\n block._type === 'block' &&\n flatListItem !== null &&\n !('listItem' in block)\n ) {\n const flatBlock = {\n ...(block as PortableTextTextBlock),\n listItem: flatListItem,\n level,\n ...(item.checked === undefined\n ? {}\n : {checked: item.checked}),\n }\n pushBlock(flatBlock)\n } else {\n pushBlock(block)\n }\n }\n }\n }\n }\n break\n }\n case 'list_item_open': {\n const frame = listContainerStack.at(-1)\n\n // Flush any previous list item block before starting a new one\n // This is needed for proper separation of list items\n if (currentBlock) {\n flushBlock()\n }\n\n // Structural path: start a new `list-item` whose `content` becomes\n // the divert target for subsequent block emissions until\n // `list_item_close`.\n if (frame) {\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n frame.currentItem = {\n _type: 'list-item',\n _key: consolidatedOptions.keyGenerator(),\n ...(taskChecked === undefined ? {} : {checked: taskChecked}),\n content: [],\n }\n inListItem = true\n break\n }\n\n // Flat path\n const baseListType = currentListStack.at(-1)\n\n if (baseListType === undefined) {\n throw new Error('Expected an open list')\n }\n\n // Resolve task list type and checked state for this specific item.\n // If the schema declares a `task` list definition, GFM checkboxes\n // (`- [ ]` / `- [x]`) override the surrounding list's type for this\n // item. Otherwise the prefix has already been stripped by the\n // pre-pass and we render as the surrounding list type.\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n let listType = baseListType\n let checked: boolean | undefined\n if (taskChecked !== undefined) {\n const taskListType = consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n })\n if (taskListType) {\n listType = taskListType\n checked = taskChecked\n }\n }\n\n // If listType is null, it means there's no list definition in the schema\n // Just create a normal block without list properties\n if (listType === null) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n inListItem = true\n break\n }\n\n ensureListBlock(listType, checked)\n inListItem = true\n break\n }\n case 'list_item_close': {\n const frame = listContainerStack.at(-1)\n\n // Structural path: flush any current block into the item's content,\n // then push the completed item onto the frame.\n if (frame && frame.currentItem) {\n flushBlock()\n frame.items.push(frame.currentItem)\n frame.currentItem = null\n inListItem = false\n break\n }\n\n // Flat path\n inListItem = false\n flushBlock()\n break\n }\n\n // Code fences / blocks\n case 'fence': {\n flushBlock()\n\n const language = token.info.trim() || undefined\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language, code},\n isInline: false,\n })\n\n if (!codeObject) {\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n break\n }\n\n pushBlock(codeObject)\n\n break\n }\n\n // Horizontal rule\n case 'hr': {\n flushBlock()\n\n const hrObject = consolidatedOptions.types.horizontalRule({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {},\n isInline: false,\n })\n\n if (!hrObject) {\n // If there's no break definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan('---')\n flushBlock()\n break\n }\n\n pushBlock(hrObject)\n\n break\n }\n\n // HTML block\n case 'html_block': {\n flushBlock()\n\n const htmlContent = token.content.trim()\n\n if (!htmlContent) {\n break\n }\n\n const htmlObject = consolidatedOptions.types.html({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {html: htmlContent},\n isInline: false,\n })\n\n if (!htmlObject) {\n // If there's no HTML block definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(htmlContent)\n flushBlock()\n break\n }\n\n pushBlock(htmlObject)\n\n break\n }\n\n case 'code_block': {\n flushBlock()\n\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language: undefined, code},\n isInline: false,\n })\n\n if (!codeObject) {\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n } else {\n pushBlock(codeObject)\n }\n\n break\n }\n\n // Tables\n case 'table_open':\n flushBlock()\n currentTable = {\n rows: [],\n headerRows: 0,\n emptyHeaderDropped: false,\n alignment: [],\n }\n break\n\n case 'table_close': {\n if (!currentTable) {\n break\n }\n\n // Only create table object if table type is defined\n if (consolidatedOptions.types.table) {\n const hasAlignment = currentTable.alignment.some((a) => a !== null)\n const tableObject = consolidatedOptions.types.table({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {\n rows: currentTable.rows,\n headerRows:\n currentTable.headerRows > 0\n ? currentTable.headerRows\n : currentTable.emptyHeaderDropped\n ? 0\n : undefined,\n alignment: hasAlignment ? currentTable.alignment : undefined,\n },\n isInline: false,\n })\n\n if (tableObject) {\n pushBlock(tableObject)\n } else {\n // If table object couldn't be created, flatten the table\n flattenTable(\n currentTable,\n blockTarget() as Array<PortableTextBlock>,\n )\n }\n } else {\n // If there's no table definition in the schema, flatten the table\n flattenTable(currentTable, blockTarget() as Array<PortableTextBlock>)\n }\n\n currentTable = null\n break\n }\n\n case 'thead_open':\n inTableHead = true\n break\n\n case 'thead_close':\n inTableHead = false\n break\n\n case 'tbody_open':\n case 'tbody_close':\n // Just markers, no action needed\n break\n\n case 'tr_open':\n currentTableRow = []\n break\n\n case 'tr_close':\n if (currentTable && currentTableRow) {\n if (\n inTableHead &&\n isEmptyTableRow(currentTableRow, {\n schema: consolidatedOptions.schema,\n })\n ) {\n // An all-empty header row means \"no header\": drop it and leave\n // `headerRows` at 0 (recorded so `table_close` emits an explicit\n // 0, not `undefined`), so `portableTextToMarkdown`'s headerless\n // output round-trips back to `headerRows: 0`.\n currentTable.emptyHeaderDropped = true\n } else {\n currentTable.rows.push({\n _key: consolidatedOptions.keyGenerator(),\n _type: 'row',\n cells: currentTableRow,\n })\n if (inTableHead) {\n currentTable.headerRows++\n }\n }\n }\n currentTableRow = null\n break\n\n case 'th_open':\n case 'td_open': {\n // Alignment is per-column, set on every cell of that column. Read\n // from the header so each column contributes exactly one entry.\n if (currentTable && inTableHead && token.type === 'th_open') {\n currentTable.alignment.push(\n extractAlignmentFromStyleAttr(token.attrGet('style')),\n )\n }\n\n // Start a new block for the table cell\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n break\n }\n\n case 'th_close':\n case 'td_close': {\n // Flush the current block into the cell\n flushBlock()\n\n // Get all blocks that were added since this cell started\n // We need to extract them from the current target array\n const cellBlocks: Array<PortableTextBlock> = []\n const target = blockTarget()\n\n // Check if we have blocks to extract (added after table_open)\n if (target.length > 0) {\n const lastBlock = target.at(-1)\n if (lastBlock && lastBlock._type === 'block') {\n cellBlocks.push(target.pop()! as PortableTextBlock)\n }\n }\n\n // If no blocks were created (empty cell), create an empty block\n if (cellBlocks.length === 0) {\n cellBlocks.push({\n _type: 'block' as const,\n style:\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) || 'normal',\n children: [\n {\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n },\n ],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n })\n }\n\n // Check if the cell contains a single block with a single image child\n // If so, extract the image as a block-level image\n const firstBlock = cellBlocks[0]\n if (\n cellBlocks.length === 1 &&\n firstBlock &&\n firstBlock._type === 'block' &&\n 'children' in firstBlock &&\n Array.isArray(firstBlock.children) &&\n firstBlock.children.length === 1\n ) {\n const onlyChild = firstBlock.children[0]\n // Check if it's an image object (not a span)\n if (\n typeof onlyChild === 'object' &&\n onlyChild !== null &&\n '_type' in onlyChild &&\n onlyChild._type !== consolidatedOptions.schema.span.name &&\n onlyChild._type === 'image'\n ) {\n // Replace the block with just the image\n cellBlocks[0] = onlyChild as PortableTextBlock\n }\n }\n\n if (currentTableRow !== null) {\n currentTableRow.push({\n _type: 'cell',\n _key: consolidatedOptions.keyGenerator(),\n value: cellBlocks,\n })\n }\n break\n }\n\n // Inline container\n case 'inline': {\n // Check if we're in a table cell\n const inTableCell = currentTableRow !== null\n\n // Check if this is a standalone image (paragraph with only an image)\n if (\n token.children?.length === 1 &&\n token.children[0]?.type === 'image'\n ) {\n const imageToken = token.children[0]\n if (!imageToken) {\n break\n }\n\n const src =\n imageToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(imageToken.content || '')\n const title =\n imageToken.attrs?.find(([name]) => name === 'title')?.at(1) ||\n undefined\n\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: false,\n })\n\n if (blockImageObject) {\n if (inTableCell) {\n // In table cells, we can't push to portableText directly\n // The block image will be handled in th_close/td_close extraction logic\n // For now, add it as a child of the current block\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n } else {\n // If the current block has content, flush it before adding the block image\n // Otherwise, discard the empty block that was created by paragraph_open\n const hasContent =\n currentBlock &&\n 'children' in currentBlock &&\n (currentBlock as PortableTextTextBlock).children.length > 0\n\n if (hasContent) {\n flushBlock()\n } else {\n currentBlock = null\n currentMarkDefs = []\n }\n pushBlock(blockImageObject)\n }\n break\n }\n\n // Block image not supported, try inline image as fallback\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: true,\n })\n\n if (inlineImageObject) {\n // Ensure we have a block to add the inline image to\n if (!currentBlock) {\n if (inListItem) {\n // Structural list: start a plain text block; the image\n // lands in the current item's content via flushBlock.\n if (listContainerStack.at(-1)) {\n const style =\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ?? 'normal'\n startBlock(style)\n } else {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n } else {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n }\n }\n\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Neither block nor inline image supported, fall back to text\n addSpan(`![${alt}](${src})`)\n break\n }\n\n // Walk its children for text/marks/links\n for (const childToken of token.children ?? []) {\n switch (childToken.type) {\n case 'text':\n addSpan(childToken.content)\n break\n case 'softbreak':\n case 'hardbreak':\n addSpan('\\n')\n break\n case 'code_inline': {\n const decorator = consolidatedOptions.marks.code({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n // No code decorator defined, just add the content without marks\n addSpan(childToken.content)\n break\n }\n\n markDefRefs.push(decorator)\n addSpan(childToken.content)\n\n // code_inline is self-contained, so we need to pop the decorator\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'strong_open': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n break\n }\n case 'strong_close': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'em_open': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 'em_close': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 's_open': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 's_close': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'link_open': {\n const href = childToken.attrs\n ?.find(([name]) => name === 'href')\n ?.at(1)\n\n if (!href) {\n break\n }\n\n const title = childToken.attrs\n ?.find(([name]) => name === 'title')\n ?.at(1)\n\n const linkObject = consolidatedOptions.marks.link({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {href, title},\n })\n\n if (!linkObject) {\n break\n }\n\n currentMarkDefs.push(linkObject)\n markDefRefs.push(linkObject._key)\n break\n }\n case 'link_close': {\n // remove the last link key\n const markDefKeys = new Set(currentMarkDefs.map((d) => d._key))\n let lastLinkIndex: number | undefined\n\n for (const markDefRef of markDefRefs.reverse()) {\n if (markDefKeys.has(markDefRef)) {\n lastLinkIndex = markDefRefs.indexOf(markDefRef)\n break\n }\n }\n\n if (lastLinkIndex !== undefined) {\n const realIndex = markDefRefs.length - 1 - lastLinkIndex\n markDefRefs.splice(realIndex, 1)\n }\n break\n }\n case 'image': {\n const src =\n childToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(childToken.content || '')\n\n // Try to create an inline image first\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: true,\n })\n\n if (inlineImageObject) {\n // Inline image is supported - add it to current block\n if (!currentBlock) {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n // At this point currentBlock should exist\n if (!currentBlock) {\n throw new Error('Expected current block after startBlock')\n }\n\n // Add the image as an inline object (TypeScript assertion needed for type narrowing)\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n break\n }\n\n // Inline image not supported - try block image as fallback\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: false,\n })\n\n if (!blockImageObject) {\n // Neither inline nor block image supported\n addSpan(`![${alt}](${src})`)\n break\n }\n\n // Block image supported - flush current block and add as block-level\n // Skip if we're in a table cell (images in cells are handled differently)\n if (inTableCell) {\n // In table cells, add the image to current block (will be extracted later)\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Not in table - flush current block, add image as block, start new block\n flushBlock()\n pushBlock(blockImageObject)\n\n // Start a new block for any remaining content\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n\n break\n }\n case 'html_inline': {\n // Handle inline HTML based on configuration\n if (consolidatedOptions.html.inline === 'text') {\n addSpan(childToken.content)\n }\n // 'skip' - do nothing, ignore the HTML\n break\n }\n default:\n // Ignore other inline token types by default\n break\n }\n }\n break\n }\n\n // Callouts (GFM alerts)\n case 'alert_open': {\n flushBlock()\n calloutStartTarget = blockTarget()\n calloutStartIndex = calloutStartTarget.length\n calloutType = token.markup\n\n // Set blockquote style so content blocks inside the callout\n // get blockquote styling (used in fallback when callout type\n // is not in the schema)\n const style =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n\n case 'alert_title': {\n // Type is already captured via alert_open's markup\n break\n }\n\n case 'alert_close': {\n flushBlock()\n\n if (\n calloutStartIndex !== null &&\n calloutType !== null &&\n calloutStartTarget !== null\n ) {\n const contentBlocks = calloutStartTarget.splice(\n calloutStartIndex,\n ) as Array<PortableTextBlock>\n\n const calloutObject = consolidatedOptions.types.callout?.({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {tone: calloutType, content: contentBlocks},\n isInline: false,\n })\n\n if (calloutObject) {\n pushBlock(calloutObject)\n } else {\n for (const block of contentBlocks) {\n pushBlock(block)\n }\n }\n }\n\n calloutStartIndex = null\n calloutStartTarget = null\n calloutType = null\n currentBlockquoteStyle = null\n break\n }\n\n default:\n break\n }\n }\n\n flushBlock()\n\n return portableText\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/key-generator.ts","../src/from-portable-text/build-list-index-map.ts","../src/from-portable-text/render-node.ts","../src/from-portable-text/renderers/block-spacing.ts","../src/from-portable-text/renderers/hard-break.ts","../src/from-portable-text/renderers/list-item.ts","../src/escape.ts","../src/from-portable-text/renderers/marks.ts","../src/from-portable-text/renderers/style.ts","../src/from-portable-text/renderers/type.ts","../src/from-portable-text/portable-text-to-markdown.ts","../src/default-schema.ts","../src/to-portable-text/matchers.ts","../src/to-portable-text/markdown-to-portable-text.ts"],"sourcesContent":["export function defaultKeyGenerator() {\n return randomKey(12)\n}\n\nconst getByteHexTable = (() => {\n let table: any[]\n return () => {\n if (table) {\n return table\n }\n\n table = []\n for (let i = 0; i < 256; ++i) {\n table[i] = (i + 0x100).toString(16).slice(1)\n }\n return table\n }\n})()\n\n// WHATWG crypto RNG - https://w3c.github.io/webcrypto/Overview.html\nfunction whatwgRNG(length = 16) {\n const rnds8 = new Uint8Array(length)\n crypto.getRandomValues(rnds8)\n return rnds8\n}\n\nfunction randomKey(length?: number): string {\n const table = getByteHexTable()\n return whatwgRNG(length)\n .reduce((str, n) => str + table[n], '')\n .slice(0, length)\n}\n","import {\n compileSchema,\n defineSchema,\n isTextBlock,\n type PortableTextBlock,\n} from '@portabletext/schema'\nimport type {ArbitraryTypedObject, TypedObject} from '@portabletext/types'\nimport {defaultKeyGenerator} from '../key-generator'\n\nconst schema = compileSchema(defineSchema({}))\n\n/**\n * Builds a map of list item `_key`s to their index, and a map of list item\n * `_key`s to the depth they should be rendered at.\n *\n * The depth is not the same as the block's `level`. A list can start at a level\n * deeper than 1, and can skip levels, but Markdown has no way to express either:\n * indentation is relative to the list item above, and indenting a first item by\n * four spaces or more makes it a code block rather than a list. So each jump to a\n * deeper level counts as a single step of nesting, however many levels it spans.\n *\n * Mutates the blocks in place by adding a `_key` if necessary.\n */\nexport function buildListIndexMap<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(\n blocks: Array<Block>,\n): {listIndexMap: Map<string, number>; listDepthMap: Map<string, number>} {\n const levelIndexMaps = new Map<string, Map<number, number>>()\n const listIndexMap = new Map<string, number>()\n const listDepthMap = new Map<string, number>()\n\n // Levels of the list items this one is nested inside, shallowest first\n let levelStack: Array<number> = []\n\n function depthOf(level: number): number {\n let deepest = levelStack.at(-1)\n\n while (deepest !== undefined && deepest > level) {\n levelStack.pop()\n deepest = levelStack.at(-1)\n }\n\n if (deepest !== level) {\n levelStack.push(level)\n }\n\n return levelStack.length - 1\n }\n\n let previousListItem:\n | {\n listItem: string\n depth: number\n }\n | undefined\n\n for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) {\n const block = blocks.at(blockIndex)\n\n if (block === undefined) {\n continue\n }\n\n if (!block._key) {\n block._key = defaultKeyGenerator()\n }\n\n // Clear the state if we encounter a non-text block\n if (!isTextBlock({schema}, block)) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n // Clear the state if we encounter a non-list text block\n if (block.listItem === undefined || block.level === undefined) {\n levelIndexMaps.clear()\n previousListItem = undefined\n levelStack = []\n\n continue\n }\n\n const depth = depthOf(block.level)\n listDepthMap.set(block._key, depth)\n\n // If we encounter a new list item, we set the initial index to 1 for the\n // list type on that level.\n if (!previousListItem) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // If the previous list item is of the same type but on a lower level, we\n // need to reset the level index map for that type.\n if (\n previousListItem.listItem === block.listItem &&\n previousListItem.depth < depth\n ) {\n const listIndex = 1\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n levelIndexMap.set(depth, listIndex)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, listIndex)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n\n continue\n }\n\n // Reset other list types at current depth and deeper\n levelIndexMaps.forEach((levelIndexMap, listItem) => {\n if (listItem === block.listItem) {\n return\n }\n\n // Reset all levels that are >= current level\n const depthsToDelete: number[] = []\n\n levelIndexMap.forEach((_, existingDepth) => {\n if (existingDepth >= depth) {\n depthsToDelete.push(existingDepth)\n }\n })\n\n depthsToDelete.forEach((depthToDelete) => {\n levelIndexMap.delete(depthToDelete)\n })\n })\n\n const levelIndexMap =\n levelIndexMaps.get(block.listItem) ?? new Map<number, number>()\n const levelCounter = levelIndexMap.get(depth) ?? 0\n levelIndexMap.set(depth, levelCounter + 1)\n levelIndexMaps.set(block.listItem, levelIndexMap)\n\n listIndexMap.set(block._key, levelCounter + 1)\n\n previousListItem = {\n listItem: block.listItem,\n depth,\n }\n }\n\n return {listIndexMap, listDepthMap}\n}\n","import {\n buildMarksTree,\n isPortableTextBlock,\n isPortableTextListItemBlock,\n isPortableTextToolkitSpan,\n isPortableTextToolkitTextNode,\n spanToPlainText,\n type ToolkitNestedPortableTextSpan,\n type ToolkitTextNode,\n} from '@portabletext/toolkit'\nimport type {\n PortableTextBlock,\n PortableTextListItemBlock,\n PortableTextMarkDefinition,\n PortableTextSpan,\n TypedObject,\n} from '@portabletext/types'\nimport {defaultKeyGenerator} from '../key-generator'\nimport type {PortableTextRenderers, RenderNode, Serializable} from './types'\n\ninterface SerializedBlock {\n _key: string\n children: string\n index: number\n isInline: boolean\n node: PortableTextBlock | PortableTextListItemBlock\n}\n\nexport const createRenderNode = (\n renderers: PortableTextRenderers,\n listIndexMap: Map<string, number>,\n listDepthMap: Map<string, number>,\n): RenderNode => {\n function renderNode<N extends TypedObject>(options: Serializable<N>): string {\n const {node, index, isInline} = options\n\n if (isPortableTextListItemBlock(node)) {\n return renderListItem(node, index)\n }\n\n if (isPortableTextToolkitSpan(node)) {\n return renderSpan(node)\n }\n\n if (isPortableTextBlock(node)) {\n return renderBlock(node, index, isInline)\n }\n\n if (isPortableTextToolkitTextNode(node)) {\n return renderText(node)\n }\n\n return renderCustomBlock(node, index, isInline)\n }\n\n function renderListItem(\n node: PortableTextListItemBlock<\n PortableTextMarkDefinition,\n PortableTextSpan\n >,\n index: number,\n ): string {\n const renderer = renderers.listItem\n const handler =\n typeof renderer === 'function' ? renderer : renderer[node.listItem]\n const itemHandler = handler || renderers.unknownListItem\n\n // Build the text content from the block\n const tree = buildMarksTree(node)\n const textContent = tree\n .map((child, i) => {\n return renderNode({node: child, isInline: true, index: i, renderNode})\n })\n .join('')\n\n let children = textContent\n\n if (node.style && node.style !== 'normal') {\n // Wrap any other style in whatever the block component says to use\n const {listItem: _listItem, ...blockNode} = node\n children = renderNode({\n node: blockNode,\n index,\n isInline: false,\n renderNode,\n })\n // Strip trailing newlines from block styles - list item component handles spacing\n children = children.replace(/\\n+$/, '')\n }\n\n return itemHandler({\n value: node,\n index,\n listIndex: node._key ? listIndexMap.get(node._key) : undefined,\n listDepth: node._key ? listDepthMap.get(node._key) : undefined,\n isInline: false,\n renderNode,\n children,\n })\n }\n\n function renderSpan(node: ToolkitNestedPortableTextSpan): string {\n const {markDef, markType, markKey} = node\n const span = renderers.marks[markType] || renderers.unknownMark\n const children = node.children.map((child, childIndex) =>\n renderNode({node: child, index: childIndex, isInline: true, renderNode}),\n )\n\n return span({\n text: spanToPlainText(node),\n value: markDef,\n markType,\n markKey,\n renderNode,\n children: children.join(''),\n })\n }\n\n function renderBlock(\n node: PortableTextBlock,\n index: number,\n isInline: boolean,\n ): string {\n const {_key, ...props} = serializeBlock({node, index, isInline, renderNode})\n const style = props.node.style || 'normal'\n const handler =\n typeof renderers.block === 'function'\n ? renderers.block\n : renderers.block[style]\n const block = handler || renderers.unknownBlockStyle\n\n return block({...props, value: props.node, renderNode})\n }\n\n function renderText(node: ToolkitTextNode): string {\n if (node.text === '\\n') {\n return renderers.hardBreak()\n }\n\n return node.text\n }\n\n function renderCustomBlock(\n value: TypedObject,\n index: number,\n isInline: boolean,\n ): string {\n const component = renderers.types[value._type] ?? renderers.unknownType\n\n return component({\n value,\n isInline,\n index,\n renderNode,\n })\n }\n\n return renderNode\n}\n\nfunction serializeBlock(\n options: Serializable<PortableTextBlock>,\n): SerializedBlock {\n const {node, index, isInline, renderNode} = options\n const tree = buildMarksTree(node)\n\n const renderedChildren = tree.map((child, i) =>\n renderNode({node: child, isInline: true, index: i, renderNode}),\n )\n\n return {\n _key: node._key || defaultKeyGenerator(),\n children: renderedChildren.join(''),\n index,\n isInline,\n node,\n }\n}\n","import {\n isPortableTextBlock,\n isPortableTextListItemBlock,\n} from '@portabletext/toolkit'\nimport type {TypedObject} from '@portabletext/types'\n\n/**\n * @public\n */\nexport type BlockSpacingRenderer = (options: {\n current: TypedObject\n next: TypedObject\n}) => string | undefined\n\n/**\n * @public\n */\nexport const DefaultBlockSpacingRenderer: BlockSpacingRenderer = ({\n current,\n next,\n}) => {\n if (\n isPortableTextListItemBlock(current) &&\n isPortableTextListItemBlock(next)\n ) {\n return '\\n'\n }\n\n if (\n isPortableTextBlock(current) &&\n isPortableTextBlock(next) &&\n current.style === 'blockquote' &&\n next.style === 'blockquote'\n ) {\n return '\\n>\\n'\n }\n\n return '\\n\\n'\n}\n","/**\n * @public\n */\nexport const DefaultHardBreakRenderer = (): string => ' \\n'\n","import type {PortableTextListItemRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultListItemRenderer: PortableTextListItemRenderer = ({\n children,\n value,\n listIndex,\n listDepth,\n}) => {\n const listStyle = value.listItem || 'bullet'\n const depth = listDepth ?? (value.level || 1) - 1\n const indent = ' '.repeat(depth)\n\n if (listStyle === 'number') {\n return `${indent}${listIndex ?? 1}. ${children}`\n }\n\n if (listStyle === 'task') {\n const checked =\n 'checked' in value && typeof value.checked === 'boolean'\n ? value.checked\n : false\n const marker = checked ? '[x]' : '[ ]'\n return `${indent}- ${marker} ${children}`\n }\n\n return `${indent}- ${children}`\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownListItemRenderer: PortableTextListItemRenderer = ({\n children,\n}) => {\n return `- ${children}\\n`\n}\n","/**\n * Escapes special characters in image alt texts and link texts.\n */\nexport function escapeImageAndLinkText(text: string): string {\n return text.replace(/([[\\]\\\\])/g, '\\\\$1')\n}\n\n/**\n * Unescapes special characters in image alt texts and link texts.\n */\nexport function unescapeImageAndLinkText(text: string): string {\n return text.replace(/\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g, '$1')\n}\n\n/**\n * Escapes special characters in image/link titles (the part inside quotes).\n */\nexport function escapeImageAndLinkTitle(text: string): string {\n return text.replace(/([\\\\\"])/g, '\\\\$1')\n}\n\n/**\n * Escapes characters that have special meaning at the row level of a GFM\n * table cell.\n *\n * A literal `|` ends the cell, so unescaped pipes are replaced with `\\|`.\n * Newlines end the row, so they are replaced with `<br>` to keep the\n * visible line break inside the cell. Already-escaped pipes (`\\|`) are\n * left intact so that escapes introduced by mark renderers survive the\n * pass.\n *\n * Backslashes are intentionally not escaped here so that other escapes\n * already in the rendered cell (such as `\\[` and `\\]` in link text) are\n * not double-escaped.\n */\nexport function escapeTableCell(text: string): string {\n return text.replace(/(?<!\\\\)\\|/g, '\\\\|').replace(/\\n/g, '<br>')\n}\n","import type {TypedObject} from '@portabletext/types'\nimport {escapeImageAndLinkText, escapeImageAndLinkTitle} from '../../escape'\nimport type {PortableTextMarkRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultEmRenderer: PortableTextMarkRenderer = ({children}) =>\n `_${children}_`\n\n/**\n * @public\n */\nexport const DefaultStrongRenderer: PortableTextMarkRenderer = ({children}) =>\n `**${children}**`\n\n/**\n * @public\n */\nexport const DefaultCodeRenderer: PortableTextMarkRenderer = ({children}) =>\n `\\`${children}\\``\n\n/**\n * @public\n */\nexport const DefaultUnderlineRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `<u>${children}</u>`\n\n/**\n * @public\n */\nexport const DefaultStrikeThroughRenderer: PortableTextMarkRenderer = ({\n children,\n}) => `~~${children}~~`\n\ninterface DefaultLink extends TypedObject {\n _type: 'link'\n href: string\n title: string | undefined\n}\n\n/**\n * @public\n */\nexport const DefaultLinkRenderer: PortableTextMarkRenderer<DefaultLink> = ({\n children,\n value,\n}) => {\n const href = value?.href || ''\n const title = value?.title || ''\n const looksSafe = uriLooksSafe(href)\n\n if (looksSafe) {\n // Check if the URL looks like an HTML injection attempt\n // If it has quotes AND angle brackets, or other suspicious patterns, encode more aggressively\n const looksLikeInjection = /[\"'][^\"']*[<>]|[<>][^<>]*[\"']/.test(href)\n\n if (looksLikeInjection) {\n // Encode all special characters that could be used for injection\n const encodedHref = href.replace(/[\"<>() ]/g, (char) => {\n return `%${char.charCodeAt(0).toString(16).toUpperCase()}`\n })\n return `[${escapeImageAndLinkText(children)}](${encodedHref})`\n }\n\n // For normal URLs, don't encode parentheses - Markdown handles balanced parens fine\n return `[${escapeImageAndLinkText(children)}](${href}${title ? ` \"${escapeImageAndLinkTitle(title)}\"` : ''})`\n }\n\n // Return children without link when URL is unsafe\n return children\n}\n\nfunction uriLooksSafe(uri: string): boolean {\n const url = (uri || '').trim()\n const first = url.charAt(0)\n\n if (first === '#' || first === '/') {\n return true\n }\n\n const colonIndex = url.indexOf(':')\n if (colonIndex === -1) {\n return true\n }\n\n const allowedProtocols = ['http', 'https', 'mailto', 'tel']\n const proto = url.slice(0, colonIndex).toLowerCase()\n if (allowedProtocols.indexOf(proto) !== -1) {\n return true\n }\n\n const queryIndex = url.indexOf('?')\n if (queryIndex !== -1 && colonIndex > queryIndex) {\n return true\n }\n\n const hashIndex = url.indexOf('#')\n if (hashIndex !== -1 && colonIndex > hashIndex) {\n return true\n }\n\n return false\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownMarkRenderer: PortableTextMarkRenderer = ({\n children,\n}) => {\n return children\n}\n","import type {PortableTextBlock} from '@portabletext/types'\nimport type {PortableTextRenderer} from '../types'\n\ntype PortableTextBlockRenderer = PortableTextRenderer<PortableTextBlock>\n\n/**\n * @public\n */\nexport const DefaultNormalRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Empty blocks should not add extra spacing\n if (!children || children.trim() === '') {\n return ''\n }\n\n return children\n}\n\n/**\n * @public\n */\nexport const DefaultBlockquoteRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n // Prefix each line with \"> \" for proper blockquote formatting\n // This handles multi-line content and preserves empty lines\n if (!children) {\n return '>'\n }\n\n return children\n .split('\\n')\n .map((line) => `> ${line}`)\n .join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultH1Renderer: PortableTextBlockRenderer = ({children}) =>\n `# ${children}`\n\n/**\n * @public\n */\nexport const DefaultH2Renderer: PortableTextBlockRenderer = ({children}) =>\n `## ${children}`\n\n/**\n * @public\n */\nexport const DefaultH3Renderer: PortableTextBlockRenderer = ({children}) =>\n `### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH4Renderer: PortableTextBlockRenderer = ({children}) =>\n `#### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH5Renderer: PortableTextBlockRenderer = ({children}) =>\n `##### ${children}`\n\n/**\n * @public\n */\nexport const DefaultH6Renderer: PortableTextBlockRenderer = ({children}) =>\n `###### ${children}`\n\n/**\n * @public\n */\nexport const DefaultUnknownStyleRenderer: PortableTextBlockRenderer = ({\n children,\n}) => {\n return children ?? ''\n}\n","import {isTypedObject} from '@portabletext/schema'\nimport type {PortableTextBlock, TypedObject} from '@portabletext/types'\nimport {\n escapeImageAndLinkText,\n escapeImageAndLinkTitle,\n escapeTableCell,\n} from '../../escape'\nimport type {PortableTextTypeRenderer} from '../types'\n\n/**\n * @public\n */\nexport const DefaultCodeBlockRenderer: PortableTextTypeRenderer<{\n _type: 'code'\n code: string\n language: string | undefined\n}> = (options) => {\n if (!isCodeShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n return `\\`\\`\\`${normalizeLanguage(options.value.language)}\\n${options.value.code}\\n\\`\\`\\``\n}\n\nfunction isCodeShaped(value: unknown): value is {code: string} {\n return typeof (value as {code?: unknown} | null)?.code === 'string'\n}\n\n/**\n * A fence info string is everything after the opening fence on the same\n * line, so a real `language` can never contain a newline, and the parser\n * only ever produces a string. Junk in this optional field should not send\n * an otherwise valid code block to the fenced-JSON path, so it is treated\n * as absent instead of guarded.\n */\nfunction normalizeLanguage(language: unknown): string {\n if (typeof language !== 'string' || language.includes('\\n')) {\n return ''\n }\n return language\n}\n\n/**\n * @public\n */\nexport const DefaultHorizontalRuleRenderer: PortableTextTypeRenderer = () => {\n return '---'\n}\n\n/**\n * @public\n */\nexport const DefaultHtmlRenderer: PortableTextTypeRenderer<{\n _type: 'html'\n html: string\n}> = (options) => {\n if (!isHtmlShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n return options.value.html\n}\n\nfunction isHtmlShaped(value: unknown): value is {html: string} {\n return typeof (value as {html?: unknown} | null)?.html === 'string'\n}\n\n/**\n * @public\n */\nexport const DefaultImageRenderer: PortableTextTypeRenderer<{\n _type: 'image'\n src: string\n alt: string | undefined\n title: string | undefined\n}> = (options) => {\n if (!isImageShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n const alt = escapeImageAndLinkText(options.value.alt ?? '')\n const title = options.value.title\n ? ` \"${escapeImageAndLinkTitle(options.value.title)}\"`\n : ''\n return `![${alt}](${options.value.src}${title})`\n}\n\nfunction isImageShaped(value: unknown): value is {\n src: string\n alt: string | null | undefined\n title: string | null | undefined\n} {\n const image = value as {src?: unknown; alt?: unknown; title?: unknown} | null\n return (\n typeof image?.src === 'string' &&\n // CMS payloads commonly store cleared optional strings as `null`; the\n // render body treats `null` like absent, so the guard must too\n (image.alt == null || typeof image.alt === 'string') &&\n (image.title == null || typeof image.title === 'string')\n )\n}\n\n/**\n * A table is table-shaped when everything the renderer dereferences is\n * there: `rows` an array of typed objects with a `cells` array, every cell\n * a typed object whose `value` array holds typed objects (`renderNode`'s\n * input contract). The predicate narrows to exactly what `renderTable`\n * consumes, so the renderer needs no casts. A malformed `table` value\n * (e.g. a consumer's differently-shaped `table` type) falls back to the\n * fenced-JSON path instead of throwing.\n */\nfunction isTableShaped(value: unknown): value is TableShaped {\n const rows = (value as {rows?: unknown} | null)?.rows\n return (\n Array.isArray(rows) &&\n rows.every(\n (row) =>\n isTypedObject(row) &&\n Array.isArray(row['cells']) &&\n row['cells'].every(\n (cell) =>\n isTypedObject(cell) &&\n Array.isArray(cell['value']) &&\n cell['value'].every(isTypedObject),\n ),\n )\n )\n}\n\ntype TableShaped = {\n headerRows?: unknown\n alignment?: unknown\n rows: Array<{cells: Array<{value: Array<TypedObject>}>}>\n}\n\n/**\n * Renders a Portable Text table block-object back to Markdown.\n *\n * The PT `headerRows` field decides the header. Missing `headerRows` and\n * `headerRows === 0` both render headerless: GFM has no headerless form, so\n * an empty header row is emitted and every row goes in the body (that empty\n * header reads back as `headerRows: 0` via `markdownToPortableText`).\n * `headerRows >= 1` promotes `rows[0]` to the header. GFM allows exactly one\n * header row, so header rows beyond the first flatten into the body, lossy,\n * but the extra rows stay on the Portable Text side.\n *\n * Asymmetric tables (rows of varying cell counts) are widened to match\n * the row with the most cells. Narrower rows are padded with empty cells\n * so a GFM parser doesn't silently drop the extra cells in wider rows.\n *\n * @public\n */\nexport const DefaultTableRenderer: PortableTextTypeRenderer<{\n _type: 'table'\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n cells: Array<{\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n}> = (options) => {\n const {value, renderNode} = options\n\n if (!isTableShaped(value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n\n return renderTable(value, renderNode)\n}\n\nfunction renderTable(\n value: TableShaped,\n renderNode: Parameters<PortableTextTypeRenderer>[0]['renderNode'],\n): string {\n const rows = value.rows\n // `alignment` is an extension field, not part of the table shape: junk\n // here should not send an otherwise valid table to the fenced-JSON path,\n // so it is normalized away instead of guarded (`{}.at` would throw below).\n const alignment: ReadonlyArray<unknown> | undefined = Array.isArray(\n value.alignment,\n )\n ? value.alignment\n : undefined\n\n const headerRow = rows.at(0)\n\n if (!headerRow) {\n return ''\n }\n\n // Helper to extract text from cell blocks\n const getCellText = (cellBlocks: Array<TypedObject>): string => {\n return cellBlocks\n .map((block, index) =>\n renderNode({\n node: block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join(' ')\n .trim()\n }\n\n const lines: string[] = []\n\n // GFM requires every row to have the same number of cells as the header row\n // and the delimiter row. Parsers silently drop excess cells from body rows\n // that are wider than the header, so we widen the table to the widest row\n // and pad narrower rows with empty cells to keep all data visible.\n const columnCount = rows.reduce(\n (max, row) => Math.max(max, row.cells.length),\n 0,\n )\n\n const renderCells = (texts: Array<string>): string => {\n const padded = [...texts]\n while (padded.length < columnCount) {\n padded.push('')\n }\n return `| ${padded.join(' | ')} |`\n }\n\n const renderRow = (cells: typeof headerRow.cells): string =>\n renderCells(cells.map((cell) => escapeTableCell(getCellText(cell.value))))\n\n // Delimiter row, sized to the column count. Each cell's colons encode the\n // column's alignment as defined by `value.alignment[columnIndex]`.\n const separators = Array.from({length: columnCount}, (_, index) => {\n const align = alignment?.at(index)\n if (align === 'left') {\n return ' :--- '\n }\n if (align === 'center') {\n return ' :---: '\n }\n if (align === 'right') {\n return ' ---: '\n }\n return ' --- '\n })\n const delimiter = `|${separators.join('|')}|`\n\n const hasHeader = (Number(value.headerRows) || 0) >= 1\n\n if (!hasHeader) {\n // Headerless table: emit an empty header row and keep every row in the\n // body.\n lines.push(renderCells([]))\n lines.push(delimiter)\n for (const row of rows) {\n lines.push(renderRow(row.cells))\n }\n } else {\n // `rows[0]` is the header. Header rows beyond the first flatten into the\n // body (GFM has a single header row).\n lines.push(renderRow(headerRow.cells))\n lines.push(delimiter)\n for (let i = 1; i < rows.length; i++) {\n const row = rows.at(i)\n if (row) {\n lines.push(renderRow(row.cells))\n }\n }\n }\n\n return lines.join('\\n')\n}\n\n/**\n * @public\n */\nexport const DefaultCalloutRenderer: PortableTextTypeRenderer<{\n _type: 'callout'\n tone: string\n content: Array<PortableTextBlock>\n}> = (options) => {\n if (!isCalloutShaped(options.value)) {\n return DefaultUnknownTypeRenderer(options)\n }\n const {renderNode} = options\n const renderedContent = options.value.content\n .map((block, index) =>\n renderNode({\n node: block._type === 'block' ? {...block, style: 'normal'} : block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n const prefixed = renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n\n return `> [!${options.value.tone.toUpperCase()}]\\n${prefixed}`\n}\n\nfunction isCalloutShaped(\n value: unknown,\n): value is {tone: string; content: Array<TypedObject>} {\n const callout = value as {tone?: unknown; content?: unknown} | null\n return (\n typeof callout?.tone === 'string' &&\n Array.isArray(callout.content) &&\n callout.content.every(isTypedObject)\n )\n}\n\n/**\n * Renders a structural blockquote block-object (the `types.blockquote` shape\n * produced by `markdownToPortableText` when a `types.blockquote` matcher is\n * provided) back to Markdown. Each content block is rendered via the\n * recursive renderer pipeline, joined with blank lines, and every line is\n * prefixed with `> ` to form a Markdown blockquote.\n *\n * Distinct from `DefaultBlockquoteRenderer`, which renders flat-path text\n * blocks with `style: 'blockquote'`.\n *\n * @public\n */\nexport const DefaultBlockquoteObjectRenderer: PortableTextTypeRenderer<{\n _type: 'blockquote'\n content: Array<PortableTextBlock>\n}> = ({value, renderNode}) => {\n const renderedContent = value.content\n .map((block, index) =>\n renderNode({\n node: block._type === 'block' ? {...block, style: 'normal'} : block,\n index,\n isInline: false,\n renderNode,\n }),\n )\n .join('\\n\\n')\n\n return renderedContent\n .split('\\n')\n .map((line) => (line === '' ? '>' : `> ${line}`))\n .join('\\n')\n}\n\n/**\n * Renders a structural list block-object (the `types.list` shape produced by\n * `markdownToPortableText` when a `types.list` matcher is provided) back to\n * Markdown. Items render as `- ` for `kind: 'bullet'`, `1. `/`2. ` for `'number'`,\n * and `- [x] ` / `- [ ] ` for `'task'`. Items can hold any blocks - text blocks,\n * code blocks, callouts, images, and nested lists - and content other than the\n * leading text block is indented to keep it inside the item.\n *\n * @public\n */\nexport const DefaultListRenderer: PortableTextTypeRenderer<{\n _type: 'list'\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | TypedObject>\n }>\n}> = ({value, renderNode}) => {\n // A list is \"loose\" when any item carries multiple non-list-block\n // content entries (a continuation paragraph, a code block, etc).\n // CommonMark uses blank lines between items in loose lists; tight lists\n // pack items together with single newlines. A nested list as a second\n // child of an item does NOT make the list loose, so we ignore those when\n // counting.\n const isLoose = value.items.some((item) => {\n const nonNestedBlocks = item.content.filter(\n (block) => (block as TypedObject)._type !== 'list',\n )\n return nonNestedBlocks.length > 1\n })\n const itemSeparator = isLoose ? '\\n\\n' : '\\n'\n\n const lines = value.items.map((item, itemIndex) => {\n const marker = getListMarker(value.kind, itemIndex, item.checked)\n // Continuation indent matches the marker's width so that subsequent\n // blocks attach to this item under CommonMark's lazy-continuation rule.\n // Bullet `- ` indents to 2; ordered `1. ` indents to 3, `10. ` to 4.\n // Task `- [x] ` is conceptually `- ` + a `[x] ` content prefix at the\n // markdown-it level, so its continuation indent stays at 2.\n const indentWidth = value.kind === 'task' ? 2 : marker.length\n const indent = ' '.repeat(indentWidth)\n\n const renderedBlocks = item.content.map((block, blockIndex) => ({\n isNestedList: (block as TypedObject)._type === 'list',\n text: renderNode({\n node: block as TypedObject,\n index: blockIndex,\n isInline: false,\n renderNode,\n }),\n }))\n\n const [first, ...rest] = renderedBlocks\n // Trim trailing whitespace from empty items so `- ` becomes `-`.\n const head = `${marker}${first?.text ?? ''}`.trimEnd()\n if (rest.length === 0) {\n return head\n }\n\n const tail = rest\n .map((rendered) => {\n const indented = rendered.text\n .split('\\n')\n .map((line) => (line === '' ? '' : `${indent}${line}`))\n .join('\\n')\n // Nested lists hug the previous block (tight list); other content\n // gets a blank line separator (paragraph break).\n return rendered.isNestedList ? `\\n${indented}` : `\\n\\n${indented}`\n })\n .join('')\n\n return `${head}${tail}`\n })\n\n return lines.join(itemSeparator)\n}\n\nfunction getListMarker(\n kind: 'bullet' | 'number' | 'task',\n itemIndex: number,\n checked: boolean | undefined,\n): string {\n if (kind === 'number') {\n return `${itemIndex + 1}. `\n }\n if (kind === 'task') {\n return checked ? '- [x] ' : '- [ ] '\n }\n return '- '\n}\n\n/**\n * @public\n */\nexport const DefaultUnknownTypeRenderer: PortableTextTypeRenderer = ({\n value,\n isInline,\n}) => {\n const json = `\\`\\`\\`json\\n${JSON.stringify(value, null, 2)}\\n\\`\\`\\``\n // For inline unknown types, add newlines to break them out of the text flow\n return isInline ? `\\n${json}\\n` : json\n}\n","import type {\n ArbitraryTypedObject,\n PortableTextBlock,\n TypedObject,\n} from '@portabletext/types'\nimport {buildListIndexMap} from './build-list-index-map'\nimport {createRenderNode} from './render-node'\nimport {\n DefaultBlockSpacingRenderer,\n type BlockSpacingRenderer,\n} from './renderers/block-spacing'\nimport {DefaultHardBreakRenderer} from './renderers/hard-break'\nimport {\n DefaultListItemRenderer,\n DefaultUnknownListItemRenderer,\n} from './renderers/list-item'\nimport {\n DefaultCodeRenderer,\n DefaultEmRenderer,\n DefaultLinkRenderer,\n DefaultStrikeThroughRenderer,\n DefaultStrongRenderer,\n DefaultUnderlineRenderer,\n DefaultUnknownMarkRenderer,\n} from './renderers/marks'\nimport {\n DefaultBlockquoteRenderer,\n DefaultH1Renderer,\n DefaultH2Renderer,\n DefaultH3Renderer,\n DefaultH4Renderer,\n DefaultH5Renderer,\n DefaultH6Renderer,\n DefaultNormalRenderer,\n DefaultUnknownStyleRenderer,\n} from './renderers/style'\nimport {\n DefaultCalloutRenderer,\n DefaultCodeBlockRenderer,\n DefaultHorizontalRuleRenderer,\n DefaultHtmlRenderer,\n DefaultImageRenderer,\n DefaultTableRenderer,\n DefaultUnknownTypeRenderer,\n} from './renderers/type'\nimport type {PortableTextRenderers} from './types'\n\nconst defaultRenderers: PortableTextRenderers = {\n types: {\n 'callout': DefaultCalloutRenderer,\n 'code': DefaultCodeBlockRenderer,\n 'horizontal-rule': DefaultHorizontalRuleRenderer,\n 'html': DefaultHtmlRenderer,\n 'image': DefaultImageRenderer,\n 'table': DefaultTableRenderer,\n },\n\n block: {\n normal: DefaultNormalRenderer,\n blockquote: DefaultBlockquoteRenderer,\n h1: DefaultH1Renderer,\n h2: DefaultH2Renderer,\n h3: DefaultH3Renderer,\n h4: DefaultH4Renderer,\n h5: DefaultH5Renderer,\n h6: DefaultH6Renderer,\n },\n marks: {\n 'em': DefaultEmRenderer,\n 'strong': DefaultStrongRenderer,\n 'code': DefaultCodeRenderer,\n 'underline': DefaultUnderlineRenderer,\n 'strike-through': DefaultStrikeThroughRenderer,\n 'link': DefaultLinkRenderer,\n },\n listItem: DefaultListItemRenderer,\n hardBreak: DefaultHardBreakRenderer,\n\n unknownType: DefaultUnknownTypeRenderer,\n unknownMark: DefaultUnknownMarkRenderer,\n unknownListItem: DefaultUnknownListItemRenderer,\n unknownBlockStyle: DefaultUnknownStyleRenderer,\n}\n\ntype Options = Partial<PortableTextRenderers> & {\n blockSpacing?: BlockSpacingRenderer\n}\n\n/**\n * @public\n */\nexport function portableTextToMarkdown<\n Block extends TypedObject = PortableTextBlock | ArbitraryTypedObject,\n>(blocks: Array<Block>, options: Options = {}): string {\n const renderers = {\n block: {\n ...defaultRenderers.block,\n ...options.block,\n },\n listItem: options.listItem ?? defaultRenderers.listItem,\n marks: {\n ...defaultRenderers.marks,\n ...options.marks,\n },\n types: {\n ...defaultRenderers.types,\n ...options.types,\n },\n hardBreak: options.hardBreak ?? defaultRenderers.hardBreak,\n unknownType: options.unknownType ?? defaultRenderers.unknownType,\n unknownBlockStyle:\n options.unknownBlockStyle ?? defaultRenderers.unknownBlockStyle,\n unknownListItem:\n options.unknownListItem ?? defaultRenderers.unknownListItem,\n unknownMark: options.unknownMark ?? defaultRenderers.unknownMark,\n }\n const renderBlockSpacing = options.blockSpacing ?? DefaultBlockSpacingRenderer\n\n const {listIndexMap, listDepthMap} = buildListIndexMap(blocks)\n const renderNode = createRenderNode(renderers, listIndexMap, listDepthMap)\n\n return blocks\n .map((node, index) => {\n const renderedNode = renderNode({\n node,\n index,\n isInline: false,\n renderNode,\n })\n\n if (index === blocks.length - 1) {\n return renderedNode\n }\n\n const nextNode = blocks.at(index + 1)\n\n if (!nextNode) {\n return renderedNode\n }\n\n const blockSpacing =\n renderBlockSpacing({\n current: node,\n next: nextNode,\n }) ?? '\\n\\n'\n\n return `${renderedNode}${blockSpacing}`\n })\n .join('')\n}\n","import {\n compileSchema,\n defineSchema,\n type AnnotationDefinition,\n type BlockObjectDefinition,\n type DecoratorDefinition,\n type ListDefinition,\n type StyleDefinition,\n} from '@portabletext/schema'\n\n/********************\n * Default style definitions\n ********************/\n\nexport const normalStyleDefinition = {\n name: 'normal',\n} as const satisfies StyleDefinition\n\nexport const h1StyleDefinition = {\n name: 'h1',\n} as const satisfies StyleDefinition\n\nexport const h2StyleDefinition = {\n name: 'h2',\n} as const satisfies StyleDefinition\n\nexport const h3StyleDefinition = {\n name: 'h3',\n} as const satisfies StyleDefinition\n\nexport const h4StyleDefinition = {\n name: 'h4',\n} as const satisfies StyleDefinition\n\nexport const h5StyleDefinition = {\n name: 'h5',\n} as const satisfies StyleDefinition\n\nexport const h6StyleDefinition = {\n name: 'h6',\n} as const satisfies StyleDefinition\n\nexport const blockquoteStyleDefinition = {\n name: 'blockquote',\n} as const satisfies StyleDefinition\n\n/********************\n * Default list definitions\n ********************/\n\nexport const defaultOrderedListItemDefinition = {\n name: 'number',\n} as const satisfies ListDefinition\n\nexport const defaultUnorderedListItemDefinition = {\n name: 'bullet',\n} as const satisfies ListDefinition\n\nexport const defaultTaskListItemDefinition = {\n name: 'task',\n} as const satisfies ListDefinition\n\n/********************\n * Default decorator definitions\n ********************/\n\nexport const defaultStrongDecoratorDefinition = {\n name: 'strong',\n} as const satisfies DecoratorDefinition\n\nexport const defaultEmDecoratorDefinition = {\n name: 'em',\n} as const satisfies DecoratorDefinition\n\nexport const defaultCodeDecoratorDefinition = {\n name: 'code',\n} as const satisfies DecoratorDefinition\n\nexport const defaultStrikeThroughDecoratorDefinition = {\n name: 'strike-through',\n} as const satisfies DecoratorDefinition\n\n/********************\n * Default annotation definitions\n ********************/\n\nexport const defaultLinkObjectDefinition = {\n name: 'link',\n fields: [\n {name: 'href', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies AnnotationDefinition\n\n/********************\n * Default object definitions\n ********************/\n\nexport const defaultCodeObjectDefinition = {\n name: 'code',\n fields: [\n {name: 'language', type: 'string'},\n {name: 'code', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultImageObjectDefinition = {\n name: 'image',\n fields: [\n {name: 'src', type: 'string'},\n {name: 'alt', type: 'string'},\n {name: 'title', type: 'string'},\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHorizontalRuleObjectDefinition = {\n name: 'horizontal-rule',\n} as const satisfies BlockObjectDefinition\n\nexport const defaultHtmlObjectDefinition = {\n name: 'html',\n fields: [{name: 'html', type: 'string'}],\n} as const satisfies BlockObjectDefinition\n\n/**\n * Mirrors the canonical shape `@portabletext/plugin-table` expects: `table`\n * (`headerRows`, `rows`), `row` (`cells`), `cell` (`value`, text blocks or\n * standalone `image` objects). `alignment` is a `@portabletext/markdown`\n * extension field; `@portabletext/plugin-table` ignores it. Keep this in\n * sync with `packages/plugin-table/src/table-config.ts`'s\n * `defaultTableConfig`.\n */\nexport const defaultTableObjectDefinition = {\n name: 'table',\n fields: [\n {name: 'headerRows', type: 'number'},\n {name: 'alignment', type: 'array'},\n {\n name: 'rows',\n type: 'array',\n of: [\n {\n type: 'object',\n name: 'row',\n fields: [\n {\n name: 'cells',\n type: 'array',\n of: [\n {\n type: 'object',\n name: 'cell',\n fields: [\n {\n name: 'value',\n type: 'array',\n of: [{type: 'block'}, {type: 'image'}],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n} as const satisfies BlockObjectDefinition\n\nexport const defaultCalloutObjectDefinition = {\n name: 'callout',\n fields: [\n {name: 'tone', type: 'string'},\n {name: 'content', type: 'array'},\n ],\n} as const satisfies BlockObjectDefinition\n\n/**\n * The default schema for converting markdown to Portable Text.\n *\n * @public\n */\nexport const defaultSchema = compileSchema(\n defineSchema({\n block: {\n fields: [{name: 'checked', type: 'boolean'}],\n },\n styles: [\n normalStyleDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n blockquoteStyleDefinition,\n ],\n lists: [\n defaultOrderedListItemDefinition,\n defaultUnorderedListItemDefinition,\n defaultTaskListItemDefinition,\n ],\n decorators: [\n defaultStrongDecoratorDefinition,\n defaultEmDecoratorDefinition,\n defaultCodeDecoratorDefinition,\n defaultStrikeThroughDecoratorDefinition,\n ],\n annotations: [defaultLinkObjectDefinition],\n blockObjects: [\n defaultCalloutObjectDefinition,\n defaultCodeObjectDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultTableObjectDefinition,\n ],\n inlineObjects: [defaultImageObjectDefinition],\n }),\n)\n","import type {\n PortableTextObject,\n Schema,\n SchemaDefinition,\n} from '@portabletext/schema'\n\n/**\n * Matcher function for mapping markdown elements to Portable Text block styles.\n *\n * @public\n */\nexport type StyleMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildStyleMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): StyleMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.styles.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown list items to Portable Text list types.\n *\n * @public\n */\nexport type ListItemMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildListItemMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ListItemMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.lists.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown inline formatting to Portable Text decorators.\n *\n * @public\n */\nexport type DecoratorMatcher = ({\n context,\n}: {\n context: {schema: Schema}\n}) => string | undefined\n\nexport function buildDecoratorMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): DecoratorMatcher {\n return ({context}) => {\n const schemaDefinition = context.schema.decorators.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n return schemaDefinition.name\n }\n}\n\n/**\n * Matcher function for mapping markdown links to Portable Text annotations.\n *\n * @public\n */\nexport type AnnotationMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n}) => PortableTextObject | undefined\n\nexport function buildAnnotationMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): AnnotationMatcher<ExtractValue<TDefinition>> {\n return ({context, value}) => {\n const schemaDefinition = context.schema.annotations.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n const filteredValue = schemaDefinition.fields.reduce<\n Record<string, unknown>\n >((filteredValue, field) => {\n const fieldValue = value[field.name as keyof typeof value]\n\n if (fieldValue !== undefined) {\n filteredValue[field.name] = fieldValue\n }\n\n return filteredValue\n }, {})\n\n return {\n _key: context.keyGenerator(),\n _type: schemaDefinition.name,\n ...filteredValue,\n }\n }\n}\n\n/**\n * Matcher function for mapping markdown objects to Portable Text block or inline objects.\n *\n * @public\n */\nexport type ObjectMatcher<\n TValue extends Record<string, unknown> = Record<string, never>,\n> = ({\n context,\n value,\n isInline,\n}: {\n context: {schema: Schema; keyGenerator: () => string}\n value: TValue\n isInline: boolean\n}) => PortableTextObject | undefined\n\nexport function buildObjectMatcher<TDefinition extends {name: string}>(\n definition: TDefinition,\n): ObjectMatcher<ExtractValue<TDefinition>> {\n return ({context, value, isInline}) => {\n const schemaCollection = isInline\n ? context.schema.inlineObjects\n : context.schema.blockObjects\n\n const schemaDefinition = schemaCollection.find(\n (item) => item.name === definition.name,\n )\n\n if (!schemaDefinition) {\n return undefined\n }\n\n const filteredValue = schemaDefinition.fields.reduce<\n Record<string, unknown>\n >((filteredValue, field) => {\n const fieldValue = value[field.name as keyof typeof value]\n\n if (fieldValue !== undefined) {\n filteredValue[field.name] = fieldValue\n }\n\n return filteredValue\n }, {})\n\n return {\n _key: context.keyGenerator(),\n _type: schemaDefinition.name,\n ...filteredValue,\n }\n }\n}\n\nexport type ExtractValue<\n TDefinition extends NonNullable<SchemaDefinition['blockObjects']>[0],\n> = TDefinition extends {fields: ReadonlyArray<{name: infer TNames}>}\n ? Record<TNames & string, unknown>\n : Record<string, never>\n","import {alert} from '@mdit/plugin-alert'\nimport {\n isSpan,\n isTextBlock,\n type PortableTextBlock,\n type PortableTextObject,\n type PortableTextTextBlock,\n type Schema,\n} from '@portabletext/schema'\nimport markdownit from 'markdown-it'\nimport {\n blockquoteStyleDefinition,\n defaultCalloutObjectDefinition,\n defaultCodeDecoratorDefinition,\n defaultCodeObjectDefinition,\n defaultEmDecoratorDefinition,\n defaultHorizontalRuleObjectDefinition,\n defaultHtmlObjectDefinition,\n defaultImageObjectDefinition,\n defaultLinkObjectDefinition,\n defaultOrderedListItemDefinition,\n defaultSchema,\n defaultStrikeThroughDecoratorDefinition,\n defaultStrongDecoratorDefinition,\n defaultTableObjectDefinition,\n defaultTaskListItemDefinition,\n defaultUnorderedListItemDefinition,\n h1StyleDefinition,\n h2StyleDefinition,\n h3StyleDefinition,\n h4StyleDefinition,\n h5StyleDefinition,\n h6StyleDefinition,\n normalStyleDefinition,\n} from '../default-schema'\nimport {unescapeImageAndLinkText} from '../escape'\nimport {defaultKeyGenerator} from '../key-generator'\nimport {\n buildAnnotationMatcher,\n buildDecoratorMatcher,\n buildListItemMatcher,\n buildObjectMatcher,\n buildStyleMatcher,\n type AnnotationMatcher,\n type DecoratorMatcher,\n type ExtractValue,\n type ListItemMatcher,\n type ObjectMatcher,\n type StyleMatcher,\n} from './matchers'\n\ntype Options = {\n schema?: Schema\n keyGenerator?: () => string\n marks?: {\n strong?: DecoratorMatcher\n em?: DecoratorMatcher\n code?: DecoratorMatcher\n strikeThrough?: DecoratorMatcher\n link?: AnnotationMatcher<{href: string; title: string | undefined}>\n }\n block?: {\n normal?: StyleMatcher\n blockquote?: StyleMatcher\n h1?: StyleMatcher\n h2?: StyleMatcher\n h3?: StyleMatcher\n h4?: StyleMatcher\n h5?: StyleMatcher\n h6?: StyleMatcher\n }\n listItem?: {\n number?: ListItemMatcher\n bullet?: ListItemMatcher\n task?: ListItemMatcher\n }\n types?: {\n code?: ObjectMatcher<{language: string | undefined; code: string}>\n horizontalRule?: ObjectMatcher\n html?: ObjectMatcher<{html: string}>\n table?: ObjectMatcher<{\n headerRows: number | undefined\n alignment: Array<'left' | 'center' | 'right' | null> | undefined\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n }>\n image?: ObjectMatcher<{src: string; alt: string; title: string | undefined}>\n callout?: ObjectMatcher<{tone: string; content: Array<PortableTextBlock>}>\n blockquote?: ObjectMatcher<{content: Array<PortableTextBlock>}>\n list?: ObjectMatcher<{\n kind: 'bullet' | 'number' | 'task'\n items: Array<{\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }>\n }>\n }\n html?: {\n /**\n * How to handle inline HTML.\n * - 'skip': Ignore inline HTML (default)\n * - 'text': Convert inline HTML to plain text\n *\n * @defaultValue 'skip'\n */\n inline?: 'skip' | 'text'\n }\n}\n\nconst codeBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultCodeObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultCodeObjectDefinition)\n const codeObject = defaultMatcher({context, value, isInline})\n\n if (!codeObject) {\n return undefined\n }\n\n if (!('code' in codeObject)) {\n return undefined\n }\n\n return codeObject\n}\n\nconst imageBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultImageObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultImageObjectDefinition)\n const imageObject = defaultMatcher({context, value, isInline})\n\n if (!imageObject) {\n return undefined\n }\n\n if (!('src' in imageObject)) {\n return undefined\n }\n\n return imageObject\n}\n\nconst tableBlockMatcher: ObjectMatcher<\n ExtractValue<typeof defaultTableObjectDefinition>\n> = ({context, value, isInline}) => {\n const defaultMatcher = buildObjectMatcher(defaultTableObjectDefinition)\n const tableObject = defaultMatcher({context, value, isInline})\n\n if (!tableObject) {\n return undefined\n }\n\n if (!('rows' in tableObject)) {\n return undefined\n }\n\n return tableObject\n}\n\nconst defaultOptions = {\n schema: defaultSchema,\n keyGenerator: defaultKeyGenerator,\n html: {\n inline: 'skip',\n },\n block: {\n normal: buildStyleMatcher(normalStyleDefinition),\n blockquote: buildStyleMatcher(blockquoteStyleDefinition),\n h1: buildStyleMatcher(h1StyleDefinition),\n h2: buildStyleMatcher(h2StyleDefinition),\n h3: buildStyleMatcher(h3StyleDefinition),\n h4: buildStyleMatcher(h4StyleDefinition),\n h5: buildStyleMatcher(h5StyleDefinition),\n h6: buildStyleMatcher(h6StyleDefinition),\n },\n listItem: {\n number: buildListItemMatcher(defaultOrderedListItemDefinition),\n bullet: buildListItemMatcher(defaultUnorderedListItemDefinition),\n task: buildListItemMatcher(defaultTaskListItemDefinition),\n },\n marks: {\n strong: buildDecoratorMatcher(defaultStrongDecoratorDefinition),\n em: buildDecoratorMatcher(defaultEmDecoratorDefinition),\n code: buildDecoratorMatcher(defaultCodeDecoratorDefinition),\n strikeThrough: buildDecoratorMatcher(\n defaultStrikeThroughDecoratorDefinition,\n ),\n link: buildAnnotationMatcher(defaultLinkObjectDefinition),\n },\n types: {\n code: codeBlockMatcher,\n horizontalRule: buildObjectMatcher(defaultHorizontalRuleObjectDefinition),\n html: buildObjectMatcher(defaultHtmlObjectDefinition),\n image: imageBlockMatcher,\n callout: buildObjectMatcher(defaultCalloutObjectDefinition),\n table: tableBlockMatcher,\n },\n} as const satisfies Options\n\n/**\n * Reads GFM column alignment from a markdown-it cell token's `style`\n * attribute. Tolerates other CSS declarations sharing the value.\n */\nexport function extractAlignmentFromStyleAttr(\n styleAttr: string | null,\n): 'left' | 'center' | 'right' | null {\n if (!styleAttr) {\n return null\n }\n const match = styleAttr.match(/text-align\\s*:\\s*(left|center|right)/)\n if (!match) {\n return null\n }\n return match[1] as 'left' | 'center' | 'right'\n}\n\n/**\n * A table row is empty when every cell holds only blank spans, no non-empty\n * text, no inline objects, no non-text blocks. Used to detect a headerless\n * GFM table: `portableTextToMarkdown` emits an empty header row for\n * `headerRows: 0`, and an empty header must round-trip back to\n * `headerRows: 0` rather than a phantom header row.\n */\nfunction isEmptyTableRow(\n cells: Array<{value: Array<PortableTextBlock>}>,\n context: {schema: Schema},\n): boolean {\n return cells.every((cell) =>\n cell.value.every(\n (block) =>\n isTextBlock(context, block) &&\n block.children.every(\n (child) => isSpan(context, child) && (child.text ?? '').trim() === '',\n ),\n ),\n )\n}\n\n/**\n * Flattens a table structure by lifting all blocks from all cells.\n */\nfunction flattenTable(\n table: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n },\n portableText: Array<PortableTextBlock>,\n): void {\n // Flatten the table by lifting all blocks from all cells\n for (const row of table.rows) {\n for (const cell of row.cells) {\n for (const block of cell.value) {\n portableText.push(block)\n }\n }\n }\n}\n\n/**\n * Converts a markdown string to an array of Portable Text blocks.\n *\n * @public\n */\nexport function markdownToPortableText(\n markdown: string,\n options?: Options,\n): Array<PortableTextBlock> {\n const consolidatedOptions = {\n schema: options?.schema ?? defaultSchema,\n keyGenerator: options?.keyGenerator ?? defaultKeyGenerator,\n html: {\n inline: options?.html?.inline ?? 'skip',\n },\n marks: {\n ...defaultOptions.marks,\n ...options?.marks,\n },\n block: {\n ...defaultOptions.block,\n ...options?.block,\n },\n listItem: {\n ...defaultOptions.listItem,\n ...options?.listItem,\n },\n types: {\n ...defaultOptions.types,\n ...options?.types,\n },\n }\n\n const md = markdownit({\n html: true,\n linkify: true,\n typographer: false,\n })\n .enable(['strikethrough', 'table'])\n .use(alert)\n\n const tokens = md.parse(markdown, {})\n\n // Pre-pass: detect GFM task-list checkbox prefixes (`[ ]`, `[x]`, `[X]`)\n // on the first inline content of each list item. Strip the prefix from the\n // inline content and remember which list items are tasks (and their checked\n // state) so the main walk can apply `listItem: 'task'` and `checked` when\n // processing the corresponding `list_item_open` token.\n const taskCheckedByListItemIndex = new Map<number, boolean>()\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]\n if (token?.type !== 'list_item_open') {\n continue\n }\n // Find the first inline token within this list item.\n let inlineIndex = -1\n for (let j = i + 1; j < tokens.length; j++) {\n const candidate = tokens[j]\n if (!candidate) {\n continue\n }\n if (candidate.type === 'list_item_close') {\n break\n }\n if (candidate.type === 'inline') {\n inlineIndex = j\n break\n }\n }\n if (inlineIndex === -1) {\n continue\n }\n const inlineToken = tokens[inlineIndex]\n if (!inlineToken) {\n continue\n }\n const match = inlineToken.content.match(/^\\[([ xX])\\] /)\n if (!match) {\n continue\n }\n const checked = match[1] !== ' '\n taskCheckedByListItemIndex.set(i, checked)\n // Strip the prefix from the content and the first child text token so the\n // resulting span doesn't include the checkbox marker.\n inlineToken.content = inlineToken.content.slice(match[0].length)\n const firstChild = inlineToken.children?.[0]\n if (firstChild && typeof firstChild.content === 'string') {\n firstChild.content = firstChild.content.slice(match[0].length)\n }\n }\n\n const portableText: Array<PortableTextBlock> = []\n\n // State\n let currentBlock: PortableTextTextBlock | null = null\n const currentListStack: Array<string | null> = []\n const markDefRefs: Array<string> = [] // mark keys: 'strong', 'em', 'code', or link keys\n let currentMarkDefs: Array<PortableTextObject> = []\n let currentBlockquoteStyle: string | null = null // Track blockquote style when inside blockquote\n let inListItem = false // Track if we're inside a list item\n\n // Callout state\n let calloutStartIndex: number | null = null\n let calloutStartTarget: Array<PortableTextBlock | PortableTextObject> | null =\n null\n let calloutType: string | null = null\n\n // Blockquote container state. When `types.blockquote` is defined and the\n // parser enters a `blockquote_open`, a frame is pushed here. Block\n // emissions inside the surrounding open/close pair are captured and\n // spliced out at close to wrap them in a `blockquote` block-object.\n // Nested blockquotes push additional frames; `blockTarget()` already\n // routes correctly because the splice happens against the same target.\n const blockquoteStack: Array<{\n startTarget: Array<PortableTextBlock | PortableTextObject>\n startIndex: number\n }> = []\n\n // Table state\n let currentTable: {\n rows: Array<{\n _key: string\n _type: 'row'\n cells: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }>\n }>\n headerRows: number\n emptyHeaderDropped: boolean\n alignment: Array<'left' | 'center' | 'right' | null>\n } | null = null\n let currentTableRow: Array<{\n _type: 'cell'\n _key: string\n value: Array<PortableTextBlock>\n }> | null = null\n let inTableHead = false\n\n // List container state. When `types.list` is defined and the parser enters\n // a `bullet_list_open` / `ordered_list_open`, a structural-list frame is\n // pushed here. Block emissions inside the surrounding `list_item_open` /\n // `list_item_close` pair are diverted into the item's `content` array\n // instead of the top-level `portableText`. At list-close, the matcher is\n // called to materialize a `list` block-object, which is pushed into the\n // enclosing target (parent list item's content if nested, else top-level).\n type ListContainerItem = {\n _type: 'list-item'\n _key: string\n checked?: boolean\n content: Array<PortableTextBlock | PortableTextObject>\n }\n type ListContainerFrame = {\n kind: 'bullet' | 'number' | 'task'\n items: Array<ListContainerItem>\n currentItem: ListContainerItem | null\n }\n // A null entry marks a list that is being handled by the flat path (either\n // because `types.list` is undefined, or because a nested list inside a\n // flat-path list should also stay flat). Parallel to `currentListStack`.\n const listContainerStack: Array<ListContainerFrame | null> = []\n\n /**\n * Returns the array that block emissions should land in. If the innermost\n * structural list frame has an open `currentItem`, blocks land in that\n * item's `content`. Otherwise blocks land at the top level.\n */\n const blockTarget = (): Array<PortableTextBlock | PortableTextObject> => {\n for (let i = listContainerStack.length - 1; i >= 0; i--) {\n const frame = listContainerStack[i]\n if (frame && frame.currentItem) {\n return frame.currentItem.content\n }\n }\n return portableText\n }\n\n /**\n * Pushes a block into the current target (innermost open list item, or\n * top-level `portableText` if none). Use instead of direct\n * `portableText.push(...)` for any block emission that should be captured\n * by an enclosing list container.\n */\n const pushBlock = (block: PortableTextBlock | PortableTextObject): void => {\n blockTarget().push(block as PortableTextBlock)\n }\n\n const startBlock = (style: string) => {\n flushBlock()\n currentBlock = {\n _type: 'block' as const,\n style,\n children: [],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n }\n currentMarkDefs = []\n }\n\n const flushBlock = () => {\n if (!currentBlock) {\n return\n }\n\n // Text blocks must have at least one child span\n if (currentBlock.children.length === 0) {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n })\n }\n\n // Assign accumulated markDefs to the block\n currentBlock.markDefs = currentMarkDefs\n\n pushBlock(currentBlock)\n\n currentBlock = null\n currentMarkDefs = []\n }\n\n const addSpan = (text: string) => {\n if (text.length === 0) {\n return\n }\n\n if (!currentBlock) {\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n const lastChild = currentBlock.children.at(-1)\n\n if (\n isSpan({schema: consolidatedOptions.schema}, lastChild) &&\n lastChild.marks?.every((mark) => markDefRefs.includes(mark)) &&\n markDefRefs.every((mark) => lastChild.marks?.includes(mark))\n ) {\n // Merge with previous span if marks match\n lastChild.text += text\n } else {\n currentBlock.children.push({\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: text,\n marks: [...markDefRefs],\n })\n }\n }\n\n // Helpers for lists\n const listLevel = () => currentListStack.length\n const ensureListBlock = (listItem: string, checked?: boolean) => {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n if (!currentBlock) {\n throw new Error('Expected current block')\n }\n\n if (\n currentBlock.listItem !== listItem ||\n currentBlock.level !== listLevel()\n ) {\n currentBlock.listItem = listItem\n currentBlock.level = listLevel()\n }\n\n if (checked !== undefined) {\n ;(currentBlock as PortableTextTextBlock & {checked?: boolean}).checked =\n checked\n }\n }\n\n // Walk tokens\n for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {\n const token = tokens[tokenIndex]\n if (!token) {\n continue\n }\n\n switch (token.type) {\n // Paragraphs\n case 'paragraph_open': {\n // If we're in a list item but have no current block (e.g., after a code block),\n // we need to create a new list item block\n if (inListItem) {\n // Structural list path: start a plain text block; the paragraph\n // lands in the current list item's `content` via `pushBlock`.\n if (listContainerStack.at(-1)) {\n if (!currentBlock) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ??\n 'normal'\n startBlock(style)\n }\n break\n }\n\n // Flat list path: ensure the current text block carries\n // `listItem` + `level` fields.\n if (!currentBlock) {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n\n break\n }\n\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n break\n }\n\n startBlock(style)\n break\n }\n case 'paragraph_close':\n // In a flat list item: skip flushing, list_item_close will flush.\n // In a structural list item: flush so multiple paragraphs in one\n // item land as separate text blocks.\n if (inListItem) {\n if (listContainerStack.at(-1)) {\n flushBlock()\n }\n break\n }\n flushBlock()\n break\n\n // Headings\n case 'heading_open': {\n const level = Number(token?.tag?.slice(1))\n\n // Map level to the appropriate heading matcher\n const headingMatchers = {\n 1: consolidatedOptions.block.h1,\n 2: consolidatedOptions.block.h2,\n 3: consolidatedOptions.block.h3,\n 4: consolidatedOptions.block.h4,\n 5: consolidatedOptions.block.h5,\n 6: consolidatedOptions.block.h6,\n } as const\n\n const headingMatcher =\n headingMatchers[level as keyof typeof headingMatchers]\n\n const style =\n headingMatcher?.({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No heading style found, using \"normal\"')\n startBlock('normal')\n break\n }\n\n startBlock(style)\n break\n }\n case 'heading_close':\n flushBlock()\n break\n\n // Blockquote\n case 'blockquote_open': {\n // Flush any current block before entering blockquote\n flushBlock()\n\n // Structural-blockquote path: when the consumer registers a\n // `types.blockquote` matcher, plain blockquotes (NOT GFM alerts -\n // those use separate `alert_open`/`alert_close` tokens) become\n // block-objects with an explicit `content` array. Block emissions\n // inside the open/close pair are spliced out at close time and\n // wrapped in a `blockquote` block-object.\n if (consolidatedOptions.types.blockquote) {\n const startTarget = blockTarget()\n blockquoteStack.push({\n startTarget,\n startIndex: startTarget.length,\n })\n break\n }\n\n // Flat path: set the blockquote style for paragraphs inside the\n // blockquote so they emit text blocks with `style: 'blockquote'`.\n const style =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n case 'blockquote_close': {\n // Flush any blockquote content before exiting\n flushBlock()\n\n // Structural path: pop the topmost frame and splice its captured\n // content into a `blockquote` block-object via the matcher. If the\n // matcher returns undefined, fall back to flat-style by re-emitting\n // the content blocks with `style: 'blockquote'`.\n if (\n consolidatedOptions.types.blockquote &&\n blockquoteStack.length > 0\n ) {\n const frame = blockquoteStack.pop()\n if (frame) {\n const contentBlocks = frame.startTarget.splice(\n frame.startIndex,\n ) as Array<PortableTextBlock>\n\n const blockquoteObject = consolidatedOptions.types.blockquote({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {content: contentBlocks},\n isInline: false,\n })\n\n if (blockquoteObject) {\n pushBlock(blockquoteObject)\n } else {\n // Matcher returned undefined: fall back to flat-style by\n // re-emitting each content block with `style: 'blockquote'`.\n const blockquoteStyle =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ??\n 'blockquote'\n for (const block of contentBlocks) {\n if (block._type === 'block') {\n pushBlock({\n ...(block as PortableTextTextBlock),\n style: blockquoteStyle,\n })\n } else {\n pushBlock(block)\n }\n }\n }\n }\n break\n }\n\n currentBlockquoteStyle = null\n break\n }\n // Lists\n case 'bullet_list_open': {\n flushBlock()\n\n // Structural-container path: when the consumer registers a\n // `types.list` matcher, lists become block-objects with explicit\n // `items` arrays. Block emissions inside list items are diverted\n // into `currentItem.content` via `blockTarget()`. Mirrors the\n // `types.table` pattern.\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'bullet',\n items: [],\n currentItem: null,\n })\n currentListStack.push(null)\n break\n }\n\n // Flat path: lists are reconstructed from text blocks with\n // `listItem` + `level` fields at render time.\n const listItem = consolidatedOptions.listItem.bullet({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n currentListStack.push(null)\n break\n }\n currentListStack.push(listItem)\n break\n }\n case 'ordered_list_open': {\n flushBlock()\n\n if (consolidatedOptions.types.list) {\n listContainerStack.push({\n kind: 'number',\n items: [],\n currentItem: null,\n })\n currentListStack.push(null)\n break\n }\n\n const listItem = consolidatedOptions.listItem.number({\n context: {schema: consolidatedOptions.schema},\n })\n\n listContainerStack.push(null)\n if (!listItem) {\n currentListStack.push(null)\n break\n }\n currentListStack.push(listItem)\n break\n }\n case 'bullet_list_close':\n case 'ordered_list_close': {\n const frame = listContainerStack.pop()\n currentListStack.pop()\n\n // Structural close: materialize the list block-object and push it\n // into the enclosing target (parent list item's content if nested,\n // else top-level).\n if (frame && consolidatedOptions.types.list) {\n // Promote `kind` to 'task' if any item carries a checked state.\n const kind: 'bullet' | 'number' | 'task' = frame.items.some(\n (item) => 'checked' in item,\n )\n ? 'task'\n : frame.kind\n\n const listObject = consolidatedOptions.types.list({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {kind, items: frame.items},\n isInline: false,\n })\n\n if (listObject) {\n pushBlock(listObject)\n } else {\n // Matcher returned undefined: fall back to the flat path by\n // re-emitting each item's content. Text blocks get the same\n // `listItem` + `level` fields the flat path would produce so\n // adjacent blocks form a list at render time. Non-text-block\n // content (code blocks, etc.) gets pushed as-is, mirroring\n // how the flat path handles those when they appear inside a\n // list item.\n const flatListItem =\n (kind === 'task'\n ? consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n })\n : kind === 'number'\n ? consolidatedOptions.listItem.number({\n context: {schema: consolidatedOptions.schema},\n })\n : consolidatedOptions.listItem.bullet({\n context: {schema: consolidatedOptions.schema},\n })) ?? null\n // The just-popped list was nested at depth = remaining stack\n // length + 1 (since we already popped).\n const level = listContainerStack.length + 1\n for (const item of frame.items) {\n for (const block of item.content) {\n if (\n block._type === 'block' &&\n flatListItem !== null &&\n !('listItem' in block)\n ) {\n const flatBlock = {\n ...(block as PortableTextTextBlock),\n listItem: flatListItem,\n level,\n ...(item.checked === undefined\n ? {}\n : {checked: item.checked}),\n }\n pushBlock(flatBlock)\n } else {\n pushBlock(block)\n }\n }\n }\n }\n }\n break\n }\n case 'list_item_open': {\n const frame = listContainerStack.at(-1)\n\n // Flush any previous list item block before starting a new one\n // This is needed for proper separation of list items\n if (currentBlock) {\n flushBlock()\n }\n\n // Structural path: start a new `list-item` whose `content` becomes\n // the divert target for subsequent block emissions until\n // `list_item_close`.\n if (frame) {\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n frame.currentItem = {\n _type: 'list-item',\n _key: consolidatedOptions.keyGenerator(),\n ...(taskChecked === undefined ? {} : {checked: taskChecked}),\n content: [],\n }\n inListItem = true\n break\n }\n\n // Flat path\n const baseListType = currentListStack.at(-1)\n\n if (baseListType === undefined) {\n throw new Error('Expected an open list')\n }\n\n // Resolve task list type and checked state for this specific item.\n // If the schema declares a `task` list definition, GFM checkboxes\n // (`- [ ]` / `- [x]`) override the surrounding list's type for this\n // item. Otherwise the prefix has already been stripped by the\n // pre-pass and we render as the surrounding list type.\n const taskChecked = taskCheckedByListItemIndex.get(tokenIndex)\n let listType = baseListType\n let checked: boolean | undefined\n if (taskChecked !== undefined) {\n const taskListType = consolidatedOptions.listItem.task?.({\n context: {schema: consolidatedOptions.schema},\n })\n if (taskListType) {\n listType = taskListType\n checked = taskChecked\n }\n }\n\n // If listType is null, it means there's no list definition in the schema\n // Just create a normal block without list properties\n if (listType === null) {\n // Use blockquote style if inside a blockquote, otherwise use normal style\n const style =\n currentBlockquoteStyle ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n inListItem = true\n break\n }\n\n ensureListBlock(listType, checked)\n inListItem = true\n break\n }\n case 'list_item_close': {\n const frame = listContainerStack.at(-1)\n\n // Structural path: flush any current block into the item's content,\n // then push the completed item onto the frame.\n if (frame && frame.currentItem) {\n flushBlock()\n frame.items.push(frame.currentItem)\n frame.currentItem = null\n inListItem = false\n break\n }\n\n // Flat path\n inListItem = false\n flushBlock()\n break\n }\n\n // Code fences / blocks\n case 'fence': {\n flushBlock()\n\n const language = token.info.trim() || undefined\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language, code},\n isInline: false,\n })\n\n if (!codeObject) {\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n break\n }\n\n pushBlock(codeObject)\n\n break\n }\n\n // Horizontal rule\n case 'hr': {\n flushBlock()\n\n const hrObject = consolidatedOptions.types.horizontalRule({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {},\n isInline: false,\n })\n\n if (!hrObject) {\n // If there's no break definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan('---')\n flushBlock()\n break\n }\n\n pushBlock(hrObject)\n\n break\n }\n\n // HTML block\n case 'html_block': {\n flushBlock()\n\n const htmlContent = token.content.trim()\n\n if (!htmlContent) {\n break\n }\n\n const htmlObject = consolidatedOptions.types.html({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {html: htmlContent},\n isInline: false,\n })\n\n if (!htmlObject) {\n // If there's no HTML block definition in the schema, parse as text\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(htmlContent)\n flushBlock()\n break\n }\n\n pushBlock(htmlObject)\n\n break\n }\n\n case 'code_block': {\n flushBlock()\n\n // Remove trailing newline from code content\n const code = token.content.replace(/\\n$/, '')\n\n const codeObject = consolidatedOptions.types.code({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {language: undefined, code},\n isInline: false,\n })\n\n if (!codeObject) {\n // Code block not in schema, fall back to text block\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n\n addSpan(code)\n flushBlock()\n } else {\n pushBlock(codeObject)\n }\n\n break\n }\n\n // Tables\n case 'table_open':\n flushBlock()\n currentTable = {\n rows: [],\n headerRows: 0,\n emptyHeaderDropped: false,\n alignment: [],\n }\n break\n\n case 'table_close': {\n if (!currentTable) {\n break\n }\n\n // Only create table object if table type is defined\n if (consolidatedOptions.types.table) {\n const hasAlignment = currentTable.alignment.some((a) => a !== null)\n const tableObject = consolidatedOptions.types.table({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {\n rows: currentTable.rows,\n headerRows:\n currentTable.headerRows > 0\n ? currentTable.headerRows\n : currentTable.emptyHeaderDropped\n ? 0\n : undefined,\n alignment: hasAlignment ? currentTable.alignment : undefined,\n },\n isInline: false,\n })\n\n if (tableObject) {\n pushBlock(tableObject)\n } else {\n // If table object couldn't be created, flatten the table\n flattenTable(\n currentTable,\n blockTarget() as Array<PortableTextBlock>,\n )\n }\n } else {\n // If there's no table definition in the schema, flatten the table\n flattenTable(currentTable, blockTarget() as Array<PortableTextBlock>)\n }\n\n currentTable = null\n break\n }\n\n case 'thead_open':\n inTableHead = true\n break\n\n case 'thead_close':\n inTableHead = false\n break\n\n case 'tbody_open':\n case 'tbody_close':\n // Just markers, no action needed\n break\n\n case 'tr_open':\n currentTableRow = []\n break\n\n case 'tr_close':\n if (currentTable && currentTableRow) {\n if (\n inTableHead &&\n isEmptyTableRow(currentTableRow, {\n schema: consolidatedOptions.schema,\n })\n ) {\n // An all-empty header row means \"no header\": drop it and leave\n // `headerRows` at 0 (recorded so `table_close` emits an explicit\n // 0, not `undefined`), so `portableTextToMarkdown`'s headerless\n // output round-trips back to `headerRows: 0`.\n currentTable.emptyHeaderDropped = true\n } else {\n currentTable.rows.push({\n _key: consolidatedOptions.keyGenerator(),\n _type: 'row',\n cells: currentTableRow,\n })\n if (inTableHead) {\n currentTable.headerRows++\n }\n }\n }\n currentTableRow = null\n break\n\n case 'th_open':\n case 'td_open': {\n // Alignment is per-column, set on every cell of that column. Read\n // from the header so each column contributes exactly one entry.\n if (currentTable && inTableHead && token.type === 'th_open') {\n currentTable.alignment.push(\n extractAlignmentFromStyleAttr(token.attrGet('style')),\n )\n }\n\n // Start a new block for the table cell\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n break\n }\n\n case 'th_close':\n case 'td_close': {\n // Flush the current block into the cell\n flushBlock()\n\n // Get all blocks that were added since this cell started\n // We need to extract them from the current target array\n const cellBlocks: Array<PortableTextBlock> = []\n const target = blockTarget()\n\n // Check if we have blocks to extract (added after table_open)\n if (target.length > 0) {\n const lastBlock = target.at(-1)\n if (lastBlock && lastBlock._type === 'block') {\n cellBlocks.push(target.pop()! as PortableTextBlock)\n }\n }\n\n // If no blocks were created (empty cell), create an empty block\n if (cellBlocks.length === 0) {\n cellBlocks.push({\n _type: 'block' as const,\n style:\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) || 'normal',\n children: [\n {\n _type: consolidatedOptions.schema.span.name,\n _key: consolidatedOptions.keyGenerator(),\n text: '',\n marks: [],\n },\n ],\n _key: consolidatedOptions.keyGenerator(),\n markDefs: [],\n })\n }\n\n // Check if the cell contains a single block with a single image child\n // If so, extract the image as a block-level image\n const firstBlock = cellBlocks[0]\n if (\n cellBlocks.length === 1 &&\n firstBlock &&\n firstBlock._type === 'block' &&\n 'children' in firstBlock &&\n Array.isArray(firstBlock.children) &&\n firstBlock.children.length === 1\n ) {\n const onlyChild = firstBlock.children[0]\n // Check if it's an image object (not a span)\n if (\n typeof onlyChild === 'object' &&\n onlyChild !== null &&\n '_type' in onlyChild &&\n onlyChild._type !== consolidatedOptions.schema.span.name &&\n onlyChild._type === 'image'\n ) {\n // Replace the block with just the image\n cellBlocks[0] = onlyChild as PortableTextBlock\n }\n }\n\n if (currentTableRow !== null) {\n currentTableRow.push({\n _type: 'cell',\n _key: consolidatedOptions.keyGenerator(),\n value: cellBlocks,\n })\n }\n break\n }\n\n // Inline container\n case 'inline': {\n // Check if we're in a table cell\n const inTableCell = currentTableRow !== null\n\n // Check if this is a standalone image (paragraph with only an image)\n if (\n token.children?.length === 1 &&\n token.children[0]?.type === 'image'\n ) {\n const imageToken = token.children[0]\n if (!imageToken) {\n break\n }\n\n const src =\n imageToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(imageToken.content || '')\n const title =\n imageToken.attrs?.find(([name]) => name === 'title')?.at(1) ||\n undefined\n\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: false,\n })\n\n if (blockImageObject) {\n if (inTableCell) {\n // In table cells, we can't push to portableText directly\n // The block image will be handled in th_close/td_close extraction logic\n // For now, add it as a child of the current block\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n } else {\n // If the current block has content, flush it before adding the block image\n // Otherwise, discard the empty block that was created by paragraph_open\n const hasContent =\n currentBlock &&\n 'children' in currentBlock &&\n (currentBlock as PortableTextTextBlock).children.length > 0\n\n if (hasContent) {\n flushBlock()\n } else {\n currentBlock = null\n currentMarkDefs = []\n }\n pushBlock(blockImageObject)\n }\n break\n }\n\n // Block image not supported, try inline image as fallback\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title},\n isInline: true,\n })\n\n if (inlineImageObject) {\n // Ensure we have a block to add the inline image to\n if (!currentBlock) {\n if (inListItem) {\n // Structural list: start a plain text block; the image\n // lands in the current item's content via flushBlock.\n if (listContainerStack.at(-1)) {\n const style =\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n }) ?? 'normal'\n startBlock(style)\n } else {\n const listType = currentListStack.at(-1)\n\n if (listType) {\n ensureListBlock(listType)\n }\n }\n } else {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n }\n }\n\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Neither block nor inline image supported, fall back to text\n addSpan(`![${alt}](${src})`)\n break\n }\n\n // Walk its children for text/marks/links\n for (const childToken of token.children ?? []) {\n switch (childToken.type) {\n case 'text':\n addSpan(childToken.content)\n break\n case 'softbreak':\n case 'hardbreak':\n addSpan('\\n')\n break\n case 'code_inline': {\n const decorator = consolidatedOptions.marks.code({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n // No code decorator defined, just add the content without marks\n addSpan(childToken.content)\n break\n }\n\n markDefRefs.push(decorator)\n addSpan(childToken.content)\n\n // code_inline is self-contained, so we need to pop the decorator\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'strong_open': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n break\n }\n case 'strong_close': {\n const decorator = consolidatedOptions.marks.strong({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'em_open': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 'em_close': {\n const decorator = consolidatedOptions.marks.em({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 's_open': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n markDefRefs.push(decorator)\n\n break\n }\n case 's_close': {\n const decorator = consolidatedOptions.marks.strikeThrough({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!decorator) {\n break\n }\n\n const index = markDefRefs.lastIndexOf(decorator)\n\n if (index !== -1) {\n markDefRefs.splice(index, 1)\n }\n\n break\n }\n case 'link_open': {\n const href = childToken.attrs\n ?.find(([name]) => name === 'href')\n ?.at(1)\n\n if (!href) {\n break\n }\n\n const title = childToken.attrs\n ?.find(([name]) => name === 'title')\n ?.at(1)\n\n const linkObject = consolidatedOptions.marks.link({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {href, title},\n })\n\n if (!linkObject) {\n break\n }\n\n currentMarkDefs.push(linkObject)\n markDefRefs.push(linkObject._key)\n break\n }\n case 'link_close': {\n // remove the last link key\n const markDefKeys = new Set(currentMarkDefs.map((d) => d._key))\n let lastLinkIndex: number | undefined\n\n for (const markDefRef of markDefRefs.reverse()) {\n if (markDefKeys.has(markDefRef)) {\n lastLinkIndex = markDefRefs.indexOf(markDefRef)\n break\n }\n }\n\n if (lastLinkIndex !== undefined) {\n const realIndex = markDefRefs.length - 1 - lastLinkIndex\n markDefRefs.splice(realIndex, 1)\n }\n break\n }\n case 'image': {\n const src =\n childToken.attrs?.find(([name]) => name === 'src')?.at(1) || ''\n const alt = unescapeImageAndLinkText(childToken.content || '')\n\n // Try to create an inline image first\n const inlineImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: true,\n })\n\n if (inlineImageObject) {\n // Inline image is supported - add it to current block\n if (!currentBlock) {\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (!style) {\n console.warn('No default style found, using \"normal\"')\n startBlock('normal')\n } else {\n startBlock(style)\n }\n }\n\n // At this point currentBlock should exist\n if (!currentBlock) {\n throw new Error('Expected current block after startBlock')\n }\n\n // Add the image as an inline object (TypeScript assertion needed for type narrowing)\n ;(currentBlock as PortableTextTextBlock).children.push(\n inlineImageObject as PortableTextObject,\n )\n break\n }\n\n // Inline image not supported - try block image as fallback\n const blockImageObject = consolidatedOptions.types.image({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {src, alt, title: undefined},\n isInline: false,\n })\n\n if (!blockImageObject) {\n // Neither inline nor block image supported\n addSpan(`![${alt}](${src})`)\n break\n }\n\n // Block image supported - flush current block and add as block-level\n // Skip if we're in a table cell (images in cells are handled differently)\n if (inTableCell) {\n // In table cells, add the image to current block (will be extracted later)\n if (currentBlock && 'children' in currentBlock) {\n ;(currentBlock as PortableTextTextBlock).children.push(\n blockImageObject as PortableTextObject,\n )\n }\n break\n }\n\n // Not in table - flush current block, add image as block, start new block\n flushBlock()\n pushBlock(blockImageObject)\n\n // Start a new block for any remaining content\n const style = consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n if (style) {\n startBlock(style)\n }\n\n break\n }\n case 'html_inline': {\n // Handle inline HTML based on configuration\n if (consolidatedOptions.html.inline === 'text') {\n addSpan(childToken.content)\n }\n // 'skip' - do nothing, ignore the HTML\n break\n }\n default:\n // Ignore other inline token types by default\n break\n }\n }\n break\n }\n\n // Callouts (GFM alerts)\n case 'alert_open': {\n flushBlock()\n calloutStartTarget = blockTarget()\n calloutStartIndex = calloutStartTarget.length\n calloutType = token.markup\n\n // Set blockquote style so content blocks inside the callout\n // get blockquote styling (used in fallback when callout type\n // is not in the schema)\n const style =\n consolidatedOptions.block.blockquote({\n context: {schema: consolidatedOptions.schema},\n }) ??\n consolidatedOptions.block.normal({\n context: {schema: consolidatedOptions.schema},\n })\n\n currentBlockquoteStyle = style ?? 'normal'\n break\n }\n\n case 'alert_title': {\n // Type is already captured via alert_open's markup\n break\n }\n\n case 'alert_close': {\n flushBlock()\n\n if (\n calloutStartIndex !== null &&\n calloutType !== null &&\n calloutStartTarget !== null\n ) {\n const contentBlocks = calloutStartTarget.splice(\n calloutStartIndex,\n ) as Array<PortableTextBlock>\n\n const calloutObject = consolidatedOptions.types.callout?.({\n context: {\n schema: consolidatedOptions.schema,\n keyGenerator: consolidatedOptions.keyGenerator,\n },\n value: {tone: calloutType, content: contentBlocks},\n isInline: false,\n })\n\n if (calloutObject) {\n pushBlock(calloutObject)\n } else {\n for (const block of contentBlocks) {\n pushBlock(block)\n }\n }\n }\n\n calloutStartIndex = null\n calloutStartTarget = null\n calloutType = null\n currentBlockquoteStyle = null\n break\n }\n\n default:\n break\n }\n }\n\n flushBlock()\n\n return portableText\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/markdown",
3
- "version": "1.4.7",
3
+ "version": "1.5.0",
4
4
  "description": "Convert Portable Text to and from Markdown",
5
5
  "keywords": [
6
6
  "markdown",