@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.
Files changed (2) hide show
  1. package/README.md +29 -4
  2. 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
- \* Requires a schema that declares a `task` list; the default schema does not (see [GFM task lists](#configuring-matchers) below)
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": "1.5.0",
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": "^5.0.2",
32
+ "@portabletext/toolkit": "^6.0.0",
35
33
  "markdown-it": "^14.3.0",
36
- "@portabletext/schema": "^2.2.4"
34
+ "@portabletext/schema": "^3.0.0"
37
35
  },
38
36
  "devDependencies": {
39
37
  "@portabletext/types": "^4.0.2",
40
- "@sanity/pkg-utils": "^12.1.0",
38
+ "@sanity/pkg-utils": "^12.3.0",
41
39
  "@sanity/tsconfig": "^2.1.0",
42
40
  "@types/markdown-it": "^14.1.2",
43
- "typescript": "6.0.3",
41
+ "typescript": "^7.0.2",
44
42
  "vite": "^8.2.0",
45
43
  "vitest": "^4.1.10",
46
- "@portabletext/test": "^1.0.5"
44
+ "@portabletext/test": "^2.0.0"
47
45
  },
48
46
  "engines": {
49
- "node": ">=20.19 <22 || >=22.12"
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",