create-markdown 0.2.0 → 0.4.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/dist/index.cjs +19 -1726
- package/dist/index.d.ts +6 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1724
- package/dist/preview.cjs +40 -0
- package/dist/preview.d.ts +8 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +2 -0
- package/dist/react.cjs +40 -0
- package/dist/react.d.ts +8 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +2 -0
- package/package.json +36 -19
- package/LICENSE +0 -21
- package/README.md +0 -253
- package/dist/core/blocks.d.ts +0 -136
- package/dist/core/blocks.d.ts.map +0 -1
- package/dist/core/document.d.ts +0 -135
- package/dist/core/document.d.ts.map +0 -1
- package/dist/core/utils.d.ts +0 -80
- package/dist/core/utils.d.ts.map +0 -1
- package/dist/parsers/inline.d.ts +0 -14
- package/dist/parsers/inline.d.ts.map +0 -1
- package/dist/parsers/markdown.d.ts +0 -19
- package/dist/parsers/markdown.d.ts.map +0 -1
- package/dist/parsers/tokenizer.d.ts +0 -38
- package/dist/parsers/tokenizer.d.ts.map +0 -1
- package/dist/react/block-renderer.d.ts +0 -70
- package/dist/react/block-renderer.d.ts.map +0 -1
- package/dist/react/hooks.d.ts +0 -142
- package/dist/react/hooks.d.ts.map +0 -1
- package/dist/react/index.cjs +0 -1813
- package/dist/react/index.d.ts +0 -11
- package/dist/react/index.d.ts.map +0 -1
- package/dist/react/index.js +0 -1781
- package/dist/serializers/markdown.d.ts +0 -30
- package/dist/serializers/markdown.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -199
- package/dist/types/index.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,23 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __reExport = (target, mod, secondTarget) => {
|
|
6
|
+
for (let key of __getOwnPropNames(mod))
|
|
7
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
8
|
+
__defProp(target, key, {
|
|
9
|
+
get: () => mod[key],
|
|
10
|
+
enumerable: true
|
|
11
|
+
});
|
|
12
|
+
if (secondTarget) {
|
|
13
|
+
for (let key of __getOwnPropNames(mod))
|
|
14
|
+
if (!__hasOwnProp.call(secondTarget, key) && key !== "default")
|
|
15
|
+
__defProp(secondTarget, key, {
|
|
16
|
+
get: () => mod[key],
|
|
17
|
+
enumerable: true
|
|
18
|
+
});
|
|
19
|
+
return secondTarget;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
5
22
|
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
23
|
var __toCommonJS = (from) => {
|
|
7
24
|
var entry = __moduleCache.get(from), desc;
|
|
@@ -29,1732 +46,8 @@ var __export = (target, all) => {
|
|
|
29
46
|
// src/index.ts
|
|
30
47
|
var exports_src = {};
|
|
31
48
|
__export(exports_src, {
|
|
32
|
-
|
|
33
|
-
updateProps: () => updateProps,
|
|
34
|
-
updateMeta: () => updateMeta,
|
|
35
|
-
updateBlock: () => updateBlock,
|
|
36
|
-
unescapeMarkdown: () => unescapeMarkdown,
|
|
37
|
-
underline: () => underline,
|
|
38
|
-
trimTrailingWhitespace: () => trimTrailingWhitespace,
|
|
39
|
-
trimBlankLines: () => trimBlankLines,
|
|
40
|
-
tokenize: () => tokenize,
|
|
41
|
-
toMarkdown: () => toMarkdown,
|
|
42
|
-
tipCallout: () => tipCallout,
|
|
43
|
-
text: () => text,
|
|
44
|
-
table: () => table,
|
|
45
|
-
swapBlocks: () => swapBlocks,
|
|
46
|
-
styled: () => styled,
|
|
47
|
-
stringify: () => stringify,
|
|
48
|
-
strikethrough: () => strikethrough,
|
|
49
|
-
spansToPlainText: () => spansToPlainText,
|
|
50
|
-
spans: () => spans,
|
|
51
|
-
setMetaField: () => setMetaField,
|
|
52
|
-
setContent: () => setContent,
|
|
53
|
-
setBlocks: () => setBlocks,
|
|
54
|
-
setBlockContent: () => setBlockContent,
|
|
55
|
-
serializeSpan: () => serializeSpan,
|
|
56
|
-
serializeInlineContent: () => serializeInlineContent,
|
|
57
|
-
serializeBlock: () => serializeBlock,
|
|
58
|
-
replaceBlock: () => replaceBlock,
|
|
59
|
-
removeBlocks: () => removeBlocks,
|
|
60
|
-
removeBlock: () => removeBlock,
|
|
61
|
-
prependContent: () => prependContent,
|
|
62
|
-
prependBlock: () => prependBlock,
|
|
63
|
-
plainSpan: () => plainSpan,
|
|
64
|
-
plainContent: () => plainContent,
|
|
65
|
-
parseInlineContent: () => parseInlineContent,
|
|
66
|
-
parse: () => parse,
|
|
67
|
-
paragraph: () => paragraph,
|
|
68
|
-
numberedList: () => numberedList,
|
|
69
|
-
noteCallout: () => noteCallout,
|
|
70
|
-
normalizeLineEndings: () => normalizeLineEndings,
|
|
71
|
-
moveBlock: () => moveBlock,
|
|
72
|
-
markdownToDocument: () => markdownToDocument,
|
|
73
|
-
markdownToBlocks: () => markdownToBlocks,
|
|
74
|
-
mapBlocks: () => mapBlocks,
|
|
75
|
-
link: () => link,
|
|
76
|
-
italic: () => italic,
|
|
77
|
-
isValidHeadingLevel: () => isValidHeadingLevel,
|
|
78
|
-
isValidBlockType: () => isValidBlockType,
|
|
79
|
-
isListToken: () => isListToken,
|
|
80
|
-
isEmpty: () => isEmpty,
|
|
81
|
-
isCodeToken: () => isCodeToken,
|
|
82
|
-
insertBlocks: () => insertBlocks,
|
|
83
|
-
insertBlock: () => insertBlock,
|
|
84
|
-
infoCallout: () => infoCallout,
|
|
85
|
-
indent: () => indent,
|
|
86
|
-
image: () => image,
|
|
87
|
-
highlight: () => highlight,
|
|
88
|
-
heading: () => heading,
|
|
89
|
-
hasContent: () => hasContent,
|
|
90
|
-
hasChildren: () => hasChildren,
|
|
91
|
-
hasBlock: () => hasBlock,
|
|
92
|
-
h6: () => h6,
|
|
93
|
-
h5: () => h5,
|
|
94
|
-
h4: () => h4,
|
|
95
|
-
h3: () => h3,
|
|
96
|
-
h2: () => h2,
|
|
97
|
-
h1: () => h1,
|
|
98
|
-
groupTokens: () => groupTokens,
|
|
99
|
-
getMetaField: () => getMetaField,
|
|
100
|
-
getLastBlock: () => getLastBlock,
|
|
101
|
-
getFirstBlock: () => getFirstBlock,
|
|
102
|
-
getBlockIndex: () => getBlockIndex,
|
|
103
|
-
getBlockCount: () => getBlockCount,
|
|
104
|
-
getBlockAt: () => getBlockAt,
|
|
105
|
-
generateId: () => generateId,
|
|
106
|
-
fromMarkdown: () => fromMarkdown,
|
|
107
|
-
findBlocksByType: () => findBlocksByType,
|
|
108
|
-
findBlock: () => findBlock,
|
|
109
|
-
filterBlocks: () => filterBlocks,
|
|
110
|
-
escapeMarkdown: () => escapeMarkdown,
|
|
111
|
-
escapeCodeBlock: () => escapeCodeBlock,
|
|
112
|
-
emptyDocument: () => emptyDocument,
|
|
113
|
-
documentToMarkdown: () => documentToMarkdown,
|
|
114
|
-
divider: () => divider,
|
|
115
|
-
deepCloneBlocks: () => deepCloneBlocks,
|
|
116
|
-
deepClone: () => deepClone,
|
|
117
|
-
dangerCallout: () => dangerCallout,
|
|
118
|
-
createDocument: () => createDocument,
|
|
119
|
-
createBlock: () => createBlock,
|
|
120
|
-
convertLineEndings: () => convertLineEndings,
|
|
121
|
-
codeBlock: () => codeBlock,
|
|
122
|
-
code: () => code,
|
|
123
|
-
cloneDocument: () => cloneDocument,
|
|
124
|
-
clearBlocks: () => clearBlocks,
|
|
125
|
-
checkListItem: () => checkListItem,
|
|
126
|
-
checkList: () => checkList,
|
|
127
|
-
callout: () => callout,
|
|
128
|
-
bulletList: () => bulletList,
|
|
129
|
-
bold: () => bold,
|
|
130
|
-
blocksToMarkdown: () => blocksToMarkdown,
|
|
131
|
-
blockquote: () => blockquote,
|
|
132
|
-
appendContent: () => appendContent,
|
|
133
|
-
appendBlockContent: () => appendBlockContent,
|
|
134
|
-
appendBlock: () => appendBlock,
|
|
135
|
-
addChildren: () => addChildren,
|
|
136
|
-
VERSION: () => VERSION,
|
|
137
|
-
DOCUMENT_VERSION: () => DOCUMENT_VERSION
|
|
49
|
+
VERSION: () => VERSION
|
|
138
50
|
});
|
|
139
51
|
module.exports = __toCommonJS(exports_src);
|
|
140
|
-
|
|
141
|
-
// src/core/utils.ts
|
|
142
|
-
var ID_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
143
|
-
var ID_LENGTH = 8;
|
|
144
|
-
function generateId(length = ID_LENGTH) {
|
|
145
|
-
let id = "";
|
|
146
|
-
const charsLength = ID_CHARS.length;
|
|
147
|
-
for (let i = 0;i < length; i++) {
|
|
148
|
-
id += ID_CHARS.charAt(Math.floor(Math.random() * charsLength));
|
|
149
|
-
}
|
|
150
|
-
return id;
|
|
151
|
-
}
|
|
152
|
-
function deepClone(block, regenerateIds = true) {
|
|
153
|
-
return {
|
|
154
|
-
id: regenerateIds ? generateId() : block.id,
|
|
155
|
-
type: block.type,
|
|
156
|
-
content: block.content.map((span) => ({
|
|
157
|
-
text: span.text,
|
|
158
|
-
styles: { ...span.styles }
|
|
159
|
-
})),
|
|
160
|
-
children: block.children.map((child) => deepClone(child, regenerateIds)),
|
|
161
|
-
props: { ...block.props }
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
function deepCloneBlocks(blocks, regenerateIds = true) {
|
|
165
|
-
return blocks.map((block) => deepClone(block, regenerateIds));
|
|
166
|
-
}
|
|
167
|
-
function normalizeLineEndings(text) {
|
|
168
|
-
return text.replace(/\r\n|\r/g, `
|
|
169
|
-
`);
|
|
170
|
-
}
|
|
171
|
-
function convertLineEndings(text, lineEnding) {
|
|
172
|
-
const normalized = normalizeLineEndings(text);
|
|
173
|
-
if (lineEnding === `\r
|
|
174
|
-
`) {
|
|
175
|
-
return normalized.replace(/\n/g, `\r
|
|
176
|
-
`);
|
|
177
|
-
}
|
|
178
|
-
return normalized;
|
|
179
|
-
}
|
|
180
|
-
var MARKDOWN_ESCAPE_CHARS = /[\\`*_{}[\]()#+\-.!|]/g;
|
|
181
|
-
function escapeMarkdown(text) {
|
|
182
|
-
return text.replace(MARKDOWN_ESCAPE_CHARS, "\\$&");
|
|
183
|
-
}
|
|
184
|
-
function unescapeMarkdown(text) {
|
|
185
|
-
return text.replace(/\\([\\`*_{}[\]()#+\-.!|])/g, "$1");
|
|
186
|
-
}
|
|
187
|
-
function escapeCodeBlock(text) {
|
|
188
|
-
return text.replace(/```/g, "\\`\\`\\`");
|
|
189
|
-
}
|
|
190
|
-
function trimTrailingWhitespace(text) {
|
|
191
|
-
return text.split(`
|
|
192
|
-
`).map((line) => line.trimEnd()).join(`
|
|
193
|
-
`);
|
|
194
|
-
}
|
|
195
|
-
function trimBlankLines(text) {
|
|
196
|
-
const lines = text.split(`
|
|
197
|
-
`);
|
|
198
|
-
let start = 0;
|
|
199
|
-
while (start < lines.length && lines[start].trim() === "") {
|
|
200
|
-
start++;
|
|
201
|
-
}
|
|
202
|
-
let end = lines.length - 1;
|
|
203
|
-
while (end >= start && lines[end].trim() === "") {
|
|
204
|
-
end--;
|
|
205
|
-
}
|
|
206
|
-
return lines.slice(start, end + 1).join(`
|
|
207
|
-
`);
|
|
208
|
-
}
|
|
209
|
-
function indent(text, spaces) {
|
|
210
|
-
const padding = " ".repeat(spaces);
|
|
211
|
-
return text.split(`
|
|
212
|
-
`).map((line) => line.trim() ? padding + line : line).join(`
|
|
213
|
-
`);
|
|
214
|
-
}
|
|
215
|
-
function spansToPlainText(spans) {
|
|
216
|
-
return spans.map((span) => span.text).join("");
|
|
217
|
-
}
|
|
218
|
-
function plainSpan(text) {
|
|
219
|
-
return { text, styles: {} };
|
|
220
|
-
}
|
|
221
|
-
function plainContent(text) {
|
|
222
|
-
return [plainSpan(text)];
|
|
223
|
-
}
|
|
224
|
-
function hasContent(block) {
|
|
225
|
-
return block.content.length > 0 && block.content.some((span) => span.text.length > 0);
|
|
226
|
-
}
|
|
227
|
-
function hasChildren(block) {
|
|
228
|
-
return block.children.length > 0;
|
|
229
|
-
}
|
|
230
|
-
function isValidHeadingLevel(level) {
|
|
231
|
-
return Number.isInteger(level) && level >= 1 && level <= 6;
|
|
232
|
-
}
|
|
233
|
-
function isValidBlockType(type) {
|
|
234
|
-
const validTypes = [
|
|
235
|
-
"paragraph",
|
|
236
|
-
"heading",
|
|
237
|
-
"bulletList",
|
|
238
|
-
"numberedList",
|
|
239
|
-
"checkList",
|
|
240
|
-
"codeBlock",
|
|
241
|
-
"blockquote",
|
|
242
|
-
"table",
|
|
243
|
-
"image",
|
|
244
|
-
"divider",
|
|
245
|
-
"callout"
|
|
246
|
-
];
|
|
247
|
-
return validTypes.includes(type);
|
|
248
|
-
}
|
|
249
|
-
// src/core/blocks.ts
|
|
250
|
-
function createBlock(type, content = [], props = {}, children = []) {
|
|
251
|
-
return {
|
|
252
|
-
id: generateId(),
|
|
253
|
-
type,
|
|
254
|
-
content,
|
|
255
|
-
children,
|
|
256
|
-
props
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
function text(content) {
|
|
260
|
-
return plainSpan(content);
|
|
261
|
-
}
|
|
262
|
-
function bold(content) {
|
|
263
|
-
return { text: content, styles: { bold: true } };
|
|
264
|
-
}
|
|
265
|
-
function italic(content) {
|
|
266
|
-
return { text: content, styles: { italic: true } };
|
|
267
|
-
}
|
|
268
|
-
function code(content) {
|
|
269
|
-
return { text: content, styles: { code: true } };
|
|
270
|
-
}
|
|
271
|
-
function strikethrough(content) {
|
|
272
|
-
return { text: content, styles: { strikethrough: true } };
|
|
273
|
-
}
|
|
274
|
-
function underline(content) {
|
|
275
|
-
return { text: content, styles: { underline: true } };
|
|
276
|
-
}
|
|
277
|
-
function highlight(content) {
|
|
278
|
-
return { text: content, styles: { highlight: true } };
|
|
279
|
-
}
|
|
280
|
-
function link(content, url, title) {
|
|
281
|
-
return {
|
|
282
|
-
text: content,
|
|
283
|
-
styles: { link: { url, title } }
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
function styled(content, styles) {
|
|
287
|
-
return { text: content, styles };
|
|
288
|
-
}
|
|
289
|
-
function spans(...textSpans) {
|
|
290
|
-
return textSpans;
|
|
291
|
-
}
|
|
292
|
-
function paragraph(content) {
|
|
293
|
-
const textContent = typeof content === "string" ? plainContent(content) : content;
|
|
294
|
-
return createBlock("paragraph", textContent, {});
|
|
295
|
-
}
|
|
296
|
-
function heading(level, content) {
|
|
297
|
-
const textContent = typeof content === "string" ? plainContent(content) : content;
|
|
298
|
-
return createBlock("heading", textContent, { level });
|
|
299
|
-
}
|
|
300
|
-
var h1 = (content) => heading(1, content);
|
|
301
|
-
var h2 = (content) => heading(2, content);
|
|
302
|
-
var h3 = (content) => heading(3, content);
|
|
303
|
-
var h4 = (content) => heading(4, content);
|
|
304
|
-
var h5 = (content) => heading(5, content);
|
|
305
|
-
var h6 = (content) => heading(6, content);
|
|
306
|
-
function bulletList(items) {
|
|
307
|
-
const children = items.map((item) => {
|
|
308
|
-
if (typeof item === "string") {
|
|
309
|
-
return paragraph(item);
|
|
310
|
-
}
|
|
311
|
-
if (Array.isArray(item)) {
|
|
312
|
-
return paragraph(item);
|
|
313
|
-
}
|
|
314
|
-
return item;
|
|
315
|
-
});
|
|
316
|
-
return createBlock("bulletList", [], {}, children);
|
|
317
|
-
}
|
|
318
|
-
function numberedList(items) {
|
|
319
|
-
const children = items.map((item) => {
|
|
320
|
-
if (typeof item === "string") {
|
|
321
|
-
return paragraph(item);
|
|
322
|
-
}
|
|
323
|
-
if (Array.isArray(item)) {
|
|
324
|
-
return paragraph(item);
|
|
325
|
-
}
|
|
326
|
-
return item;
|
|
327
|
-
});
|
|
328
|
-
return createBlock("numberedList", [], {}, children);
|
|
329
|
-
}
|
|
330
|
-
function checkListItem(content, checked = false) {
|
|
331
|
-
const textContent = typeof content === "string" ? plainContent(content) : content;
|
|
332
|
-
return createBlock("checkList", textContent, { checked });
|
|
333
|
-
}
|
|
334
|
-
function checkList(items) {
|
|
335
|
-
return items.map((item) => checkListItem(item.content, item.checked ?? false));
|
|
336
|
-
}
|
|
337
|
-
function codeBlock(code2, language) {
|
|
338
|
-
return createBlock("codeBlock", plainContent(code2), { language });
|
|
339
|
-
}
|
|
340
|
-
function blockquote(content) {
|
|
341
|
-
const textContent = typeof content === "string" ? plainContent(content) : content;
|
|
342
|
-
return createBlock("blockquote", textContent, {});
|
|
343
|
-
}
|
|
344
|
-
function divider() {
|
|
345
|
-
return createBlock("divider", [], {});
|
|
346
|
-
}
|
|
347
|
-
function image(url, alt, options) {
|
|
348
|
-
return createBlock("image", [], {
|
|
349
|
-
url,
|
|
350
|
-
alt,
|
|
351
|
-
title: options?.title,
|
|
352
|
-
width: options?.width,
|
|
353
|
-
height: options?.height
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
function callout(type, content) {
|
|
357
|
-
const textContent = typeof content === "string" ? plainContent(content) : content;
|
|
358
|
-
return createBlock("callout", textContent, { type });
|
|
359
|
-
}
|
|
360
|
-
var infoCallout = (content) => callout("info", content);
|
|
361
|
-
var warningCallout = (content) => callout("warning", content);
|
|
362
|
-
var tipCallout = (content) => callout("tip", content);
|
|
363
|
-
var dangerCallout = (content) => callout("danger", content);
|
|
364
|
-
var noteCallout = (content) => callout("note", content);
|
|
365
|
-
function table(headers, rows, alignments) {
|
|
366
|
-
return createBlock("table", [], {
|
|
367
|
-
headers,
|
|
368
|
-
rows,
|
|
369
|
-
alignments
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
function appendContent(block, ...newSpans) {
|
|
373
|
-
return {
|
|
374
|
-
...block,
|
|
375
|
-
content: [...block.content, ...newSpans]
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
function prependContent(block, ...newSpans) {
|
|
379
|
-
return {
|
|
380
|
-
...block,
|
|
381
|
-
content: [...newSpans, ...block.content]
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
function setContent(block, content) {
|
|
385
|
-
return {
|
|
386
|
-
...block,
|
|
387
|
-
content
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
|
-
function addChildren(block, ...newChildren) {
|
|
391
|
-
return {
|
|
392
|
-
...block,
|
|
393
|
-
children: [...block.children, ...newChildren]
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
function updateProps(block, props) {
|
|
397
|
-
return {
|
|
398
|
-
...block,
|
|
399
|
-
props: { ...block.props, ...props }
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
// src/core/document.ts
|
|
403
|
-
var DOCUMENT_VERSION = 1;
|
|
404
|
-
function createDocument(blocks = [], options = {}) {
|
|
405
|
-
const { meta = {} } = options;
|
|
406
|
-
return {
|
|
407
|
-
version: DOCUMENT_VERSION,
|
|
408
|
-
blocks: deepCloneBlocks(blocks, false),
|
|
409
|
-
meta: {
|
|
410
|
-
createdAt: new Date,
|
|
411
|
-
updatedAt: new Date,
|
|
412
|
-
...meta
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
function emptyDocument(options = {}) {
|
|
417
|
-
return createDocument([], options);
|
|
418
|
-
}
|
|
419
|
-
function cloneDocument(doc) {
|
|
420
|
-
return {
|
|
421
|
-
version: doc.version,
|
|
422
|
-
blocks: deepCloneBlocks(doc.blocks, true),
|
|
423
|
-
meta: {
|
|
424
|
-
...doc.meta,
|
|
425
|
-
createdAt: new Date,
|
|
426
|
-
updatedAt: new Date
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
function insertBlock(doc, block, index) {
|
|
431
|
-
const newBlocks = [...doc.blocks];
|
|
432
|
-
const insertIndex = index ?? newBlocks.length;
|
|
433
|
-
newBlocks.splice(insertIndex, 0, deepClone(block, false));
|
|
434
|
-
return {
|
|
435
|
-
...doc,
|
|
436
|
-
blocks: newBlocks,
|
|
437
|
-
meta: {
|
|
438
|
-
...doc.meta,
|
|
439
|
-
updatedAt: new Date
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
function appendBlock(doc, block) {
|
|
444
|
-
return insertBlock(doc, block);
|
|
445
|
-
}
|
|
446
|
-
function prependBlock(doc, block) {
|
|
447
|
-
return insertBlock(doc, block, 0);
|
|
448
|
-
}
|
|
449
|
-
function insertBlocks(doc, blocks, index) {
|
|
450
|
-
const newBlocks = [...doc.blocks];
|
|
451
|
-
const insertIndex = index ?? newBlocks.length;
|
|
452
|
-
newBlocks.splice(insertIndex, 0, ...deepCloneBlocks(blocks, false));
|
|
453
|
-
return {
|
|
454
|
-
...doc,
|
|
455
|
-
blocks: newBlocks,
|
|
456
|
-
meta: {
|
|
457
|
-
...doc.meta,
|
|
458
|
-
updatedAt: new Date
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
function removeBlock(doc, blockId) {
|
|
463
|
-
const newBlocks = doc.blocks.filter((block) => block.id !== blockId);
|
|
464
|
-
if (newBlocks.length === doc.blocks.length) {
|
|
465
|
-
return doc;
|
|
466
|
-
}
|
|
467
|
-
return {
|
|
468
|
-
...doc,
|
|
469
|
-
blocks: newBlocks,
|
|
470
|
-
meta: {
|
|
471
|
-
...doc.meta,
|
|
472
|
-
updatedAt: new Date
|
|
473
|
-
}
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
function removeBlocks(doc, blockIds) {
|
|
477
|
-
const idSet = new Set(blockIds);
|
|
478
|
-
const newBlocks = doc.blocks.filter((block) => !idSet.has(block.id));
|
|
479
|
-
if (newBlocks.length === doc.blocks.length) {
|
|
480
|
-
return doc;
|
|
481
|
-
}
|
|
482
|
-
return {
|
|
483
|
-
...doc,
|
|
484
|
-
blocks: newBlocks,
|
|
485
|
-
meta: {
|
|
486
|
-
...doc.meta,
|
|
487
|
-
updatedAt: new Date
|
|
488
|
-
}
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
function updateBlock(doc, blockId, updates) {
|
|
492
|
-
const blockIndex = doc.blocks.findIndex((block) => block.id === blockId);
|
|
493
|
-
if (blockIndex === -1) {
|
|
494
|
-
return doc;
|
|
495
|
-
}
|
|
496
|
-
const newBlocks = [...doc.blocks];
|
|
497
|
-
const existingBlock = newBlocks[blockIndex];
|
|
498
|
-
newBlocks[blockIndex] = {
|
|
499
|
-
...existingBlock,
|
|
500
|
-
...updates,
|
|
501
|
-
id: existingBlock.id,
|
|
502
|
-
type: existingBlock.type,
|
|
503
|
-
content: updates.content ?? existingBlock.content,
|
|
504
|
-
children: updates.children ?? existingBlock.children,
|
|
505
|
-
props: updates.props ? { ...existingBlock.props, ...updates.props } : existingBlock.props
|
|
506
|
-
};
|
|
507
|
-
return {
|
|
508
|
-
...doc,
|
|
509
|
-
blocks: newBlocks,
|
|
510
|
-
meta: {
|
|
511
|
-
...doc.meta,
|
|
512
|
-
updatedAt: new Date
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
function replaceBlock(doc, blockId, newBlock) {
|
|
517
|
-
const blockIndex = doc.blocks.findIndex((block) => block.id === blockId);
|
|
518
|
-
if (blockIndex === -1) {
|
|
519
|
-
return doc;
|
|
520
|
-
}
|
|
521
|
-
const newBlocks = [...doc.blocks];
|
|
522
|
-
newBlocks[blockIndex] = deepClone(newBlock, false);
|
|
523
|
-
return {
|
|
524
|
-
...doc,
|
|
525
|
-
blocks: newBlocks,
|
|
526
|
-
meta: {
|
|
527
|
-
...doc.meta,
|
|
528
|
-
updatedAt: new Date
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
function moveBlock(doc, blockId, newIndex) {
|
|
533
|
-
const currentIndex = doc.blocks.findIndex((block) => block.id === blockId);
|
|
534
|
-
if (currentIndex === -1) {
|
|
535
|
-
return doc;
|
|
536
|
-
}
|
|
537
|
-
const targetIndex = Math.max(0, Math.min(newIndex, doc.blocks.length - 1));
|
|
538
|
-
if (currentIndex === targetIndex) {
|
|
539
|
-
return doc;
|
|
540
|
-
}
|
|
541
|
-
const newBlocks = [...doc.blocks];
|
|
542
|
-
const [movedBlock] = newBlocks.splice(currentIndex, 1);
|
|
543
|
-
newBlocks.splice(targetIndex, 0, movedBlock);
|
|
544
|
-
return {
|
|
545
|
-
...doc,
|
|
546
|
-
blocks: newBlocks,
|
|
547
|
-
meta: {
|
|
548
|
-
...doc.meta,
|
|
549
|
-
updatedAt: new Date
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
function swapBlocks(doc, blockId1, blockId2) {
|
|
554
|
-
const index1 = doc.blocks.findIndex((block) => block.id === blockId1);
|
|
555
|
-
const index2 = doc.blocks.findIndex((block) => block.id === blockId2);
|
|
556
|
-
if (index1 === -1 || index2 === -1 || index1 === index2) {
|
|
557
|
-
return doc;
|
|
558
|
-
}
|
|
559
|
-
const newBlocks = [...doc.blocks];
|
|
560
|
-
[newBlocks[index1], newBlocks[index2]] = [newBlocks[index2], newBlocks[index1]];
|
|
561
|
-
return {
|
|
562
|
-
...doc,
|
|
563
|
-
blocks: newBlocks,
|
|
564
|
-
meta: {
|
|
565
|
-
...doc.meta,
|
|
566
|
-
updatedAt: new Date
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
function findBlock(doc, blockId) {
|
|
571
|
-
return doc.blocks.find((block) => block.id === blockId);
|
|
572
|
-
}
|
|
573
|
-
function getBlockIndex(doc, blockId) {
|
|
574
|
-
return doc.blocks.findIndex((block) => block.id === blockId);
|
|
575
|
-
}
|
|
576
|
-
function getBlockAt(doc, index) {
|
|
577
|
-
return doc.blocks[index];
|
|
578
|
-
}
|
|
579
|
-
function getFirstBlock(doc) {
|
|
580
|
-
return doc.blocks[0];
|
|
581
|
-
}
|
|
582
|
-
function getLastBlock(doc) {
|
|
583
|
-
return doc.blocks[doc.blocks.length - 1];
|
|
584
|
-
}
|
|
585
|
-
function findBlocksByType(doc, type) {
|
|
586
|
-
return doc.blocks.filter((block) => block.type === type);
|
|
587
|
-
}
|
|
588
|
-
function hasBlock(doc, blockId) {
|
|
589
|
-
return doc.blocks.some((block) => block.id === blockId);
|
|
590
|
-
}
|
|
591
|
-
function getBlockCount(doc) {
|
|
592
|
-
return doc.blocks.length;
|
|
593
|
-
}
|
|
594
|
-
function isEmpty(doc) {
|
|
595
|
-
return doc.blocks.length === 0;
|
|
596
|
-
}
|
|
597
|
-
function setBlockContent(doc, blockId, content) {
|
|
598
|
-
return updateBlock(doc, blockId, { content });
|
|
599
|
-
}
|
|
600
|
-
function appendBlockContent(doc, blockId, content) {
|
|
601
|
-
const block = findBlock(doc, blockId);
|
|
602
|
-
if (!block)
|
|
603
|
-
return doc;
|
|
604
|
-
return updateBlock(doc, blockId, {
|
|
605
|
-
content: [...block.content, ...content]
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
function updateMeta(doc, meta) {
|
|
609
|
-
return {
|
|
610
|
-
...doc,
|
|
611
|
-
meta: {
|
|
612
|
-
...doc.meta,
|
|
613
|
-
...meta,
|
|
614
|
-
updatedAt: new Date
|
|
615
|
-
}
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
function setMetaField(doc, key, value) {
|
|
619
|
-
return updateMeta(doc, { [key]: value });
|
|
620
|
-
}
|
|
621
|
-
function getMetaField(doc, key) {
|
|
622
|
-
return doc.meta[key];
|
|
623
|
-
}
|
|
624
|
-
function clearBlocks(doc) {
|
|
625
|
-
return {
|
|
626
|
-
...doc,
|
|
627
|
-
blocks: [],
|
|
628
|
-
meta: {
|
|
629
|
-
...doc.meta,
|
|
630
|
-
updatedAt: new Date
|
|
631
|
-
}
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
function setBlocks(doc, blocks) {
|
|
635
|
-
return {
|
|
636
|
-
...doc,
|
|
637
|
-
blocks: deepCloneBlocks(blocks, false),
|
|
638
|
-
meta: {
|
|
639
|
-
...doc.meta,
|
|
640
|
-
updatedAt: new Date
|
|
641
|
-
}
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
function filterBlocks(doc, predicate) {
|
|
645
|
-
const newBlocks = doc.blocks.filter(predicate);
|
|
646
|
-
if (newBlocks.length === doc.blocks.length) {
|
|
647
|
-
return doc;
|
|
648
|
-
}
|
|
649
|
-
return {
|
|
650
|
-
...doc,
|
|
651
|
-
blocks: newBlocks,
|
|
652
|
-
meta: {
|
|
653
|
-
...doc.meta,
|
|
654
|
-
updatedAt: new Date
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
function mapBlocks(doc, transform) {
|
|
659
|
-
return {
|
|
660
|
-
...doc,
|
|
661
|
-
blocks: doc.blocks.map(transform),
|
|
662
|
-
meta: {
|
|
663
|
-
...doc.meta,
|
|
664
|
-
updatedAt: new Date
|
|
665
|
-
}
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
// src/serializers/markdown.ts
|
|
669
|
-
var DEFAULT_OPTIONS = {
|
|
670
|
-
lineEnding: `
|
|
671
|
-
`,
|
|
672
|
-
listIndent: 2,
|
|
673
|
-
headingStyle: "atx",
|
|
674
|
-
codeBlockStyle: "fenced",
|
|
675
|
-
bulletChar: "-",
|
|
676
|
-
emphasisChar: "*"
|
|
677
|
-
};
|
|
678
|
-
function blocksToMarkdown(blocks, options = {}) {
|
|
679
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
680
|
-
const serializedBlocks = blocks.map((block, index) => serializeBlock(block, 0, opts, index, blocks));
|
|
681
|
-
return serializedBlocks.filter((s) => s !== null).join(opts.lineEnding + opts.lineEnding);
|
|
682
|
-
}
|
|
683
|
-
function documentToMarkdown(doc, options = {}) {
|
|
684
|
-
return blocksToMarkdown(doc.blocks, options);
|
|
685
|
-
}
|
|
686
|
-
function serializeBlock(block, depth, options, index = 0, siblings = []) {
|
|
687
|
-
switch (block.type) {
|
|
688
|
-
case "paragraph":
|
|
689
|
-
return serializeParagraph(block, options);
|
|
690
|
-
case "heading":
|
|
691
|
-
return serializeHeading(block, options);
|
|
692
|
-
case "bulletList":
|
|
693
|
-
return serializeBulletList(block, depth, options);
|
|
694
|
-
case "numberedList":
|
|
695
|
-
return serializeNumberedList(block, depth, options, index, siblings);
|
|
696
|
-
case "checkList":
|
|
697
|
-
return serializeCheckList(block, depth, options);
|
|
698
|
-
case "codeBlock":
|
|
699
|
-
return serializeCodeBlock(block, options);
|
|
700
|
-
case "blockquote":
|
|
701
|
-
return serializeBlockquote(block, options);
|
|
702
|
-
case "table":
|
|
703
|
-
return serializeTable(block, options);
|
|
704
|
-
case "image":
|
|
705
|
-
return serializeImage(block);
|
|
706
|
-
case "divider":
|
|
707
|
-
return "---";
|
|
708
|
-
case "callout":
|
|
709
|
-
return serializeCallout(block, options);
|
|
710
|
-
default:
|
|
711
|
-
return serializeInlineContent(block.content, options);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
function serializeParagraph(block, options) {
|
|
715
|
-
return serializeInlineContent(block.content, options);
|
|
716
|
-
}
|
|
717
|
-
function serializeHeading(block, options) {
|
|
718
|
-
const level = block.props.level;
|
|
719
|
-
const content = serializeInlineContent(block.content, options);
|
|
720
|
-
if (options.headingStyle === "setext" && (level === 1 || level === 2)) {
|
|
721
|
-
const underline2 = level === 1 ? "=" : "-";
|
|
722
|
-
return `${content}${options.lineEnding}${underline2.repeat(content.length)}`;
|
|
723
|
-
}
|
|
724
|
-
return `${"#".repeat(level)} ${content}`;
|
|
725
|
-
}
|
|
726
|
-
function serializeBulletList(block, depth, options) {
|
|
727
|
-
const indent2 = " ".repeat(depth * options.listIndent);
|
|
728
|
-
const bullet = options.bulletChar;
|
|
729
|
-
return block.children.map((child) => {
|
|
730
|
-
const content = serializeListItemContent(child, depth, options);
|
|
731
|
-
return `${indent2}${bullet} ${content}`;
|
|
732
|
-
}).join(options.lineEnding);
|
|
733
|
-
}
|
|
734
|
-
function serializeNumberedList(block, depth, options, _blockIndex = 0, _siblings = []) {
|
|
735
|
-
const indent2 = " ".repeat(depth * options.listIndent);
|
|
736
|
-
return block.children.map((child, index) => {
|
|
737
|
-
const content = serializeListItemContent(child, depth, options);
|
|
738
|
-
return `${indent2}${index + 1}. ${content}`;
|
|
739
|
-
}).join(options.lineEnding);
|
|
740
|
-
}
|
|
741
|
-
function serializeCheckList(block, depth, options) {
|
|
742
|
-
const indent2 = " ".repeat(depth * options.listIndent);
|
|
743
|
-
const checked = block.props.checked ? "x" : " ";
|
|
744
|
-
const content = serializeInlineContent(block.content, options);
|
|
745
|
-
return `${indent2}- [${checked}] ${content}`;
|
|
746
|
-
}
|
|
747
|
-
function serializeListItemContent(item, depth, options) {
|
|
748
|
-
if (item.children.length > 0) {
|
|
749
|
-
const content = serializeInlineContent(item.content, options);
|
|
750
|
-
const nestedContent = item.children.map((child, index) => serializeBlock(child, depth + 1, options, index, item.children)).join(options.lineEnding);
|
|
751
|
-
return `${content}${options.lineEnding}${nestedContent}`;
|
|
752
|
-
}
|
|
753
|
-
return serializeInlineContent(item.content, options);
|
|
754
|
-
}
|
|
755
|
-
function serializeCodeBlock(block, options) {
|
|
756
|
-
const code2 = spansToPlainText(block.content);
|
|
757
|
-
const language = block.props.language ?? "";
|
|
758
|
-
if (options.codeBlockStyle === "indented") {
|
|
759
|
-
return code2.split(`
|
|
760
|
-
`).map((line) => ` ${line}`).join(options.lineEnding);
|
|
761
|
-
}
|
|
762
|
-
return `\`\`\`${language}${options.lineEnding}${code2}${options.lineEnding}\`\`\``;
|
|
763
|
-
}
|
|
764
|
-
function serializeBlockquote(block, options) {
|
|
765
|
-
const content = serializeInlineContent(block.content, options);
|
|
766
|
-
return content.split(`
|
|
767
|
-
`).map((line) => `> ${line}`).join(options.lineEnding);
|
|
768
|
-
}
|
|
769
|
-
function serializeImage(block) {
|
|
770
|
-
const alt = block.props.alt ?? "";
|
|
771
|
-
const url = block.props.url ?? "";
|
|
772
|
-
const title = block.props.title;
|
|
773
|
-
if (title) {
|
|
774
|
-
return ``;
|
|
775
|
-
}
|
|
776
|
-
return ``;
|
|
777
|
-
}
|
|
778
|
-
function serializeTable(block, options) {
|
|
779
|
-
const { headers, rows, alignments } = block.props;
|
|
780
|
-
const lineEnding = options.lineEnding;
|
|
781
|
-
const columnWidths = headers.map((header, i) => {
|
|
782
|
-
const rowWidths = rows.map((row) => (row[i] ?? "").length);
|
|
783
|
-
return Math.max(header.length, ...rowWidths, 3);
|
|
784
|
-
});
|
|
785
|
-
const headerRow = headers.map((header, i) => header.padEnd(columnWidths[i])).join(" | ");
|
|
786
|
-
const separatorRow = headers.map((_, i) => {
|
|
787
|
-
const width = columnWidths[i];
|
|
788
|
-
const alignment = alignments?.[i] ?? null;
|
|
789
|
-
if (alignment === "left")
|
|
790
|
-
return `:${"-".repeat(width - 1)}`;
|
|
791
|
-
if (alignment === "right")
|
|
792
|
-
return `${"-".repeat(width - 1)}:`;
|
|
793
|
-
if (alignment === "center")
|
|
794
|
-
return `:${"-".repeat(width - 2)}:`;
|
|
795
|
-
return "-".repeat(width);
|
|
796
|
-
}).join(" | ");
|
|
797
|
-
const dataRows = rows.map((row) => row.map((cell, i) => (cell ?? "").padEnd(columnWidths[i])).join(" | "));
|
|
798
|
-
return [
|
|
799
|
-
`| ${headerRow} |`,
|
|
800
|
-
`| ${separatorRow} |`,
|
|
801
|
-
...dataRows.map((row) => `| ${row} |`)
|
|
802
|
-
].join(lineEnding);
|
|
803
|
-
}
|
|
804
|
-
function serializeCallout(block, options) {
|
|
805
|
-
const type = block.props.type.toUpperCase();
|
|
806
|
-
const content = serializeInlineContent(block.content, options);
|
|
807
|
-
const lineEnding = options.lineEnding;
|
|
808
|
-
return `> [!${type}]${lineEnding}> ${content.split(`
|
|
809
|
-
`).join(`${lineEnding}> `)}`;
|
|
810
|
-
}
|
|
811
|
-
function serializeInlineContent(spans2, options) {
|
|
812
|
-
return spans2.map((span) => serializeSpan(span, options)).join("");
|
|
813
|
-
}
|
|
814
|
-
function serializeSpan(span, options) {
|
|
815
|
-
let text2 = span.text;
|
|
816
|
-
const styles = span.styles;
|
|
817
|
-
if (!hasStyles(styles)) {
|
|
818
|
-
return text2;
|
|
819
|
-
}
|
|
820
|
-
if (styles.code) {
|
|
821
|
-
text2 = `\`${text2}\``;
|
|
822
|
-
}
|
|
823
|
-
if (styles.highlight) {
|
|
824
|
-
text2 = `==${text2}==`;
|
|
825
|
-
}
|
|
826
|
-
if (styles.strikethrough) {
|
|
827
|
-
text2 = `~~${text2}~~`;
|
|
828
|
-
}
|
|
829
|
-
if (styles.bold && styles.italic) {
|
|
830
|
-
const char = options.emphasisChar;
|
|
831
|
-
text2 = `${char}${char}${char}${text2}${char}${char}${char}`;
|
|
832
|
-
} else {
|
|
833
|
-
if (styles.italic) {
|
|
834
|
-
const char = options.emphasisChar;
|
|
835
|
-
text2 = `${char}${text2}${char}`;
|
|
836
|
-
}
|
|
837
|
-
if (styles.bold) {
|
|
838
|
-
const char = options.emphasisChar;
|
|
839
|
-
text2 = `${char}${char}${text2}${char}${char}`;
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
if (styles.underline) {
|
|
843
|
-
text2 = `<u>${text2}</u>`;
|
|
844
|
-
}
|
|
845
|
-
if (styles.link) {
|
|
846
|
-
const { url, title } = styles.link;
|
|
847
|
-
if (title) {
|
|
848
|
-
text2 = `[${text2}](${url} "${title}")`;
|
|
849
|
-
} else {
|
|
850
|
-
text2 = `[${text2}](${url})`;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
return text2;
|
|
854
|
-
}
|
|
855
|
-
function hasStyles(styles) {
|
|
856
|
-
return !!(styles.bold || styles.italic || styles.underline || styles.strikethrough || styles.code || styles.highlight || styles.link);
|
|
857
|
-
}
|
|
858
|
-
function stringify(blocks, options) {
|
|
859
|
-
return blocksToMarkdown(blocks, options);
|
|
860
|
-
}
|
|
861
|
-
// src/parsers/tokenizer.ts
|
|
862
|
-
var PATTERNS = {
|
|
863
|
-
heading: /^(#{1,6})\s+(.*)$/,
|
|
864
|
-
setextH1: /^=+\s*$/,
|
|
865
|
-
setextH2: /^-+\s*$/,
|
|
866
|
-
bulletList: /^(\s*)([-*+])\s+(.*)$/,
|
|
867
|
-
numberedList: /^(\s*)(\d+)\.\s+(.*)$/,
|
|
868
|
-
checkList: /^(\s*)[-*+]\s+\[([ xX])\]\s+(.*)$/,
|
|
869
|
-
codeFence: /^(\s*)(`{3,}|~{3,})(\w*)?\s*$/,
|
|
870
|
-
blockquote: /^>\s?(.*)$/,
|
|
871
|
-
callout: /^>\s*\[!(\w+)\]\s*$/,
|
|
872
|
-
divider: /^(\s*)(-{3,}|\*{3,}|_{3,})\s*$/,
|
|
873
|
-
tableRow: /^\|(.+)\|$/,
|
|
874
|
-
tableSeparator: /^\|[\s\-:|]+\|$/,
|
|
875
|
-
image: /^!\[([^\]]*)\]\(([^)]+)\)$/,
|
|
876
|
-
blank: /^\s*$/
|
|
877
|
-
};
|
|
878
|
-
function tokenize(markdown) {
|
|
879
|
-
const lines = markdown.split(/\r?\n/);
|
|
880
|
-
const tokens = [];
|
|
881
|
-
const state = {
|
|
882
|
-
inCodeBlock: false,
|
|
883
|
-
codeBlockFence: "",
|
|
884
|
-
lineNumber: 0
|
|
885
|
-
};
|
|
886
|
-
for (let i = 0;i < lines.length; i++) {
|
|
887
|
-
state.lineNumber = i + 1;
|
|
888
|
-
const line = lines[i];
|
|
889
|
-
const token = tokenizeLine(line, state, lines, i);
|
|
890
|
-
if (token) {
|
|
891
|
-
tokens.push(token);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
return tokens;
|
|
895
|
-
}
|
|
896
|
-
function tokenizeLine(line, state, allLines, lineIndex) {
|
|
897
|
-
const lineNumber = state.lineNumber;
|
|
898
|
-
if (state.inCodeBlock) {
|
|
899
|
-
const fenceMatch = line.match(PATTERNS.codeFence);
|
|
900
|
-
if (fenceMatch && line.trim().startsWith(state.codeBlockFence.charAt(0))) {
|
|
901
|
-
state.inCodeBlock = false;
|
|
902
|
-
state.codeBlockFence = "";
|
|
903
|
-
return {
|
|
904
|
-
type: "code_fence_end",
|
|
905
|
-
raw: line,
|
|
906
|
-
content: "",
|
|
907
|
-
indent: 0,
|
|
908
|
-
line: lineNumber
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
return {
|
|
912
|
-
type: "code_content",
|
|
913
|
-
raw: line,
|
|
914
|
-
content: line,
|
|
915
|
-
indent: 0,
|
|
916
|
-
line: lineNumber
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
const codeFenceMatch = line.match(PATTERNS.codeFence);
|
|
920
|
-
if (codeFenceMatch) {
|
|
921
|
-
state.inCodeBlock = true;
|
|
922
|
-
state.codeBlockFence = codeFenceMatch[2];
|
|
923
|
-
const language = codeFenceMatch[3] || "";
|
|
924
|
-
return {
|
|
925
|
-
type: "code_fence_start",
|
|
926
|
-
raw: line,
|
|
927
|
-
content: "",
|
|
928
|
-
indent: (codeFenceMatch[1] || "").length,
|
|
929
|
-
line: lineNumber,
|
|
930
|
-
meta: { language }
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
if (PATTERNS.blank.test(line)) {
|
|
934
|
-
return {
|
|
935
|
-
type: "blank",
|
|
936
|
-
raw: line,
|
|
937
|
-
content: "",
|
|
938
|
-
indent: 0,
|
|
939
|
-
line: lineNumber
|
|
940
|
-
};
|
|
941
|
-
}
|
|
942
|
-
const dividerMatch = line.match(PATTERNS.divider);
|
|
943
|
-
if (dividerMatch) {
|
|
944
|
-
const prevLine = lineIndex > 0 ? allLines[lineIndex - 1] : "";
|
|
945
|
-
if (prevLine.trim() && !PATTERNS.blank.test(prevLine)) {
|
|
946
|
-
if (PATTERNS.setextH2.test(line)) {}
|
|
947
|
-
} else {
|
|
948
|
-
return {
|
|
949
|
-
type: "divider",
|
|
950
|
-
raw: line,
|
|
951
|
-
content: "",
|
|
952
|
-
indent: (dividerMatch[1] || "").length,
|
|
953
|
-
line: lineNumber
|
|
954
|
-
};
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
const headingMatch = line.match(PATTERNS.heading);
|
|
958
|
-
if (headingMatch) {
|
|
959
|
-
return {
|
|
960
|
-
type: "heading",
|
|
961
|
-
raw: line,
|
|
962
|
-
content: headingMatch[2].trim(),
|
|
963
|
-
indent: 0,
|
|
964
|
-
line: lineNumber,
|
|
965
|
-
meta: { level: headingMatch[1].length }
|
|
966
|
-
};
|
|
967
|
-
}
|
|
968
|
-
const calloutMatch = line.match(PATTERNS.callout);
|
|
969
|
-
if (calloutMatch) {
|
|
970
|
-
return {
|
|
971
|
-
type: "callout",
|
|
972
|
-
raw: line,
|
|
973
|
-
content: "",
|
|
974
|
-
indent: 0,
|
|
975
|
-
line: lineNumber,
|
|
976
|
-
meta: { calloutType: calloutMatch[1].toLowerCase() }
|
|
977
|
-
};
|
|
978
|
-
}
|
|
979
|
-
const blockquoteMatch = line.match(PATTERNS.blockquote);
|
|
980
|
-
if (blockquoteMatch) {
|
|
981
|
-
return {
|
|
982
|
-
type: "blockquote",
|
|
983
|
-
raw: line,
|
|
984
|
-
content: blockquoteMatch[1],
|
|
985
|
-
indent: 0,
|
|
986
|
-
line: lineNumber
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
const checkListMatch = line.match(PATTERNS.checkList);
|
|
990
|
-
if (checkListMatch) {
|
|
991
|
-
const checked = checkListMatch[2].toLowerCase() === "x";
|
|
992
|
-
return {
|
|
993
|
-
type: "check_list_item",
|
|
994
|
-
raw: line,
|
|
995
|
-
content: checkListMatch[3],
|
|
996
|
-
indent: checkListMatch[1].length,
|
|
997
|
-
line: lineNumber,
|
|
998
|
-
meta: { checked }
|
|
999
|
-
};
|
|
1000
|
-
}
|
|
1001
|
-
const bulletMatch = line.match(PATTERNS.bulletList);
|
|
1002
|
-
if (bulletMatch) {
|
|
1003
|
-
return {
|
|
1004
|
-
type: "bullet_list_item",
|
|
1005
|
-
raw: line,
|
|
1006
|
-
content: bulletMatch[3],
|
|
1007
|
-
indent: bulletMatch[1].length,
|
|
1008
|
-
line: lineNumber,
|
|
1009
|
-
meta: { listMarker: bulletMatch[2] }
|
|
1010
|
-
};
|
|
1011
|
-
}
|
|
1012
|
-
const numberedMatch = line.match(PATTERNS.numberedList);
|
|
1013
|
-
if (numberedMatch) {
|
|
1014
|
-
return {
|
|
1015
|
-
type: "numbered_list_item",
|
|
1016
|
-
raw: line,
|
|
1017
|
-
content: numberedMatch[3],
|
|
1018
|
-
indent: numberedMatch[1].length,
|
|
1019
|
-
line: lineNumber,
|
|
1020
|
-
meta: { listIndex: parseInt(numberedMatch[2], 10) }
|
|
1021
|
-
};
|
|
1022
|
-
}
|
|
1023
|
-
if (PATTERNS.tableSeparator.test(line)) {
|
|
1024
|
-
return {
|
|
1025
|
-
type: "table_separator",
|
|
1026
|
-
raw: line,
|
|
1027
|
-
content: line,
|
|
1028
|
-
indent: 0,
|
|
1029
|
-
line: lineNumber
|
|
1030
|
-
};
|
|
1031
|
-
}
|
|
1032
|
-
const tableRowMatch = line.match(PATTERNS.tableRow);
|
|
1033
|
-
if (tableRowMatch) {
|
|
1034
|
-
return {
|
|
1035
|
-
type: "table_row",
|
|
1036
|
-
raw: line,
|
|
1037
|
-
content: tableRowMatch[1],
|
|
1038
|
-
indent: 0,
|
|
1039
|
-
line: lineNumber
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
const imageMatch = line.match(PATTERNS.image);
|
|
1043
|
-
if (imageMatch) {
|
|
1044
|
-
return {
|
|
1045
|
-
type: "image",
|
|
1046
|
-
raw: line,
|
|
1047
|
-
content: imageMatch[2],
|
|
1048
|
-
indent: 0,
|
|
1049
|
-
line: lineNumber,
|
|
1050
|
-
meta: { language: imageMatch[1] }
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
1053
|
-
if (PATTERNS.setextH1.test(line) || PATTERNS.setextH2.test(line)) {
|
|
1054
|
-
const prevLine = lineIndex > 0 ? allLines[lineIndex - 1] : "";
|
|
1055
|
-
if (prevLine.trim() && !PATTERNS.blank.test(prevLine)) {
|
|
1056
|
-
return {
|
|
1057
|
-
type: "heading",
|
|
1058
|
-
raw: line,
|
|
1059
|
-
content: prevLine.trim(),
|
|
1060
|
-
indent: 0,
|
|
1061
|
-
line: lineNumber,
|
|
1062
|
-
meta: { level: PATTERNS.setextH1.test(line) ? 1 : 2 }
|
|
1063
|
-
};
|
|
1064
|
-
}
|
|
1065
|
-
return {
|
|
1066
|
-
type: "divider",
|
|
1067
|
-
raw: line,
|
|
1068
|
-
content: "",
|
|
1069
|
-
indent: 0,
|
|
1070
|
-
line: lineNumber
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
return {
|
|
1074
|
-
type: "paragraph",
|
|
1075
|
-
raw: line,
|
|
1076
|
-
content: line.trim(),
|
|
1077
|
-
indent: line.length - line.trimStart().length,
|
|
1078
|
-
line: lineNumber
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
function groupTokens(tokens) {
|
|
1082
|
-
const groups = [];
|
|
1083
|
-
let currentGroup = [];
|
|
1084
|
-
let lastType = null;
|
|
1085
|
-
for (const token of tokens) {
|
|
1086
|
-
if (token.type === "blank") {
|
|
1087
|
-
if (currentGroup.length > 0) {
|
|
1088
|
-
groups.push(currentGroup);
|
|
1089
|
-
currentGroup = [];
|
|
1090
|
-
}
|
|
1091
|
-
lastType = null;
|
|
1092
|
-
continue;
|
|
1093
|
-
}
|
|
1094
|
-
if (lastType === token.type) {
|
|
1095
|
-
currentGroup.push(token);
|
|
1096
|
-
} else {
|
|
1097
|
-
if (currentGroup.length > 0) {
|
|
1098
|
-
groups.push(currentGroup);
|
|
1099
|
-
}
|
|
1100
|
-
currentGroup = [token];
|
|
1101
|
-
lastType = token.type;
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
if (currentGroup.length > 0) {
|
|
1105
|
-
groups.push(currentGroup);
|
|
1106
|
-
}
|
|
1107
|
-
return groups;
|
|
1108
|
-
}
|
|
1109
|
-
function isListToken(token) {
|
|
1110
|
-
return token.type === "bullet_list_item" || token.type === "numbered_list_item" || token.type === "check_list_item";
|
|
1111
|
-
}
|
|
1112
|
-
function isCodeToken(token) {
|
|
1113
|
-
return token.type === "code_fence_start" || token.type === "code_fence_end" || token.type === "code_content";
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
// src/parsers/inline.ts
|
|
1117
|
-
function parseInlineContent(text2) {
|
|
1118
|
-
if (!text2) {
|
|
1119
|
-
return [];
|
|
1120
|
-
}
|
|
1121
|
-
const tokens = tokenizeInline(text2);
|
|
1122
|
-
return tokensToSpans(tokens);
|
|
1123
|
-
}
|
|
1124
|
-
function tokenizeInline(text2) {
|
|
1125
|
-
const tokens = [];
|
|
1126
|
-
let remaining = text2;
|
|
1127
|
-
let pos = 0;
|
|
1128
|
-
while (pos < remaining.length) {
|
|
1129
|
-
const matched = tryMatchInline(remaining, pos);
|
|
1130
|
-
if (matched) {
|
|
1131
|
-
if (matched.startIndex > pos) {
|
|
1132
|
-
tokens.push({
|
|
1133
|
-
type: "text",
|
|
1134
|
-
content: remaining.slice(pos, matched.startIndex)
|
|
1135
|
-
});
|
|
1136
|
-
}
|
|
1137
|
-
tokens.push(matched.token);
|
|
1138
|
-
pos = matched.endIndex;
|
|
1139
|
-
} else {
|
|
1140
|
-
pos++;
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
return parseInlineTokens(text2);
|
|
1144
|
-
}
|
|
1145
|
-
function parseInlineTokens(text2) {
|
|
1146
|
-
const tokens = [];
|
|
1147
|
-
let i = 0;
|
|
1148
|
-
let textBuffer = "";
|
|
1149
|
-
const flushText = () => {
|
|
1150
|
-
if (textBuffer) {
|
|
1151
|
-
tokens.push({ type: "text", content: textBuffer });
|
|
1152
|
-
textBuffer = "";
|
|
1153
|
-
}
|
|
1154
|
-
};
|
|
1155
|
-
while (i < text2.length) {
|
|
1156
|
-
if (text2[i] === "\\" && i + 1 < text2.length) {
|
|
1157
|
-
textBuffer += text2[i + 1];
|
|
1158
|
-
i += 2;
|
|
1159
|
-
continue;
|
|
1160
|
-
}
|
|
1161
|
-
if (text2[i] === "`") {
|
|
1162
|
-
const match = matchCode(text2, i);
|
|
1163
|
-
if (match) {
|
|
1164
|
-
flushText();
|
|
1165
|
-
tokens.push(match.token);
|
|
1166
|
-
i = match.end;
|
|
1167
|
-
continue;
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
if (text2[i] === "[" || text2[i] === "!" && text2[i + 1] === "[") {
|
|
1171
|
-
const isImage = text2[i] === "!";
|
|
1172
|
-
const match = matchLink(text2, isImage ? i + 1 : i, isImage);
|
|
1173
|
-
if (match) {
|
|
1174
|
-
flushText();
|
|
1175
|
-
tokens.push(match.token);
|
|
1176
|
-
i = match.end;
|
|
1177
|
-
continue;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
if (text2[i] === "*" || text2[i] === "_") {
|
|
1181
|
-
const match = matchEmphasis(text2, i);
|
|
1182
|
-
if (match) {
|
|
1183
|
-
flushText();
|
|
1184
|
-
tokens.push(match.token);
|
|
1185
|
-
i = match.end;
|
|
1186
|
-
continue;
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
if (text2[i] === "~" && text2[i + 1] === "~") {
|
|
1190
|
-
const match = matchStrikethrough(text2, i);
|
|
1191
|
-
if (match) {
|
|
1192
|
-
flushText();
|
|
1193
|
-
tokens.push(match.token);
|
|
1194
|
-
i = match.end;
|
|
1195
|
-
continue;
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
if (text2[i] === "=" && text2[i + 1] === "=") {
|
|
1199
|
-
const match = matchHighlight(text2, i);
|
|
1200
|
-
if (match) {
|
|
1201
|
-
flushText();
|
|
1202
|
-
tokens.push(match.token);
|
|
1203
|
-
i = match.end;
|
|
1204
|
-
continue;
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
textBuffer += text2[i];
|
|
1208
|
-
i++;
|
|
1209
|
-
}
|
|
1210
|
-
flushText();
|
|
1211
|
-
return tokens;
|
|
1212
|
-
}
|
|
1213
|
-
function matchCode(text2, start) {
|
|
1214
|
-
let backticks = 0;
|
|
1215
|
-
let i = start;
|
|
1216
|
-
while (i < text2.length && text2[i] === "`") {
|
|
1217
|
-
backticks++;
|
|
1218
|
-
i++;
|
|
1219
|
-
}
|
|
1220
|
-
if (backticks === 0)
|
|
1221
|
-
return null;
|
|
1222
|
-
const closePattern = "`".repeat(backticks);
|
|
1223
|
-
const closeIndex = text2.indexOf(closePattern, i);
|
|
1224
|
-
if (closeIndex === -1)
|
|
1225
|
-
return null;
|
|
1226
|
-
if (text2[closeIndex + backticks] === "`") {
|
|
1227
|
-
return null;
|
|
1228
|
-
}
|
|
1229
|
-
const content = text2.slice(i, closeIndex);
|
|
1230
|
-
return {
|
|
1231
|
-
token: { type: "code", content: content.trim() },
|
|
1232
|
-
end: closeIndex + backticks
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
function matchLink(text2, start, isImage = false) {
|
|
1236
|
-
if (text2[start] !== "[")
|
|
1237
|
-
return null;
|
|
1238
|
-
let bracketDepth = 1;
|
|
1239
|
-
let i = start + 1;
|
|
1240
|
-
while (i < text2.length && bracketDepth > 0) {
|
|
1241
|
-
if (text2[i] === "[")
|
|
1242
|
-
bracketDepth++;
|
|
1243
|
-
else if (text2[i] === "]")
|
|
1244
|
-
bracketDepth--;
|
|
1245
|
-
else if (text2[i] === "\\")
|
|
1246
|
-
i++;
|
|
1247
|
-
i++;
|
|
1248
|
-
}
|
|
1249
|
-
if (bracketDepth !== 0)
|
|
1250
|
-
return null;
|
|
1251
|
-
const linkText = text2.slice(start + 1, i - 1);
|
|
1252
|
-
if (text2[i] !== "(")
|
|
1253
|
-
return null;
|
|
1254
|
-
const urlStart = i + 1;
|
|
1255
|
-
let urlEnd = urlStart;
|
|
1256
|
-
let parenDepth = 1;
|
|
1257
|
-
while (urlEnd < text2.length && parenDepth > 0) {
|
|
1258
|
-
if (text2[urlEnd] === "(")
|
|
1259
|
-
parenDepth++;
|
|
1260
|
-
else if (text2[urlEnd] === ")")
|
|
1261
|
-
parenDepth--;
|
|
1262
|
-
else if (text2[urlEnd] === "\\")
|
|
1263
|
-
urlEnd++;
|
|
1264
|
-
urlEnd++;
|
|
1265
|
-
}
|
|
1266
|
-
if (parenDepth !== 0)
|
|
1267
|
-
return null;
|
|
1268
|
-
const urlPart = text2.slice(urlStart, urlEnd - 1).trim();
|
|
1269
|
-
let url = urlPart;
|
|
1270
|
-
let title;
|
|
1271
|
-
const titleMatch = urlPart.match(/^(.+?)\s+["'](.+?)["']$/);
|
|
1272
|
-
if (titleMatch) {
|
|
1273
|
-
url = titleMatch[1];
|
|
1274
|
-
title = titleMatch[2];
|
|
1275
|
-
}
|
|
1276
|
-
const token = isImage ? { type: "image", content: linkText, url, title } : { type: "link", content: linkText, url, title };
|
|
1277
|
-
return {
|
|
1278
|
-
token,
|
|
1279
|
-
end: isImage ? urlEnd + 1 : urlEnd
|
|
1280
|
-
};
|
|
1281
|
-
}
|
|
1282
|
-
function matchEmphasis(text2, start) {
|
|
1283
|
-
const char = text2[start];
|
|
1284
|
-
if (char !== "*" && char !== "_")
|
|
1285
|
-
return null;
|
|
1286
|
-
let count = 0;
|
|
1287
|
-
let i = start;
|
|
1288
|
-
while (i < text2.length && text2[i] === char && count < 3) {
|
|
1289
|
-
count++;
|
|
1290
|
-
i++;
|
|
1291
|
-
}
|
|
1292
|
-
if (count === 0)
|
|
1293
|
-
return null;
|
|
1294
|
-
const closePattern = char.repeat(count);
|
|
1295
|
-
let searchStart = i;
|
|
1296
|
-
while (searchStart < text2.length) {
|
|
1297
|
-
const closeIndex = text2.indexOf(closePattern, searchStart);
|
|
1298
|
-
if (closeIndex === -1)
|
|
1299
|
-
return null;
|
|
1300
|
-
if (text2[closeIndex + count] === char) {
|
|
1301
|
-
searchStart = closeIndex + 1;
|
|
1302
|
-
continue;
|
|
1303
|
-
}
|
|
1304
|
-
if (text2[closeIndex - 1] === " ") {
|
|
1305
|
-
searchStart = closeIndex + 1;
|
|
1306
|
-
continue;
|
|
1307
|
-
}
|
|
1308
|
-
const content = text2.slice(i, closeIndex);
|
|
1309
|
-
if (!content.trim()) {
|
|
1310
|
-
searchStart = closeIndex + 1;
|
|
1311
|
-
continue;
|
|
1312
|
-
}
|
|
1313
|
-
const children = parseInlineTokens(content);
|
|
1314
|
-
if (count === 3) {
|
|
1315
|
-
return {
|
|
1316
|
-
token: {
|
|
1317
|
-
type: "bold",
|
|
1318
|
-
content,
|
|
1319
|
-
children: [{ type: "italic", content, children }]
|
|
1320
|
-
},
|
|
1321
|
-
end: closeIndex + count
|
|
1322
|
-
};
|
|
1323
|
-
} else if (count === 2) {
|
|
1324
|
-
return {
|
|
1325
|
-
token: { type: "bold", content, children },
|
|
1326
|
-
end: closeIndex + count
|
|
1327
|
-
};
|
|
1328
|
-
} else {
|
|
1329
|
-
return {
|
|
1330
|
-
token: { type: "italic", content, children },
|
|
1331
|
-
end: closeIndex + count
|
|
1332
|
-
};
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
return null;
|
|
1336
|
-
}
|
|
1337
|
-
function matchStrikethrough(text2, start) {
|
|
1338
|
-
if (text2[start] !== "~" || text2[start + 1] !== "~")
|
|
1339
|
-
return null;
|
|
1340
|
-
const closeIndex = text2.indexOf("~~", start + 2);
|
|
1341
|
-
if (closeIndex === -1)
|
|
1342
|
-
return null;
|
|
1343
|
-
const content = text2.slice(start + 2, closeIndex);
|
|
1344
|
-
if (!content.trim())
|
|
1345
|
-
return null;
|
|
1346
|
-
const children = parseInlineTokens(content);
|
|
1347
|
-
return {
|
|
1348
|
-
token: { type: "strikethrough", content, children },
|
|
1349
|
-
end: closeIndex + 2
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
function matchHighlight(text2, start) {
|
|
1353
|
-
if (text2[start] !== "=" || text2[start + 1] !== "=")
|
|
1354
|
-
return null;
|
|
1355
|
-
const closeIndex = text2.indexOf("==", start + 2);
|
|
1356
|
-
if (closeIndex === -1)
|
|
1357
|
-
return null;
|
|
1358
|
-
const content = text2.slice(start + 2, closeIndex);
|
|
1359
|
-
if (!content.trim())
|
|
1360
|
-
return null;
|
|
1361
|
-
const children = parseInlineTokens(content);
|
|
1362
|
-
return {
|
|
1363
|
-
token: { type: "highlight", content, children },
|
|
1364
|
-
end: closeIndex + 2
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
function tokensToSpans(tokens) {
|
|
1368
|
-
const spans2 = [];
|
|
1369
|
-
for (const token of tokens) {
|
|
1370
|
-
const newSpans = tokenToSpans(token, {});
|
|
1371
|
-
spans2.push(...newSpans);
|
|
1372
|
-
}
|
|
1373
|
-
return mergeAdjacentSpans(spans2);
|
|
1374
|
-
}
|
|
1375
|
-
function tokenToSpans(token, inheritedStyles) {
|
|
1376
|
-
switch (token.type) {
|
|
1377
|
-
case "text":
|
|
1378
|
-
return [{ text: token.content, styles: { ...inheritedStyles } }];
|
|
1379
|
-
case "bold":
|
|
1380
|
-
return processStyledToken(token, { ...inheritedStyles, bold: true });
|
|
1381
|
-
case "italic":
|
|
1382
|
-
return processStyledToken(token, { ...inheritedStyles, italic: true });
|
|
1383
|
-
case "code":
|
|
1384
|
-
return [{ text: token.content, styles: { ...inheritedStyles, code: true } }];
|
|
1385
|
-
case "strikethrough":
|
|
1386
|
-
return processStyledToken(token, { ...inheritedStyles, strikethrough: true });
|
|
1387
|
-
case "highlight":
|
|
1388
|
-
return processStyledToken(token, { ...inheritedStyles, highlight: true });
|
|
1389
|
-
case "link":
|
|
1390
|
-
return processStyledToken(token, {
|
|
1391
|
-
...inheritedStyles,
|
|
1392
|
-
link: { url: token.url || "", title: token.title }
|
|
1393
|
-
});
|
|
1394
|
-
case "image":
|
|
1395
|
-
return [{ text: `[image: ${token.content}]`, styles: inheritedStyles }];
|
|
1396
|
-
default:
|
|
1397
|
-
return [{ text: token.content, styles: inheritedStyles }];
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
function processStyledToken(token, styles) {
|
|
1401
|
-
if (token.children && token.children.length > 0) {
|
|
1402
|
-
const spans2 = [];
|
|
1403
|
-
for (const child of token.children) {
|
|
1404
|
-
spans2.push(...tokenToSpans(child, styles));
|
|
1405
|
-
}
|
|
1406
|
-
return spans2;
|
|
1407
|
-
}
|
|
1408
|
-
return [{ text: token.content, styles }];
|
|
1409
|
-
}
|
|
1410
|
-
function mergeAdjacentSpans(spans2) {
|
|
1411
|
-
if (spans2.length === 0)
|
|
1412
|
-
return [];
|
|
1413
|
-
const merged = [spans2[0]];
|
|
1414
|
-
for (let i = 1;i < spans2.length; i++) {
|
|
1415
|
-
const current = spans2[i];
|
|
1416
|
-
const previous = merged[merged.length - 1];
|
|
1417
|
-
if (stylesEqual(current.styles, previous.styles)) {
|
|
1418
|
-
previous.text += current.text;
|
|
1419
|
-
} else {
|
|
1420
|
-
merged.push(current);
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
return merged;
|
|
1424
|
-
}
|
|
1425
|
-
function stylesEqual(a, b) {
|
|
1426
|
-
return a.bold === b.bold && a.italic === b.italic && a.underline === b.underline && a.strikethrough === b.strikethrough && a.code === b.code && a.highlight === b.highlight && linksEqual(a.link, b.link);
|
|
1427
|
-
}
|
|
1428
|
-
function linksEqual(a, b) {
|
|
1429
|
-
if (!a && !b)
|
|
1430
|
-
return true;
|
|
1431
|
-
if (!a || !b)
|
|
1432
|
-
return false;
|
|
1433
|
-
return a.url === b.url && a.title === b.title;
|
|
1434
|
-
}
|
|
1435
|
-
function tryMatchInline(text2, pos) {
|
|
1436
|
-
const matchers = [
|
|
1437
|
-
() => matchCode(text2, pos),
|
|
1438
|
-
() => matchEmphasis(text2, pos),
|
|
1439
|
-
() => matchStrikethrough(text2, pos),
|
|
1440
|
-
() => matchHighlight(text2, pos)
|
|
1441
|
-
];
|
|
1442
|
-
for (const match of matchers) {
|
|
1443
|
-
const result = match();
|
|
1444
|
-
if (result) {
|
|
1445
|
-
return {
|
|
1446
|
-
token: result.token,
|
|
1447
|
-
startIndex: pos,
|
|
1448
|
-
endIndex: result.end
|
|
1449
|
-
};
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
return null;
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
// src/parsers/markdown.ts
|
|
1456
|
-
var DEFAULT_OPTIONS2 = {
|
|
1457
|
-
generateId,
|
|
1458
|
-
strict: false
|
|
1459
|
-
};
|
|
1460
|
-
function markdownToBlocks(markdown, options = {}) {
|
|
1461
|
-
const opts = { ...DEFAULT_OPTIONS2, ...options };
|
|
1462
|
-
const tokens = tokenize(markdown);
|
|
1463
|
-
return parseTokens(tokens, opts);
|
|
1464
|
-
}
|
|
1465
|
-
function markdownToDocument(markdown, options = {}) {
|
|
1466
|
-
const blocks = markdownToBlocks(markdown, options);
|
|
1467
|
-
return createDocument(blocks);
|
|
1468
|
-
}
|
|
1469
|
-
function parse(markdown, options) {
|
|
1470
|
-
return markdownToBlocks(markdown, options);
|
|
1471
|
-
}
|
|
1472
|
-
function parseTokens(tokens, options) {
|
|
1473
|
-
const blocks = [];
|
|
1474
|
-
const state = {
|
|
1475
|
-
options,
|
|
1476
|
-
tokens,
|
|
1477
|
-
index: 0
|
|
1478
|
-
};
|
|
1479
|
-
while (state.index < tokens.length) {
|
|
1480
|
-
const token = tokens[state.index];
|
|
1481
|
-
if (token.type === "blank") {
|
|
1482
|
-
state.index++;
|
|
1483
|
-
continue;
|
|
1484
|
-
}
|
|
1485
|
-
const block = parseBlock(state);
|
|
1486
|
-
if (block) {
|
|
1487
|
-
blocks.push(block);
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
return blocks;
|
|
1491
|
-
}
|
|
1492
|
-
function parseBlock(state) {
|
|
1493
|
-
const token = state.tokens[state.index];
|
|
1494
|
-
switch (token.type) {
|
|
1495
|
-
case "heading":
|
|
1496
|
-
return parseHeading(state);
|
|
1497
|
-
case "paragraph":
|
|
1498
|
-
return parseParagraph(state);
|
|
1499
|
-
case "bullet_list_item":
|
|
1500
|
-
return parseBulletList(state);
|
|
1501
|
-
case "numbered_list_item":
|
|
1502
|
-
return parseNumberedList(state);
|
|
1503
|
-
case "check_list_item":
|
|
1504
|
-
return parseCheckListItem(state);
|
|
1505
|
-
case "code_fence_start":
|
|
1506
|
-
return parseCodeBlock(state);
|
|
1507
|
-
case "blockquote":
|
|
1508
|
-
return parseBlockquote(state);
|
|
1509
|
-
case "callout":
|
|
1510
|
-
return parseCallout(state);
|
|
1511
|
-
case "divider":
|
|
1512
|
-
return parseDivider(state);
|
|
1513
|
-
case "table_row":
|
|
1514
|
-
return parseTable(state);
|
|
1515
|
-
case "image":
|
|
1516
|
-
return parseImage(state);
|
|
1517
|
-
default:
|
|
1518
|
-
state.index++;
|
|
1519
|
-
return null;
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
function parseHeading(state) {
|
|
1523
|
-
const token = state.tokens[state.index];
|
|
1524
|
-
const level = token.meta?.level ?? 1;
|
|
1525
|
-
const content = parseInlineContent(token.content);
|
|
1526
|
-
state.index++;
|
|
1527
|
-
return {
|
|
1528
|
-
id: state.options.generateId(),
|
|
1529
|
-
type: "heading",
|
|
1530
|
-
content,
|
|
1531
|
-
children: [],
|
|
1532
|
-
props: { level }
|
|
1533
|
-
};
|
|
1534
|
-
}
|
|
1535
|
-
function parseParagraph(state) {
|
|
1536
|
-
const lines = [];
|
|
1537
|
-
while (state.index < state.tokens.length && state.tokens[state.index].type === "paragraph") {
|
|
1538
|
-
lines.push(state.tokens[state.index].content);
|
|
1539
|
-
state.index++;
|
|
1540
|
-
}
|
|
1541
|
-
const content = parseInlineContent(lines.join(" "));
|
|
1542
|
-
return {
|
|
1543
|
-
id: state.options.generateId(),
|
|
1544
|
-
type: "paragraph",
|
|
1545
|
-
content,
|
|
1546
|
-
children: [],
|
|
1547
|
-
props: {}
|
|
1548
|
-
};
|
|
1549
|
-
}
|
|
1550
|
-
function parseBulletList(state) {
|
|
1551
|
-
const children = [];
|
|
1552
|
-
const baseIndent = state.tokens[state.index].indent;
|
|
1553
|
-
while (state.index < state.tokens.length && state.tokens[state.index].type === "bullet_list_item" && state.tokens[state.index].indent >= baseIndent) {
|
|
1554
|
-
const token = state.tokens[state.index];
|
|
1555
|
-
if (token.indent > baseIndent) {
|
|
1556
|
-
state.index++;
|
|
1557
|
-
continue;
|
|
1558
|
-
}
|
|
1559
|
-
const content = parseInlineContent(token.content);
|
|
1560
|
-
children.push({
|
|
1561
|
-
id: state.options.generateId(),
|
|
1562
|
-
type: "paragraph",
|
|
1563
|
-
content,
|
|
1564
|
-
children: [],
|
|
1565
|
-
props: {}
|
|
1566
|
-
});
|
|
1567
|
-
state.index++;
|
|
1568
|
-
}
|
|
1569
|
-
return {
|
|
1570
|
-
id: state.options.generateId(),
|
|
1571
|
-
type: "bulletList",
|
|
1572
|
-
content: [],
|
|
1573
|
-
children,
|
|
1574
|
-
props: {}
|
|
1575
|
-
};
|
|
1576
|
-
}
|
|
1577
|
-
function parseNumberedList(state) {
|
|
1578
|
-
const children = [];
|
|
1579
|
-
const baseIndent = state.tokens[state.index].indent;
|
|
1580
|
-
while (state.index < state.tokens.length && state.tokens[state.index].type === "numbered_list_item" && state.tokens[state.index].indent >= baseIndent) {
|
|
1581
|
-
const token = state.tokens[state.index];
|
|
1582
|
-
if (token.indent > baseIndent) {
|
|
1583
|
-
state.index++;
|
|
1584
|
-
continue;
|
|
1585
|
-
}
|
|
1586
|
-
const content = parseInlineContent(token.content);
|
|
1587
|
-
children.push({
|
|
1588
|
-
id: state.options.generateId(),
|
|
1589
|
-
type: "paragraph",
|
|
1590
|
-
content,
|
|
1591
|
-
children: [],
|
|
1592
|
-
props: {}
|
|
1593
|
-
});
|
|
1594
|
-
state.index++;
|
|
1595
|
-
}
|
|
1596
|
-
return {
|
|
1597
|
-
id: state.options.generateId(),
|
|
1598
|
-
type: "numberedList",
|
|
1599
|
-
content: [],
|
|
1600
|
-
children,
|
|
1601
|
-
props: {}
|
|
1602
|
-
};
|
|
1603
|
-
}
|
|
1604
|
-
function parseCheckListItem(state) {
|
|
1605
|
-
const token = state.tokens[state.index];
|
|
1606
|
-
const checked = token.meta?.checked ?? false;
|
|
1607
|
-
const content = parseInlineContent(token.content);
|
|
1608
|
-
state.index++;
|
|
1609
|
-
return {
|
|
1610
|
-
id: state.options.generateId(),
|
|
1611
|
-
type: "checkList",
|
|
1612
|
-
content,
|
|
1613
|
-
children: [],
|
|
1614
|
-
props: { checked }
|
|
1615
|
-
};
|
|
1616
|
-
}
|
|
1617
|
-
function parseCodeBlock(state) {
|
|
1618
|
-
const startToken = state.tokens[state.index];
|
|
1619
|
-
const language = startToken.meta?.language ?? "";
|
|
1620
|
-
const codeLines = [];
|
|
1621
|
-
state.index++;
|
|
1622
|
-
while (state.index < state.tokens.length && state.tokens[state.index].type === "code_content") {
|
|
1623
|
-
codeLines.push(state.tokens[state.index].content);
|
|
1624
|
-
state.index++;
|
|
1625
|
-
}
|
|
1626
|
-
if (state.index < state.tokens.length && state.tokens[state.index].type === "code_fence_end") {
|
|
1627
|
-
state.index++;
|
|
1628
|
-
}
|
|
1629
|
-
return {
|
|
1630
|
-
id: state.options.generateId(),
|
|
1631
|
-
type: "codeBlock",
|
|
1632
|
-
content: plainContent(codeLines.join(`
|
|
1633
|
-
`)),
|
|
1634
|
-
children: [],
|
|
1635
|
-
props: { language: language || undefined }
|
|
1636
|
-
};
|
|
1637
|
-
}
|
|
1638
|
-
function parseBlockquote(state) {
|
|
1639
|
-
const lines = [];
|
|
1640
|
-
while (state.index < state.tokens.length && state.tokens[state.index].type === "blockquote") {
|
|
1641
|
-
lines.push(state.tokens[state.index].content);
|
|
1642
|
-
state.index++;
|
|
1643
|
-
}
|
|
1644
|
-
const content = parseInlineContent(lines.join(`
|
|
1645
|
-
`));
|
|
1646
|
-
return {
|
|
1647
|
-
id: state.options.generateId(),
|
|
1648
|
-
type: "blockquote",
|
|
1649
|
-
content,
|
|
1650
|
-
children: [],
|
|
1651
|
-
props: {}
|
|
1652
|
-
};
|
|
1653
|
-
}
|
|
1654
|
-
function parseCallout(state) {
|
|
1655
|
-
const calloutToken = state.tokens[state.index];
|
|
1656
|
-
const calloutType = calloutToken.meta?.calloutType ?? "note";
|
|
1657
|
-
state.index++;
|
|
1658
|
-
const lines = [];
|
|
1659
|
-
while (state.index < state.tokens.length && state.tokens[state.index].type === "blockquote") {
|
|
1660
|
-
lines.push(state.tokens[state.index].content);
|
|
1661
|
-
state.index++;
|
|
1662
|
-
}
|
|
1663
|
-
const content = parseInlineContent(lines.join(`
|
|
1664
|
-
`));
|
|
1665
|
-
return {
|
|
1666
|
-
id: state.options.generateId(),
|
|
1667
|
-
type: "callout",
|
|
1668
|
-
content,
|
|
1669
|
-
children: [],
|
|
1670
|
-
props: { type: calloutType }
|
|
1671
|
-
};
|
|
1672
|
-
}
|
|
1673
|
-
function parseDivider(state) {
|
|
1674
|
-
state.index++;
|
|
1675
|
-
return {
|
|
1676
|
-
id: state.options.generateId(),
|
|
1677
|
-
type: "divider",
|
|
1678
|
-
content: [],
|
|
1679
|
-
children: [],
|
|
1680
|
-
props: {}
|
|
1681
|
-
};
|
|
1682
|
-
}
|
|
1683
|
-
function parseTable(state) {
|
|
1684
|
-
const rows = [];
|
|
1685
|
-
let headers = [];
|
|
1686
|
-
let alignments = [];
|
|
1687
|
-
let isFirstRow = true;
|
|
1688
|
-
let hasSeparator = false;
|
|
1689
|
-
while (state.index < state.tokens.length && (state.tokens[state.index].type === "table_row" || state.tokens[state.index].type === "table_separator")) {
|
|
1690
|
-
const token = state.tokens[state.index];
|
|
1691
|
-
if (token.type === "table_separator") {
|
|
1692
|
-
alignments = parseTableAlignments(token.content);
|
|
1693
|
-
hasSeparator = true;
|
|
1694
|
-
state.index++;
|
|
1695
|
-
continue;
|
|
1696
|
-
}
|
|
1697
|
-
const cells = token.content.split("|").map((cell) => cell.trim()).filter((cell) => cell !== "");
|
|
1698
|
-
if (isFirstRow && !hasSeparator) {
|
|
1699
|
-
headers = cells;
|
|
1700
|
-
isFirstRow = false;
|
|
1701
|
-
} else if (hasSeparator) {
|
|
1702
|
-
rows.push(cells);
|
|
1703
|
-
}
|
|
1704
|
-
state.index++;
|
|
1705
|
-
}
|
|
1706
|
-
if (!hasSeparator && headers.length > 0) {
|
|
1707
|
-
rows.unshift(headers);
|
|
1708
|
-
headers = [];
|
|
1709
|
-
}
|
|
1710
|
-
return {
|
|
1711
|
-
id: state.options.generateId(),
|
|
1712
|
-
type: "table",
|
|
1713
|
-
content: [],
|
|
1714
|
-
children: [],
|
|
1715
|
-
props: {
|
|
1716
|
-
headers,
|
|
1717
|
-
rows,
|
|
1718
|
-
alignments: alignments.length > 0 ? alignments : undefined
|
|
1719
|
-
}
|
|
1720
|
-
};
|
|
1721
|
-
}
|
|
1722
|
-
function parseTableAlignments(separator) {
|
|
1723
|
-
return separator.split("|").map((cell) => cell.trim()).filter((cell) => cell !== "").map((cell) => {
|
|
1724
|
-
const leftColon = cell.startsWith(":");
|
|
1725
|
-
const rightColon = cell.endsWith(":");
|
|
1726
|
-
if (leftColon && rightColon)
|
|
1727
|
-
return "center";
|
|
1728
|
-
if (leftColon)
|
|
1729
|
-
return "left";
|
|
1730
|
-
if (rightColon)
|
|
1731
|
-
return "right";
|
|
1732
|
-
return null;
|
|
1733
|
-
});
|
|
1734
|
-
}
|
|
1735
|
-
function parseImage(state) {
|
|
1736
|
-
const token = state.tokens[state.index];
|
|
1737
|
-
const url = token.content;
|
|
1738
|
-
const alt = token.meta?.language ?? "";
|
|
1739
|
-
state.index++;
|
|
1740
|
-
return {
|
|
1741
|
-
id: state.options.generateId(),
|
|
1742
|
-
type: "image",
|
|
1743
|
-
content: [],
|
|
1744
|
-
children: [],
|
|
1745
|
-
props: {
|
|
1746
|
-
url,
|
|
1747
|
-
alt: alt || undefined
|
|
1748
|
-
}
|
|
1749
|
-
};
|
|
1750
|
-
}
|
|
1751
|
-
// src/index.ts
|
|
1752
|
-
function fromMarkdown(markdown) {
|
|
1753
|
-
const blocks = markdownToBlocks(markdown);
|
|
1754
|
-
return createDocument(blocks);
|
|
1755
|
-
}
|
|
1756
|
-
function toMarkdown(blocksOrDoc) {
|
|
1757
|
-
const blocks = Array.isArray(blocksOrDoc) ? blocksOrDoc : blocksOrDoc.blocks;
|
|
1758
|
-
return blocksToMarkdown(blocks);
|
|
1759
|
-
}
|
|
52
|
+
__reExport(exports_src, require("@create-markdown/core"), module.exports);
|
|
1760
53
|
var VERSION = "0.2.0";
|