@portabletext/markdown 1.5.0 → 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 +29 -4
- package/package.json +7 -11
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ 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
75
|
| Code blocks | ✅ | ✅ |
|
|
76
76
|
| Horizontal rules | ✅ | ✅ |
|
|
@@ -79,10 +79,35 @@ const markdown = portableTextToMarkdown([
|
|
|
79
79
|
| HTML blocks | ✅ | ✅ |
|
|
80
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
|
|
@@ -165,7 +190,7 @@ The default schema includes the following definitions:
|
|
|
165
190
|
| Type | Values |
|
|
166
191
|
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
167
192
|
| `styles` | `'normal'`, `'h1'`, `'h2'`, `'h3'`, `'h4'`, `'h5'`, `'h6'`, `'blockquote'` |
|
|
168
|
-
| `lists` | `'number'`, `'bullet'`
|
|
193
|
+
| `lists` | `'number'`, `'bullet'`, `'task'` |
|
|
169
194
|
| `decorators` | `'strong'`, `'em'`, `'code'`, `'strike-through'` |
|
|
170
195
|
| `annotations` | `'link'` (fields: `'href'`, `'title'`) |
|
|
171
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'`) |
|
|
@@ -318,7 +343,7 @@ The matcher receives `value.items` already assembled. Each item's `content` arra
|
|
|
318
343
|
|
|
319
344
|
Without `types.list`, the existing flat-block path runs unchanged.
|
|
320
345
|
|
|
321
|
-
**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.
|
|
322
347
|
|
|
323
348
|
```ts
|
|
324
349
|
markdownToPortableText('- [x] done\n- [ ] todo', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/markdown",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Convert Portable Text to and from Markdown",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
],
|
|
23
23
|
"type": "module",
|
|
24
24
|
"sideEffects": false,
|
|
25
|
-
"main": "./dist/index.js",
|
|
26
|
-
"module": "./dist/index.js",
|
|
27
25
|
"types": "./dist/index.d.ts",
|
|
28
26
|
"exports": {
|
|
29
27
|
".": "./dist/index.js",
|
|
@@ -31,34 +29,32 @@
|
|
|
31
29
|
},
|
|
32
30
|
"dependencies": {
|
|
33
31
|
"@mdit/plugin-alert": "^0.23.2",
|
|
34
|
-
"@portabletext/toolkit": "^
|
|
32
|
+
"@portabletext/toolkit": "^6.0.0",
|
|
35
33
|
"markdown-it": "^14.3.0",
|
|
36
|
-
"@portabletext/schema": "^
|
|
34
|
+
"@portabletext/schema": "^3.0.0"
|
|
37
35
|
},
|
|
38
36
|
"devDependencies": {
|
|
39
37
|
"@portabletext/types": "^4.0.2",
|
|
40
|
-
"@sanity/pkg-utils": "^12.
|
|
38
|
+
"@sanity/pkg-utils": "^12.3.0",
|
|
41
39
|
"@sanity/tsconfig": "^2.1.0",
|
|
42
40
|
"@types/markdown-it": "^14.1.2",
|
|
43
|
-
"typescript": "
|
|
41
|
+
"typescript": "^7.0.2",
|
|
44
42
|
"vite": "^8.2.0",
|
|
45
43
|
"vitest": "^4.1.10",
|
|
46
|
-
"@portabletext/test": "^
|
|
44
|
+
"@portabletext/test": "^2.0.0"
|
|
47
45
|
},
|
|
48
46
|
"engines": {
|
|
49
|
-
"node": ">=
|
|
47
|
+
"node": ">=22.12"
|
|
50
48
|
},
|
|
51
49
|
"inlinedDependencies": {
|
|
52
50
|
"@portabletext/types": "4.0.2"
|
|
53
51
|
},
|
|
54
52
|
"scripts": {
|
|
55
53
|
"build": "pkg-utils build --strict --check",
|
|
56
|
-
"check:lint": "biome lint .",
|
|
57
54
|
"check:types": "tsc",
|
|
58
55
|
"check:types:watch": "tsc --watch",
|
|
59
56
|
"clean": "del .turbo && del dist && del node_modules",
|
|
60
57
|
"dev": "pkg-utils watch",
|
|
61
|
-
"lint:fix": "biome lint --write .",
|
|
62
58
|
"test": "vitest --run",
|
|
63
59
|
"test:unit": "vitest --run --project unit",
|
|
64
60
|
"test:unit:watch": "vitest --project unit",
|