@input/pen-markdown 0.1.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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present Input B.V.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # `@input/pen-markdown`
2
+
3
+ `@input/pen-markdown` is not a package to install alone. Install `@input/pen-interop` and import `markdownExporter` from `@input/pen-interop/markdown`, which is the host-facing markdown exporter and runs URL admission on the serialized output.
4
+
5
+ This package owns the shared markdown serializer used by that exporter and by a few other Pen packages. It does not create an editor, apply ops, or admit URLs.
6
+
7
+ ## Install
8
+
9
+ This package has no peer dependencies. Hosts should install `@input/pen-interop` instead of depending on this package directly.
10
+
11
+ ```bash
12
+ pnpm add @input/pen @input/pen-markdown
13
+ ```
14
+
15
+ `engines.node` is `>=22`.
16
+
17
+ ## Usage
18
+
19
+ ```ts
20
+ import { createEditor } from "@input/pen";
21
+ import { exportMarkdownForBlocks } from "@input/pen-markdown";
22
+
23
+ const editor = createEditor();
24
+ const markdown = exportMarkdownForBlocks(
25
+ editor,
26
+ editor.documentState.allBlocks(),
27
+ );
28
+ ```
29
+
30
+ `exportMarkdownRange(editor, range)` serializes a start/end block-id span. Omit `range`, or pass a range with no ids, to serialize every block. Hosts that need the admitted URL form should call `markdownExporter` from `@input/pen-interop/markdown` instead.
31
+
32
+ ## Options
33
+
34
+ | Option | Default | Effect |
35
+ | ---------- | ------- | ------------------------------------------ |
36
+ | `viewMode` | `"raw"` | `"resolved"` drops delete-suggestion spans |
37
+
38
+ `MarkdownExportRange.startBlockId` and `endBlockId` default to the first and last block when omitted.
39
+
40
+ ## Documentation
41
+
42
+ The docs site (the `@input/pen-docs` package) covers this area on the Import and export page (`#/import-export`).
43
+
44
+ The public signatures of record are in `api-report.md` next to this package's source in the Pen repository. The docs site does not host a generated browsable reference.
45
+
46
+ ## License
47
+
48
+ MIT © Input B.V. See [`LICENSE.md`](./LICENSE.md).
package/dist/index.cjs ADDED
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ exportMarkdownForBlocks: () => exportMarkdownForBlocks,
24
+ exportMarkdownRange: () => exportMarkdownRange
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/markdownSerialization.ts
29
+ var import_pen_core = require("@input/pen-core");
30
+
31
+ // src/listGrouper.ts
32
+ function groupListItems(lines) {
33
+ const result = [];
34
+ let index = 0;
35
+ while (index < lines.length) {
36
+ const line = lines[index];
37
+ if (isListLine(line)) {
38
+ const group = [line];
39
+ index++;
40
+ while (index < lines.length && isListLine(lines[index])) {
41
+ group.push(lines[index]);
42
+ index++;
43
+ }
44
+ result.push(group.join("\n"));
45
+ continue;
46
+ }
47
+ result.push(line);
48
+ index++;
49
+ }
50
+ return result;
51
+ }
52
+ var LIST_PREFIX = /^\s*(?:[-*+]|\d+\.)\s/;
53
+ function isListLine(line) {
54
+ return LIST_PREFIX.test(line);
55
+ }
56
+
57
+ // src/markdownSerialization.ts
58
+ var DELETE_SUGGESTION_ACTION = "delete";
59
+ function exportMarkdownRange(editor, range, config) {
60
+ return exportMarkdownForBlocks(editor, resolveBlockRange(editor, range), config);
61
+ }
62
+ function exportMarkdownForBlocks(editor, handles, config) {
63
+ const viewMode = config?.viewMode ?? "raw";
64
+ const lines = [];
65
+ for (const handle of handles) {
66
+ lines.push(serializeBlockHandleToMarkdown(handle, editor, viewMode));
67
+ }
68
+ return groupListItems(lines).join("\n\n");
69
+ }
70
+ function resolveBlockRange(editor, range) {
71
+ const blocks = listAllBlockHandles(editor);
72
+ const startBlockId = range?.startBlockId ?? null;
73
+ const endBlockId = range?.endBlockId ?? null;
74
+ if (!startBlockId && !endBlockId) {
75
+ return blocks;
76
+ }
77
+ const startIndex = startBlockId ? blocks.findIndex((block) => block.id === startBlockId) : 0;
78
+ const endIndex = endBlockId ? blocks.findIndex((block) => block.id === endBlockId) : blocks.length - 1;
79
+ if (startIndex === -1 || endIndex === -1) {
80
+ return blocks;
81
+ }
82
+ const rangeStart = Math.min(startIndex, endIndex);
83
+ const rangeEnd = Math.max(startIndex, endIndex) + 1;
84
+ return blocks.slice(rangeStart, rangeEnd);
85
+ }
86
+ function serializeBlockHandleToMarkdown(handle, editor, viewMode) {
87
+ const schema = editor.schema.resolve(handle.type);
88
+ if (!schema?.serialize?.toMarkdown) {
89
+ return readResolvedText(handle, viewMode);
90
+ }
91
+ const props = handle.type === "numberedListItem" ? {
92
+ ...handle.props,
93
+ start: (0, import_pen_core.getNumberedListItemValue)(handle) ?? 1
94
+ } : handle.props;
95
+ if (handle.type === "table") {
96
+ return renderTableMarkdown(handle, editor, viewMode);
97
+ }
98
+ const block = {
99
+ id: handle.id,
100
+ type: handle.type,
101
+ props,
102
+ content: serializeInlineContent(handle, editor, viewMode),
103
+ children: (0, import_pen_core.buildTableChildren)(handle)
104
+ };
105
+ return schema.serialize.toMarkdown(block);
106
+ }
107
+ function serializeInlineContent(handle, editor, viewMode) {
108
+ const deltas = handle.textDeltas();
109
+ if (!deltas || deltas.length === 0) {
110
+ return readResolvedText(handle, viewMode);
111
+ }
112
+ const stored = deltas.map((delta) => typeof delta.insert === "string" ? delta.insert : "").join("");
113
+ if (stored === "") {
114
+ return "";
115
+ }
116
+ let result = "";
117
+ for (const delta of deltas) {
118
+ let text = typeof delta.insert === "string" ? delta.insert : "";
119
+ if (!text) continue;
120
+ const suggestion = delta.attributes?.suggestion;
121
+ if (viewMode === "resolved" && suggestion?.action === DELETE_SUGGESTION_ACTION) {
122
+ continue;
123
+ }
124
+ if (delta.attributes) {
125
+ const ordered = (0, import_pen_core.sortDeltaAttributes)(delta.attributes, editor.schema);
126
+ for (const [mark, props] of Object.entries(ordered)) {
127
+ const inlineSchema = editor.schema.resolveInline(mark);
128
+ if (!inlineSchema?.serialize?.toMarkdown) continue;
129
+ text = inlineSchema.serialize.toMarkdown(
130
+ text,
131
+ typeof props === "object" ? props : {}
132
+ );
133
+ }
134
+ }
135
+ result += text;
136
+ }
137
+ return result;
138
+ }
139
+ function renderTableMarkdown(handle, editor, viewMode) {
140
+ const rows = readTableRows(
141
+ handle,
142
+ (cell) => serializeTableCellMarkdown(cell, editor, viewMode)
143
+ );
144
+ if (rows.length === 0) {
145
+ return "";
146
+ }
147
+ const hasHeaderRow = handle.props.hasHeaderRow !== false;
148
+ if (!hasHeaderRow) {
149
+ return renderHtmlTableFallback(rows);
150
+ }
151
+ const colCount = Math.max(...rows.map((row) => row.length), 1);
152
+ const lines = [];
153
+ const headerRow = rows[0] ?? [];
154
+ const headerCells = Array.from(
155
+ { length: colCount },
156
+ (_, index) => escapeMarkdownPipe(headerRow[index] ?? "")
157
+ );
158
+ lines.push(`| ${headerCells.join(" | ")} |`);
159
+ lines.push(`| ${Array.from({ length: colCount }, () => "---").join(" | ")} |`);
160
+ for (let rowIndex = 1; rowIndex < rows.length; rowIndex++) {
161
+ const rowCells = Array.from(
162
+ { length: colCount },
163
+ (_, index) => escapeMarkdownPipe(rows[rowIndex]?.[index] ?? "")
164
+ );
165
+ lines.push(`| ${rowCells.join(" | ")} |`);
166
+ }
167
+ return lines.join("\n");
168
+ }
169
+ function readTableRows(handle, serializeCell) {
170
+ const rows = [];
171
+ const table = handle.as("table");
172
+ const rowCount = table?.tableRowCount() ?? 0;
173
+ const colCount = table?.tableColumnCount() ?? 0;
174
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
175
+ const row = [];
176
+ for (let columnIndex = 0; columnIndex < colCount; columnIndex++) {
177
+ row.push(serializeCell(table?.tableCell(rowIndex, columnIndex) ?? null));
178
+ }
179
+ rows.push(row);
180
+ }
181
+ return rows;
182
+ }
183
+ function serializeTableCellMarkdown(cell, editor, viewMode) {
184
+ if (!cell) {
185
+ return "";
186
+ }
187
+ const deltas = [...cell.textDeltas()];
188
+ const stored = deltas.map((delta) => delta.insert).join("");
189
+ if (stored === "") {
190
+ return "";
191
+ }
192
+ let result = "";
193
+ for (const delta of deltas) {
194
+ let text = delta.insert;
195
+ if (!text) {
196
+ continue;
197
+ }
198
+ const suggestion = delta.attributes?.suggestion;
199
+ if (viewMode === "resolved" && suggestion?.action === DELETE_SUGGESTION_ACTION) {
200
+ continue;
201
+ }
202
+ if (delta.attributes) {
203
+ const ordered = (0, import_pen_core.sortDeltaAttributes)(delta.attributes, editor.schema);
204
+ for (const [mark, props] of Object.entries(ordered)) {
205
+ const inlineSchema = editor.schema.resolveInline(mark);
206
+ if (!inlineSchema?.serialize?.toMarkdown) {
207
+ continue;
208
+ }
209
+ text = inlineSchema.serialize.toMarkdown(
210
+ text,
211
+ typeof props === "object" ? props : {}
212
+ );
213
+ }
214
+ }
215
+ result += text;
216
+ }
217
+ return result;
218
+ }
219
+ function renderHtmlTableFallback(rows) {
220
+ const parts = ["<table><tbody>"];
221
+ for (const row of rows) {
222
+ parts.push("<tr>");
223
+ for (const cell of row) {
224
+ parts.push(`<td>${escapeHTML(cell)}</td>`);
225
+ }
226
+ parts.push("</tr>");
227
+ }
228
+ parts.push("</tbody></table>");
229
+ return parts.join("");
230
+ }
231
+ function escapeMarkdownPipe(text) {
232
+ return text.replaceAll("\\", "\\\\").replaceAll("|", "\\|");
233
+ }
234
+ function escapeHTML(text) {
235
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
236
+ }
237
+ function listAllBlockHandles(editor) {
238
+ return Array.from(editor.documentState.allBlocks());
239
+ }
240
+ function readResolvedText(handle, viewMode) {
241
+ return viewMode === "resolved" ? handle.textContent({ resolved: true }) : handle.textContent();
242
+ }
243
+ // Annotate the CommonJS export names for ESM import in node:
244
+ 0 && (module.exports = {
245
+ exportMarkdownForBlocks,
246
+ exportMarkdownRange
247
+ });
@@ -0,0 +1,14 @@
1
+ import { Editor, BlockHandle } from '@input/pen-types';
2
+
3
+ interface MarkdownExportRange {
4
+ startBlockId?: string | null;
5
+ endBlockId?: string | null;
6
+ }
7
+ type MarkdownExportViewMode = "resolved" | "raw";
8
+ interface MarkdownExportConfig {
9
+ viewMode?: MarkdownExportViewMode;
10
+ }
11
+ declare function exportMarkdownRange(editor: Editor, range?: MarkdownExportRange | null, config?: MarkdownExportConfig): string;
12
+ declare function exportMarkdownForBlocks(editor: Editor, handles: Iterable<BlockHandle>, config?: MarkdownExportConfig): string;
13
+
14
+ export { type MarkdownExportConfig, type MarkdownExportRange, type MarkdownExportViewMode, exportMarkdownForBlocks, exportMarkdownRange };
@@ -0,0 +1,14 @@
1
+ import { Editor, BlockHandle } from '@input/pen-types';
2
+
3
+ interface MarkdownExportRange {
4
+ startBlockId?: string | null;
5
+ endBlockId?: string | null;
6
+ }
7
+ type MarkdownExportViewMode = "resolved" | "raw";
8
+ interface MarkdownExportConfig {
9
+ viewMode?: MarkdownExportViewMode;
10
+ }
11
+ declare function exportMarkdownRange(editor: Editor, range?: MarkdownExportRange | null, config?: MarkdownExportConfig): string;
12
+ declare function exportMarkdownForBlocks(editor: Editor, handles: Iterable<BlockHandle>, config?: MarkdownExportConfig): string;
13
+
14
+ export { type MarkdownExportConfig, type MarkdownExportRange, type MarkdownExportViewMode, exportMarkdownForBlocks, exportMarkdownRange };
package/dist/index.mjs ADDED
@@ -0,0 +1,223 @@
1
+ // src/markdownSerialization.ts
2
+ import {
3
+ buildTableChildren,
4
+ getNumberedListItemValue,
5
+ sortDeltaAttributes
6
+ } from "@input/pen-core";
7
+
8
+ // src/listGrouper.ts
9
+ function groupListItems(lines) {
10
+ const result = [];
11
+ let index = 0;
12
+ while (index < lines.length) {
13
+ const line = lines[index];
14
+ if (isListLine(line)) {
15
+ const group = [line];
16
+ index++;
17
+ while (index < lines.length && isListLine(lines[index])) {
18
+ group.push(lines[index]);
19
+ index++;
20
+ }
21
+ result.push(group.join("\n"));
22
+ continue;
23
+ }
24
+ result.push(line);
25
+ index++;
26
+ }
27
+ return result;
28
+ }
29
+ var LIST_PREFIX = /^\s*(?:[-*+]|\d+\.)\s/;
30
+ function isListLine(line) {
31
+ return LIST_PREFIX.test(line);
32
+ }
33
+
34
+ // src/markdownSerialization.ts
35
+ var DELETE_SUGGESTION_ACTION = "delete";
36
+ function exportMarkdownRange(editor, range, config) {
37
+ return exportMarkdownForBlocks(editor, resolveBlockRange(editor, range), config);
38
+ }
39
+ function exportMarkdownForBlocks(editor, handles, config) {
40
+ const viewMode = config?.viewMode ?? "raw";
41
+ const lines = [];
42
+ for (const handle of handles) {
43
+ lines.push(serializeBlockHandleToMarkdown(handle, editor, viewMode));
44
+ }
45
+ return groupListItems(lines).join("\n\n");
46
+ }
47
+ function resolveBlockRange(editor, range) {
48
+ const blocks = listAllBlockHandles(editor);
49
+ const startBlockId = range?.startBlockId ?? null;
50
+ const endBlockId = range?.endBlockId ?? null;
51
+ if (!startBlockId && !endBlockId) {
52
+ return blocks;
53
+ }
54
+ const startIndex = startBlockId ? blocks.findIndex((block) => block.id === startBlockId) : 0;
55
+ const endIndex = endBlockId ? blocks.findIndex((block) => block.id === endBlockId) : blocks.length - 1;
56
+ if (startIndex === -1 || endIndex === -1) {
57
+ return blocks;
58
+ }
59
+ const rangeStart = Math.min(startIndex, endIndex);
60
+ const rangeEnd = Math.max(startIndex, endIndex) + 1;
61
+ return blocks.slice(rangeStart, rangeEnd);
62
+ }
63
+ function serializeBlockHandleToMarkdown(handle, editor, viewMode) {
64
+ const schema = editor.schema.resolve(handle.type);
65
+ if (!schema?.serialize?.toMarkdown) {
66
+ return readResolvedText(handle, viewMode);
67
+ }
68
+ const props = handle.type === "numberedListItem" ? {
69
+ ...handle.props,
70
+ start: getNumberedListItemValue(handle) ?? 1
71
+ } : handle.props;
72
+ if (handle.type === "table") {
73
+ return renderTableMarkdown(handle, editor, viewMode);
74
+ }
75
+ const block = {
76
+ id: handle.id,
77
+ type: handle.type,
78
+ props,
79
+ content: serializeInlineContent(handle, editor, viewMode),
80
+ children: buildTableChildren(handle)
81
+ };
82
+ return schema.serialize.toMarkdown(block);
83
+ }
84
+ function serializeInlineContent(handle, editor, viewMode) {
85
+ const deltas = handle.textDeltas();
86
+ if (!deltas || deltas.length === 0) {
87
+ return readResolvedText(handle, viewMode);
88
+ }
89
+ const stored = deltas.map((delta) => typeof delta.insert === "string" ? delta.insert : "").join("");
90
+ if (stored === "") {
91
+ return "";
92
+ }
93
+ let result = "";
94
+ for (const delta of deltas) {
95
+ let text = typeof delta.insert === "string" ? delta.insert : "";
96
+ if (!text) continue;
97
+ const suggestion = delta.attributes?.suggestion;
98
+ if (viewMode === "resolved" && suggestion?.action === DELETE_SUGGESTION_ACTION) {
99
+ continue;
100
+ }
101
+ if (delta.attributes) {
102
+ const ordered = sortDeltaAttributes(delta.attributes, editor.schema);
103
+ for (const [mark, props] of Object.entries(ordered)) {
104
+ const inlineSchema = editor.schema.resolveInline(mark);
105
+ if (!inlineSchema?.serialize?.toMarkdown) continue;
106
+ text = inlineSchema.serialize.toMarkdown(
107
+ text,
108
+ typeof props === "object" ? props : {}
109
+ );
110
+ }
111
+ }
112
+ result += text;
113
+ }
114
+ return result;
115
+ }
116
+ function renderTableMarkdown(handle, editor, viewMode) {
117
+ const rows = readTableRows(
118
+ handle,
119
+ (cell) => serializeTableCellMarkdown(cell, editor, viewMode)
120
+ );
121
+ if (rows.length === 0) {
122
+ return "";
123
+ }
124
+ const hasHeaderRow = handle.props.hasHeaderRow !== false;
125
+ if (!hasHeaderRow) {
126
+ return renderHtmlTableFallback(rows);
127
+ }
128
+ const colCount = Math.max(...rows.map((row) => row.length), 1);
129
+ const lines = [];
130
+ const headerRow = rows[0] ?? [];
131
+ const headerCells = Array.from(
132
+ { length: colCount },
133
+ (_, index) => escapeMarkdownPipe(headerRow[index] ?? "")
134
+ );
135
+ lines.push(`| ${headerCells.join(" | ")} |`);
136
+ lines.push(`| ${Array.from({ length: colCount }, () => "---").join(" | ")} |`);
137
+ for (let rowIndex = 1; rowIndex < rows.length; rowIndex++) {
138
+ const rowCells = Array.from(
139
+ { length: colCount },
140
+ (_, index) => escapeMarkdownPipe(rows[rowIndex]?.[index] ?? "")
141
+ );
142
+ lines.push(`| ${rowCells.join(" | ")} |`);
143
+ }
144
+ return lines.join("\n");
145
+ }
146
+ function readTableRows(handle, serializeCell) {
147
+ const rows = [];
148
+ const table = handle.as("table");
149
+ const rowCount = table?.tableRowCount() ?? 0;
150
+ const colCount = table?.tableColumnCount() ?? 0;
151
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
152
+ const row = [];
153
+ for (let columnIndex = 0; columnIndex < colCount; columnIndex++) {
154
+ row.push(serializeCell(table?.tableCell(rowIndex, columnIndex) ?? null));
155
+ }
156
+ rows.push(row);
157
+ }
158
+ return rows;
159
+ }
160
+ function serializeTableCellMarkdown(cell, editor, viewMode) {
161
+ if (!cell) {
162
+ return "";
163
+ }
164
+ const deltas = [...cell.textDeltas()];
165
+ const stored = deltas.map((delta) => delta.insert).join("");
166
+ if (stored === "") {
167
+ return "";
168
+ }
169
+ let result = "";
170
+ for (const delta of deltas) {
171
+ let text = delta.insert;
172
+ if (!text) {
173
+ continue;
174
+ }
175
+ const suggestion = delta.attributes?.suggestion;
176
+ if (viewMode === "resolved" && suggestion?.action === DELETE_SUGGESTION_ACTION) {
177
+ continue;
178
+ }
179
+ if (delta.attributes) {
180
+ const ordered = sortDeltaAttributes(delta.attributes, editor.schema);
181
+ for (const [mark, props] of Object.entries(ordered)) {
182
+ const inlineSchema = editor.schema.resolveInline(mark);
183
+ if (!inlineSchema?.serialize?.toMarkdown) {
184
+ continue;
185
+ }
186
+ text = inlineSchema.serialize.toMarkdown(
187
+ text,
188
+ typeof props === "object" ? props : {}
189
+ );
190
+ }
191
+ }
192
+ result += text;
193
+ }
194
+ return result;
195
+ }
196
+ function renderHtmlTableFallback(rows) {
197
+ const parts = ["<table><tbody>"];
198
+ for (const row of rows) {
199
+ parts.push("<tr>");
200
+ for (const cell of row) {
201
+ parts.push(`<td>${escapeHTML(cell)}</td>`);
202
+ }
203
+ parts.push("</tr>");
204
+ }
205
+ parts.push("</tbody></table>");
206
+ return parts.join("");
207
+ }
208
+ function escapeMarkdownPipe(text) {
209
+ return text.replaceAll("\\", "\\\\").replaceAll("|", "\\|");
210
+ }
211
+ function escapeHTML(text) {
212
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
213
+ }
214
+ function listAllBlockHandles(editor) {
215
+ return Array.from(editor.documentState.allBlocks());
216
+ }
217
+ function readResolvedText(handle, viewMode) {
218
+ return viewMode === "resolved" ? handle.textContent({ resolved: true }) : handle.textContent();
219
+ }
220
+ export {
221
+ exportMarkdownForBlocks,
222
+ exportMarkdownRange
223
+ };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@input/pen-markdown",
3
+ "version": "0.1.0",
4
+ "description": "Shared markdown serialization helpers for Pen",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/input-systems/pen#readme",
7
+ "bugs": {
8
+ "url": "https://github.com/input-systems/pen/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/input-systems/pen.git",
13
+ "directory": "packages/shared/markdown"
14
+ },
15
+ "type": "module",
16
+ "publishConfig": {
17
+ "access": "public",
18
+ "registry": "https://registry.npmjs.org/"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "import": {
23
+ "types": "./dist/index.d.ts",
24
+ "default": "./dist/index.mjs"
25
+ },
26
+ "require": {
27
+ "types": "./dist/index.d.cts",
28
+ "default": "./dist/index.cjs"
29
+ }
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "main": "./dist/index.cjs",
34
+ "module": "./dist/index.mjs",
35
+ "types": "./dist/index.d.ts",
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "LICENSE.md"
40
+ ],
41
+ "engines": {
42
+ "node": ">=22"
43
+ },
44
+ "sideEffects": false,
45
+ "dependencies": {
46
+ "@input/pen-types": "^0.1.0",
47
+ "@input/pen-core": "^0.1.0"
48
+ },
49
+ "devDependencies": {
50
+ "tsup": "^8.4.0",
51
+ "typescript": "^5.7.3",
52
+ "vitest": "^3.2.7"
53
+ },
54
+ "scripts": {
55
+ "build": "tsup",
56
+ "typecheck": "tsc --noEmit",
57
+ "lint": "eslint .",
58
+ "test": "vitest run",
59
+ "clean": "rm -rf dist *.tsbuildinfo"
60
+ }
61
+ }