@portabletext/markdown 1.4.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -79
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +139 -21
- package/dist/index.js.map +1 -1
- package/package.json +7 -11
package/README.md
CHANGED
|
@@ -70,19 +70,44 @@ const markdown = portableTextToMarkdown([
|
|
|
70
70
|
| Blockquotes | ✅ | ✅ |
|
|
71
71
|
| Ordered lists | ✅ | ✅ |
|
|
72
72
|
| Unordered lists | ✅ | ✅ |
|
|
73
|
-
| Task lists |
|
|
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
|
-
|
|
82
|
+
## Round-trip behavior
|
|
83
|
+
|
|
84
|
+
1. Translation preserves semantics, not source spelling. The first MD→PT→MD pass normalizes Markdown to one canonical spelling: autolinks and reference links become inline links, indented code becomes fenced code, and emphasis, headings, lists, and tables each get one canonical form.
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
<https://portabletext.org> -> [https://portabletext.org](https://portabletext.org)
|
|
88
|
+
[ref link][id] -> [ref link](https://example.com "title")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
2. The normalized Markdown is a fixpoint for the constructs in the [Supported features](#supported-features) table above: parsing it and serializing again reproduces it byte-for-byte, pinned by a full-document round-trip test. This doesn't yet extend to plain text that happens to contain literal Markdown punctuation: serialization doesn't escape it, so a second parse reads it back as markup instead of literal text.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
\*bar\* -> *bar* (serialized unescaped; a second parse reads this as emphasis)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
3. MD→PT survival is schema-driven. Constructs whose type the schema doesn't declare degrade predictably: they keep their content and drop the structure that named them. Marks drop formatting but keep the text (`**bar**` with no `strong` decorator in the schema becomes a plain span reading `bar`); tables flatten their cell content into top-level blocks; images fall back to their Markdown source as plain text; task-list checkboxes strip to plain list items.
|
|
98
|
+
|
|
99
|
+
4. PT structures with no Markdown form degrade predictably on PT→MD. GFM tables have one header row, so header rows beyond the first flatten into the body. Deep or level-skipping lists collapse to relative nesting. A list's first item renders at the top level whatever its `level`, and each deeper jump between items indents one step, however many levels it skips. Multi-block table cells join their blocks with spaces. Unknown object types render as a fenced JSON block; unknown marks pass their text through unformatted.
|
|
100
|
+
|
|
101
|
+
5. Identity does not round-trip. Keys are regenerated on every parse, and adjacent spans with identical marks merge into one.
|
|
83
102
|
|
|
84
103
|
## Usage
|
|
85
104
|
|
|
105
|
+
<!-- The schema table, matcher table, supported-features table, and
|
|
106
|
+
round-trip section have condensed twins on the docs site
|
|
107
|
+
(apps/docs/src/content/docs/conversion/markdown-to-portable-text.mdx).
|
|
108
|
+
Keep them in sync: a claim corrected in one place is stale in the
|
|
109
|
+
other. -->
|
|
110
|
+
|
|
86
111
|
### `markdownToPortableText`
|
|
87
112
|
|
|
88
113
|
```ts
|
|
@@ -162,14 +187,14 @@ Out of the box, the library includes sensible defaults for both. Customize them
|
|
|
162
187
|
|
|
163
188
|
The default schema includes the following definitions:
|
|
164
189
|
|
|
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'` (
|
|
172
|
-
| `inlineObjects` | `'image'` (fields: `'src'`, `'alt'`, `'title'`)
|
|
190
|
+
| Type | Values |
|
|
191
|
+
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
192
|
+
| `styles` | `'normal'`, `'h1'`, `'h2'`, `'h3'`, `'h4'`, `'h5'`, `'h6'`, `'blockquote'` |
|
|
193
|
+
| `lists` | `'number'`, `'bullet'`, `'task'` |
|
|
194
|
+
| `decorators` | `'strong'`, `'em'`, `'code'`, `'strike-through'` |
|
|
195
|
+
| `annotations` | `'link'` (fields: `'href'`, `'title'`) |
|
|
196
|
+
| `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'`) |
|
|
197
|
+
| `inlineObjects` | `'image'` (fields: `'src'`, `'alt'`, `'title'`) |
|
|
173
198
|
|
|
174
199
|
To use a custom Schema, import `compileSchema` and `defineSchema` from `@portabletext/schema`:
|
|
175
200
|
|
|
@@ -218,8 +243,38 @@ Matchers map Markdown concepts to Portable Text types defined in the Schema. Eac
|
|
|
218
243
|
| | `image` | `` | `'image'` |
|
|
219
244
|
| | `html` | HTML blocks | `'html'` |
|
|
220
245
|
| | `callout` | `> [!NOTE]`, etc. | `'callout'` |
|
|
221
|
-
| | `
|
|
222
|
-
| | `
|
|
246
|
+
| | `table` | GFM pipe tables | `'table'` |
|
|
247
|
+
| | `blockquote`\* | `>` blockquotes | `'blockquote'` |
|
|
248
|
+
| | `list`\* | `- ` or `1. ` lists | `'list'` |
|
|
249
|
+
|
|
250
|
+
\* 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.
|
|
251
|
+
|
|
252
|
+
#### Default behavior
|
|
253
|
+
|
|
254
|
+
**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.
|
|
255
|
+
|
|
256
|
+
**Images** are handled based on context:
|
|
257
|
+
|
|
258
|
+
- Standalone images (a paragraph containing only an image) become block-level `'image'` objects
|
|
259
|
+
- Images mixed with text become inline `'image'` objects (if the schema includes `'image'` in `inlineObjects`)
|
|
260
|
+
- If neither is supported, falls back to plain text: ``
|
|
261
|
+
|
|
262
|
+
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`.
|
|
263
|
+
|
|
264
|
+
**Code** is handled based on the Markdown syntax:
|
|
265
|
+
|
|
266
|
+
- Fenced code blocks (` ``` `) become `'code'` block objects with `language` and `code` fields
|
|
267
|
+
- Inline code (`` ` ``) applies the `'code'` decorator to a span
|
|
268
|
+
|
|
269
|
+
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`.
|
|
270
|
+
|
|
271
|
+
**Links** support optional titles using `[text](url "title")` syntax. The title is captured in the `'title'` field of the `'link'` annotation.
|
|
272
|
+
|
|
273
|
+
**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.).
|
|
274
|
+
|
|
275
|
+
**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.
|
|
276
|
+
|
|
277
|
+
**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
278
|
|
|
224
279
|
#### Configuring matchers
|
|
225
280
|
|
|
@@ -246,7 +301,7 @@ markdownToPortableText(markdown, {
|
|
|
246
301
|
|
|
247
302
|
> **Note:** Checking if the type exists in the schema isn't required, but it's good practice. Returning `undefined` gracefully skips unsupported types.
|
|
248
303
|
|
|
249
|
-
**Table matcher:**
|
|
304
|
+
**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
305
|
|
|
251
306
|
```ts
|
|
252
307
|
markdownToPortableText(markdown, {
|
|
@@ -288,7 +343,7 @@ The matcher receives `value.items` already assembled. Each item's `content` arra
|
|
|
288
343
|
|
|
289
344
|
Without `types.list`, the existing flat-block path runs unchanged.
|
|
290
345
|
|
|
291
|
-
**GFM task lists** (`- [ ]` / `- [x]`): Task lists are recognized when the schema declares a `task` list item. Without a `task` definition, the checkbox markers are stripped from the text and the items render as their surrounding list type (bullet or number). With a `task` definition, items carrying a checkbox become text blocks with `listItem: 'task'` and a `checked: boolean` field; items without a checkbox keep their surrounding list type.
|
|
346
|
+
**GFM task lists** (`- [ ]` / `- [x]`): Task lists are recognized when the schema declares a `task` list item; the default schema does, so task lists parse zero-config. Without a `task` definition (a custom schema that omits it), the checkbox markers are stripped from the text and the items render as their surrounding list type (bullet or number). With a `task` definition, items carrying a checkbox become text blocks with `listItem: 'task'` and a `checked: boolean` field; items without a checkbox keep their surrounding list type.
|
|
292
347
|
|
|
293
348
|
```ts
|
|
294
349
|
markdownToPortableText('- [x] done\n- [ ] todo', {
|
|
@@ -348,31 +403,6 @@ Matchers receive:
|
|
|
348
403
|
|
|
349
404
|
Return `undefined` to skip the element (e.g., if the type isn't in the schema).
|
|
350
405
|
|
|
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: ``
|
|
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
406
|
#### Other options
|
|
377
407
|
|
|
378
408
|
```ts
|
|
@@ -449,34 +479,42 @@ The conversion is driven by **Renderers**: functions that render Portable Text e
|
|
|
449
479
|
|
|
450
480
|
#### Default renderers
|
|
451
481
|
|
|
452
|
-
| Group | Renderer
|
|
453
|
-
| ------------------- |
|
|
454
|
-
| `
|
|
455
|
-
| | `
|
|
456
|
-
| | `
|
|
457
|
-
| `
|
|
458
|
-
| | `
|
|
459
|
-
| | `
|
|
460
|
-
|
|
|
461
|
-
| | `
|
|
462
|
-
| | `
|
|
463
|
-
| `
|
|
464
|
-
| `
|
|
465
|
-
| `
|
|
466
|
-
| `
|
|
467
|
-
| `
|
|
468
|
-
| `
|
|
469
|
-
| `
|
|
482
|
+
| Group | Renderer | Renders | Output |
|
|
483
|
+
| ------------------- | ----------------- | --------------------------------- | ------------------------ |
|
|
484
|
+
| `types` | `callout` | `callout` block objects | `> [!TYPE]\n> content` |
|
|
485
|
+
| | `code` | `code` block objects | Fenced code block |
|
|
486
|
+
| | `horizontal-rule` | `horizontal-rule` block objects | `---` |
|
|
487
|
+
| | `html` | `html` block objects | Raw HTML |
|
|
488
|
+
| | `image` | `image` block/inline objects | `` |
|
|
489
|
+
| | `table` | `table` block objects | Markdown table |
|
|
490
|
+
| `block` | `normal` | Paragraphs | `{children}` |
|
|
491
|
+
| | `h1`–`h6` | Headings | `# `–`###### ` |
|
|
492
|
+
| | `blockquote` | Blockquotes | `> {children}` |
|
|
493
|
+
| `marks` | `strong` | Bold text | `**{children}**` |
|
|
494
|
+
| | `em` | Italic text | `_{children}_` |
|
|
495
|
+
| | `code` | Inline code | `` `{children}` `` |
|
|
496
|
+
| | `underline` | Underlined text | `<u>{children}</u>` |
|
|
497
|
+
| | `strike-through` | Strikethrough | `~~{children}~~` |
|
|
498
|
+
| | `link` | Links | `[{children}](url)` |
|
|
499
|
+
| `listItem` | | List items (bullet, number, task) | `- `, `1. `, or `- [x] ` |
|
|
500
|
+
| `hardBreak` | | Line breaks within blocks | ` \n` (two spaces) |
|
|
501
|
+
| `blockSpacing` | | Spacing between blocks | `\n\n`, `\n`, `\n>\n` |
|
|
502
|
+
| `unknownType` | | Unknown block types | JSON code block |
|
|
503
|
+
| `unknownBlockStyle` | | Unknown block styles | `{children}` |
|
|
504
|
+
| `unknownListItem` | | Unknown list item types | `- {children}` |
|
|
505
|
+
| `unknownMark` | | Unknown marks | `{children}` |
|
|
470
506
|
|
|
471
507
|
Unknown types render as JSON code blocks by default; unknown styles, list items, and marks pass through their children.
|
|
472
508
|
|
|
509
|
+
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.
|
|
510
|
+
|
|
473
511
|
> **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
512
|
|
|
475
513
|
#### Configuring renderers
|
|
476
514
|
|
|
477
515
|
Provide custom renderers to control how Portable Text renders to Markdown.
|
|
478
516
|
|
|
479
|
-
**Custom type renderers:** Render custom block types (objects in the blocks array):
|
|
517
|
+
**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
518
|
|
|
481
519
|
```ts
|
|
482
520
|
portableTextToMarkdown(blocks, {
|
|
@@ -500,31 +538,19 @@ portableTextToMarkdown(blocks, {
|
|
|
500
538
|
})
|
|
501
539
|
```
|
|
502
540
|
|
|
503
|
-
**Built-in type renderers:**
|
|
541
|
+
**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
542
|
|
|
505
543
|
```ts
|
|
506
544
|
import {
|
|
507
545
|
DefaultBlockquoteObjectRenderer,
|
|
508
|
-
DefaultCalloutRenderer,
|
|
509
|
-
DefaultCodeBlockRenderer,
|
|
510
|
-
DefaultHorizontalRuleRenderer,
|
|
511
|
-
DefaultHtmlRenderer,
|
|
512
|
-
DefaultImageRenderer,
|
|
513
546
|
DefaultListRenderer,
|
|
514
|
-
DefaultTableRenderer,
|
|
515
547
|
portableTextToMarkdown,
|
|
516
548
|
} from '@portabletext/markdown'
|
|
517
549
|
|
|
518
550
|
portableTextToMarkdown(blocks, {
|
|
519
551
|
types: {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
'code': DefaultCodeBlockRenderer,
|
|
523
|
-
'horizontal-rule': DefaultHorizontalRuleRenderer,
|
|
524
|
-
'html': DefaultHtmlRenderer,
|
|
525
|
-
'image': DefaultImageRenderer,
|
|
526
|
-
'list': DefaultListRenderer,
|
|
527
|
-
'table': DefaultTableRenderer,
|
|
552
|
+
blockquote: DefaultBlockquoteObjectRenderer,
|
|
553
|
+
list: DefaultListRenderer,
|
|
528
554
|
},
|
|
529
555
|
})
|
|
530
556
|
```
|
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
|
|
458
|
-
*
|
|
459
|
-
* row is emitted and every row goes in the body (that empty
|
|
460
|
-
* as `headerRows: 0` via `markdownToPortableText`).
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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":";;;;;;UAKU;;;;;EAKR;;;;;EAKA;;;;;;KAMG,uBAAuB;GACzB;;;;;;;;;;;;;UAaO,oBAAkB,UAAU,6BAA6B,4BAA4B,UAAU,cAAc,uBAAuB,kBAAkB,mBAAmB,wBAAwB,mBAAmB,kCAAkC;;;;;;;EAO9P;;;;;;EAMA;;;;;EAKA,UAAU;;;;;;EAMV,WAAW;;;;;EAKX,QAAQ;;;;;EAKR,WAAW;;;;EAIX;;;;;;;;;;;UAWQ,0BAA0B,UAAU,6BAA6B,4BAA4B,UAAU,cAAc,kBAAkB,mBAAmB,wBAAwB,mBAAmB,kCAAkC,KAAK,oBAAkB,GAAG,GAAG,GAAG;EAC/Q,UAAU;;;;;;KAMP;;;;;KAKA;;;;;;;UAOK;;;;GAIP;;;;;EAKD;;;;EAIA;;;;;;UAMQ;;;;EAIR;;;;EAIA;;;;EAIA;;;;;;EAMA;;;;;KCnIU,wBAAwB;EAClC,SAAS;EACT,MAAM;;;;;cAMK,6BAA6B;KCRrC,YAAY,kBAAkB,KAAK,eAAe,QACpD,KAAK,KAAK;;;;;;KAQD,qBAAqB,MAC/B,SAAS,4BAA4B;;;;;;KAQ3B,4BAA4B,qBAAqB;;;;;;KAOjD,+BACV,qBAAqB;;;;;;KAOX,yBAAyB,UAAU,sBAC7C,SAAS,gCAAgC;;;;KAM/B,yBAAyB,UAAU,sBAC7C,SAAS,gCAAgC;;;;;;;UAS1B;;;;;;;;;;;EAWf,OAAO,eAAe;;;;;;;EAQtB,OAAO,eAAe;;;;;;;;;EAUtB,OACI,YAAY,wBAAwB,yCACpC;;;;;;;;;EAUJ,UACI,YACE,0BACA,4CAEF;;;;;EAMJ;;;;;EAMA,aAAa;;;;;EAMb,aAAa,qBAAqB;;;;;EAMlC,mBAAmB,qBAAqB;;;;;EAMxC,iBAAiB,qBAAqB;;;;;;;UAQvB,4BAA4B;;;;EAI3C,OAAO;;;;EAKP;;;;EAKA;;;;;;;;EASA;;;;;EAMA;;;;EAKA;;;;;;EAOA,YAAY;;;;;;;KAQF,gCAAgC,KAAK,KAC/C,4BAA4B;;;;;;UASb,gCACf,UAAU,cAAc;;;;EAKxB,QAAQ;;;;EAKR;;;;EAKA;;;;EAKA;;;;EAKA;;;;;;EAOA,YAAY;;;;;;KAOF;GACN;EAAuB;IACzB;KAEQ,cAAc,UAAU,aAClC,SAAS,aAAa;UAGP,aAAa;EAC5B,MAAM;EACN;EACA;EACA,YAAY;;
|
|
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 = (
|
|
259
|
-
|
|
260
|
-
return
|
|
261
|
-
}
|
|
262
|
-
|
|
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 ``;
|
|
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
|
|
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
|
-
}
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
}
|
|
300
|
-
|
|
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
|
/**
|