@md-lark-converter/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1517 @@
1
+ // src/utils/idGenerator.ts
2
+ var ID_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
3
+ function generateBlockId() {
4
+ let id = "";
5
+ for (let i = 0; i < 4; i++) {
6
+ for (let j = 0; j < 4; j++) {
7
+ id += ID_CHARS[Math.floor(Math.random() * ID_CHARS.length)];
8
+ }
9
+ if (i < 3) id += "_";
10
+ }
11
+ return `docx${id}`;
12
+ }
13
+ function generateRecordId() {
14
+ let id = "";
15
+ for (let i = 0; i < 4; i++) {
16
+ for (let j = 0; j < 4; j++) {
17
+ id += ID_CHARS[Math.floor(Math.random() * ID_CHARS.length)];
18
+ }
19
+ if (i < 3) id += "_";
20
+ }
21
+ return `doxcn${id}`;
22
+ }
23
+ function generatePageId() {
24
+ let id = "";
25
+ for (let i = 0; i < 4; i++) {
26
+ for (let j = 0; j < 4; j++) {
27
+ id += ID_CHARS[Math.floor(Math.random() * ID_CHARS.length)];
28
+ }
29
+ if (i < 3) id += "_";
30
+ }
31
+ return `Wqf${id}`;
32
+ }
33
+
34
+ // src/converter/markdownToLark.ts
35
+ import { unified } from "unified";
36
+ import remarkParse from "remark-parse";
37
+ import remarkMath from "remark-math";
38
+ import remarkGfm from "remark-gfm";
39
+ import { visit, SKIP } from "unist-util-visit";
40
+ var MarkdownToLarkConverter = class {
41
+ rootId;
42
+ authorId;
43
+ recordMap;
44
+ blockIds;
45
+ recordIds;
46
+ payloadMap;
47
+ apoolNextNum;
48
+ apoolNumToAttrib;
49
+ constructor() {
50
+ this.rootId = null;
51
+ this.authorId = "7092639913849389057";
52
+ this.recordMap = {};
53
+ this.blockIds = [];
54
+ this.recordIds = [];
55
+ this.payloadMap = {};
56
+ this.apoolNextNum = 0;
57
+ this.apoolNumToAttrib = {};
58
+ }
59
+ async convert(markdown) {
60
+ this.rootId = generatePageId();
61
+ this.recordMap = {};
62
+ this.blockIds = [];
63
+ this.recordIds = [];
64
+ this.payloadMap = {};
65
+ this.apoolNextNum = 0;
66
+ this.apoolNumToAttrib = {};
67
+ const normalizedMarkdown = this.normalizeMathBlocks(markdown);
68
+ const tree = await unified().use(remarkParse).use(remarkGfm).use(remarkMath).parse(normalizedMarkdown);
69
+ this.createPageBlock(this.rootId);
70
+ this.convertTree(tree);
71
+ return this.buildClipboardData();
72
+ }
73
+ normalizeMathBlocks(markdown) {
74
+ return markdown.replace(/\$\$([^\n]+?)\$\$/g, (_, content) => {
75
+ return `$$
76
+ ${content.trim()}
77
+ $$`;
78
+ });
79
+ }
80
+ createPageBlock(pageId) {
81
+ this.recordMap[pageId] = {
82
+ id: pageId,
83
+ snapshot: {
84
+ type: "page",
85
+ parent_id: "",
86
+ comments: null,
87
+ revisions: null,
88
+ locked: false,
89
+ hidden: false,
90
+ author: this.authorId,
91
+ children: [],
92
+ text: this.createTextData(""),
93
+ align: "",
94
+ page_style: {},
95
+ title: {
96
+ apool: { nextNum: 0, numToAttrib: {} },
97
+ initialAttributedTexts: {
98
+ attribs: {},
99
+ text: { "0": "\u65E0\u6807\u9898" }
100
+ }
101
+ }
102
+ }
103
+ };
104
+ }
105
+ convertTree(tree) {
106
+ const topLevelRecordIds = [];
107
+ visit(tree, (node, index, parent) => {
108
+ if (parent?.type === "listItem") {
109
+ return SKIP;
110
+ }
111
+ if (node.type === "heading") {
112
+ const recordId = generateRecordId();
113
+ this.recordMap[recordId] = this.createHeadingBlock(recordId, node);
114
+ this.recordIds.push(recordId);
115
+ this.blockIds.push(this.blockIds.length + 1);
116
+ topLevelRecordIds.push(recordId);
117
+ } else if (node.type === "paragraph") {
118
+ const recordId = generateRecordId();
119
+ this.recordMap[recordId] = this.createTextBlock(recordId, node);
120
+ this.recordIds.push(recordId);
121
+ this.blockIds.push(this.blockIds.length + 1);
122
+ topLevelRecordIds.push(recordId);
123
+ } else if (node.type === "blockquote") {
124
+ const recordId = generateRecordId();
125
+ this.recordMap[recordId] = this.createQuoteBlock(recordId, node);
126
+ this.recordIds.push(recordId);
127
+ this.blockIds.push(this.blockIds.length + 1);
128
+ topLevelRecordIds.push(recordId);
129
+ return SKIP;
130
+ } else if (node.type === "code") {
131
+ const recordId = generateRecordId();
132
+ const codeNode = node;
133
+ if (codeNode.lang && codeNode.lang.toLowerCase() === "mermaid") {
134
+ this.recordMap[recordId] = this.createMermaidBlock(recordId, codeNode.value);
135
+ } else {
136
+ this.recordMap[recordId] = this.createCodeBlock(recordId, codeNode.value, codeNode.lang ?? void 0);
137
+ }
138
+ this.recordIds.push(recordId);
139
+ this.blockIds.push(this.blockIds.length + 1);
140
+ topLevelRecordIds.push(recordId);
141
+ } else if (node.type === "thematicBreak") {
142
+ const recordId = generateRecordId();
143
+ this.recordMap[recordId] = this.createDividerBlock(recordId);
144
+ this.recordIds.push(recordId);
145
+ this.blockIds.push(this.blockIds.length + 1);
146
+ topLevelRecordIds.push(recordId);
147
+ } else if (node.type === "math") {
148
+ const mathNode = node;
149
+ const recordId = generateRecordId();
150
+ const equation = mathNode.value ?? "";
151
+ this.recordMap[recordId] = this.createEquationParagraphBlock(recordId, equation);
152
+ this.recordIds.push(recordId);
153
+ this.blockIds.push(this.blockIds.length + 1);
154
+ topLevelRecordIds.push(recordId);
155
+ } else if (node.type === "table") {
156
+ const tableRecordIds = this.convertTable(node);
157
+ topLevelRecordIds.push(tableRecordIds.tableId);
158
+ }
159
+ });
160
+ const processedLists = /* @__PURE__ */ new Set();
161
+ visit(tree, "list", (node, index, parent) => {
162
+ if (processedLists.has(node)) {
163
+ return SKIP;
164
+ }
165
+ processedLists.add(node);
166
+ if (parent?.type === "listItem") {
167
+ return SKIP;
168
+ }
169
+ const listRecordIds = this.convertList(node);
170
+ topLevelRecordIds.push(...listRecordIds);
171
+ });
172
+ if (this.rootId && this.recordMap[this.rootId]) {
173
+ this.recordMap[this.rootId].snapshot.children = topLevelRecordIds;
174
+ }
175
+ }
176
+ convertList(listNode) {
177
+ const ordered = listNode.ordered || false;
178
+ return this.convertListItems(listNode.children, ordered, null, 0, true);
179
+ }
180
+ convertListItems(items, ordered, parentId = null, level = 0, isTopLevel = false) {
181
+ const childRecordIds = [];
182
+ const topLevelIds = [];
183
+ let index = 1;
184
+ for (const item of items) {
185
+ const recordId = generateRecordId();
186
+ const blockId = this.blockIds.length + 1;
187
+ let blockType = ordered ? "ordered" : "bullet";
188
+ const isTaskItem = item.checked !== void 0 && item.checked !== null;
189
+ if (isTaskItem) {
190
+ blockType = "todo";
191
+ }
192
+ const listContent = item.children;
193
+ const segments = listContent.length > 0 && listContent[0].type === "paragraph" ? this.parseInlineContent(listContent[0].children) : this.parseInlineContent(listContent);
194
+ if (isTopLevel && level === 0) {
195
+ this.recordIds.push(recordId);
196
+ }
197
+ const snapshot = {
198
+ type: blockType,
199
+ parent_id: parentId || this.rootId,
200
+ comments: [],
201
+ revisions: [],
202
+ locked: false,
203
+ hidden: false,
204
+ author: this.authorId,
205
+ children: [],
206
+ text: ordered ? this.createListItemTextData(segments) : this.createTextData(segments),
207
+ align: "",
208
+ folded: false
209
+ };
210
+ if (isTaskItem) {
211
+ snapshot.done = item.checked || false;
212
+ }
213
+ if (ordered) {
214
+ snapshot.level = level + 1;
215
+ snapshot.seq = index === 1 ? "1" : "auto";
216
+ index++;
217
+ } else {
218
+ snapshot.level = level + 1;
219
+ }
220
+ for (const child of item.children) {
221
+ if (child.type === "list") {
222
+ const nestedChildIds = this.convertListItems(
223
+ child.children,
224
+ child.ordered || false,
225
+ recordId,
226
+ level + 1,
227
+ false
228
+ );
229
+ snapshot.children.push(...nestedChildIds);
230
+ }
231
+ }
232
+ this.recordMap[recordId] = {
233
+ id: recordId,
234
+ snapshot
235
+ };
236
+ this.blockIds.push(blockId);
237
+ childRecordIds.push(recordId);
238
+ if (isTopLevel && level === 0) {
239
+ topLevelIds.push(recordId);
240
+ }
241
+ }
242
+ return isTopLevel ? topLevelIds : childRecordIds;
243
+ }
244
+ parseInlineContent(children) {
245
+ const segments = [];
246
+ for (const child of children) {
247
+ if (child.type === "text") {
248
+ segments.push({ text: child.value });
249
+ } else if (child.type === "strong") {
250
+ const text = this.extractTextContent(child);
251
+ segments.push({ text, bold: true });
252
+ } else if (child.type === "emphasis") {
253
+ const text = this.extractTextContent(child);
254
+ segments.push({ text, italic: true });
255
+ } else if (child.type === "delete") {
256
+ const text = this.extractTextContent(child);
257
+ segments.push({ text, strikethrough: true });
258
+ } else if (child.type === "inlineCode") {
259
+ segments.push({ text: child.value });
260
+ } else if (child.type === "link") {
261
+ const linkNode = child;
262
+ const text = this.extractTextContent(linkNode);
263
+ segments.push({ text, linkUrl: linkNode.url });
264
+ } else if (child.type === "image") {
265
+ segments.push({ text: " [markdown-to-lark \u6682\u65E0\u6CD5\u652F\u6301\u56FE\u7247\u8F6C\u6362] " });
266
+ } else if (child.type === "inlineMath") {
267
+ const mathNode = child;
268
+ segments.push({ text: "E", equation: mathNode.value ?? "" });
269
+ } else if (child.type === "break") {
270
+ segments.push({ text: "\n" });
271
+ }
272
+ }
273
+ return segments;
274
+ }
275
+ extractTextContent(node) {
276
+ let text = "";
277
+ if (node.type === "text") {
278
+ text = node.value;
279
+ } else if (node.children) {
280
+ for (const child of node.children) {
281
+ text += this.extractTextContent(child);
282
+ }
283
+ }
284
+ return text;
285
+ }
286
+ createHeadingBlock(recordId, node) {
287
+ const depth = node.depth;
288
+ const segments = this.parseInlineContent(node.children);
289
+ return {
290
+ id: recordId,
291
+ snapshot: {
292
+ type: `heading${depth}`,
293
+ parent_id: this.rootId,
294
+ comments: [],
295
+ revisions: [],
296
+ locked: false,
297
+ hidden: false,
298
+ author: this.authorId,
299
+ children: [],
300
+ text: this.createTextData(segments),
301
+ level: depth,
302
+ folded: false
303
+ }
304
+ };
305
+ }
306
+ createTextBlock(recordId, node) {
307
+ const segments = this.parseInlineContent(node.children);
308
+ return {
309
+ id: recordId,
310
+ snapshot: {
311
+ type: "text",
312
+ parent_id: this.rootId,
313
+ comments: [],
314
+ revisions: [],
315
+ locked: false,
316
+ hidden: false,
317
+ author: this.authorId,
318
+ children: [],
319
+ text: this.createTextData(segments),
320
+ align: "",
321
+ folded: false
322
+ }
323
+ };
324
+ }
325
+ createQuoteBlock(recordId, node) {
326
+ const flattenedContent = this.flattenNestedBlockquotes(node.children);
327
+ const segments = this.parseInlineContent(flattenedContent);
328
+ return {
329
+ id: recordId,
330
+ snapshot: {
331
+ type: "quote",
332
+ parent_id: this.rootId,
333
+ comments: [],
334
+ revisions: [],
335
+ locked: false,
336
+ hidden: false,
337
+ author: this.authorId,
338
+ children: [],
339
+ text: this.createTextData(segments),
340
+ folded: false
341
+ }
342
+ };
343
+ }
344
+ flattenNestedBlockquotes(children) {
345
+ const result = [];
346
+ for (let i = 0; i < children.length; i++) {
347
+ const child = children[i];
348
+ if (child.type === "blockquote") {
349
+ const nestedContent = this.flattenNestedBlockquotes(child.children);
350
+ if (result.length > 0) {
351
+ result.push({ type: "text", value: "\n\n" });
352
+ }
353
+ result.push(...nestedContent);
354
+ } else if (child.type === "paragraph") {
355
+ if (result.length > 0) {
356
+ result.push({ type: "text", value: "\n\n" });
357
+ }
358
+ result.push(...child.children);
359
+ } else {
360
+ result.push(child);
361
+ }
362
+ }
363
+ return result;
364
+ }
365
+ createEquationBlock(recordId, equation) {
366
+ const segments = [{ text: "E", equation }];
367
+ return {
368
+ id: recordId,
369
+ snapshot: {
370
+ type: "equation",
371
+ parent_id: this.rootId,
372
+ comments: [],
373
+ revisions: [],
374
+ locked: false,
375
+ hidden: false,
376
+ author: this.authorId,
377
+ children: [],
378
+ elements: [{
379
+ equation: {
380
+ latex: equation
381
+ }
382
+ }],
383
+ text: this.createTextData(segments),
384
+ folded: false
385
+ }
386
+ };
387
+ }
388
+ createEquationParagraphBlock(recordId, equation) {
389
+ const segments = [{ text: "E", equation: equation + "_display" }];
390
+ return {
391
+ id: recordId,
392
+ snapshot: {
393
+ type: "text",
394
+ parent_id: this.rootId,
395
+ comments: [],
396
+ revisions: [],
397
+ locked: false,
398
+ hidden: false,
399
+ author: this.authorId,
400
+ children: [],
401
+ text: this.createTextData(segments),
402
+ align: "",
403
+ folded: false
404
+ }
405
+ };
406
+ }
407
+ createCodeBlock(recordId, code, lang) {
408
+ return {
409
+ id: recordId,
410
+ snapshot: {
411
+ type: "code",
412
+ parent_id: this.rootId,
413
+ comments: [],
414
+ revisions: [],
415
+ locked: false,
416
+ hidden: false,
417
+ author: this.authorId,
418
+ children: [],
419
+ language: lang || "plaintext",
420
+ code,
421
+ text: this.createTextData(code),
422
+ is_language_picked: true,
423
+ caption: {
424
+ text: {
425
+ initialAttributedTexts: {
426
+ text: { "0": "\n" },
427
+ attribs: { "0": "|1+1" }
428
+ },
429
+ apool: { numToAttrib: {}, nextNum: 0 }
430
+ }
431
+ },
432
+ wrap: false,
433
+ folded: false
434
+ }
435
+ };
436
+ }
437
+ createDividerBlock(recordId) {
438
+ return {
439
+ id: recordId,
440
+ snapshot: {
441
+ type: "divider",
442
+ parent_id: this.rootId,
443
+ comments: [],
444
+ revisions: [],
445
+ locked: false,
446
+ hidden: false,
447
+ author: this.authorId,
448
+ folded: false
449
+ }
450
+ };
451
+ }
452
+ createMermaidBlock(recordId, code) {
453
+ const blockId = generateBlockId();
454
+ return {
455
+ id: recordId,
456
+ snapshot: {
457
+ type: "isv",
458
+ parent_id: this.rootId,
459
+ comments: null,
460
+ revisions: null,
461
+ locked: false,
462
+ hidden: false,
463
+ author: this.authorId,
464
+ children: [],
465
+ data: {
466
+ data: code,
467
+ theme: "default",
468
+ view: "codeChart"
469
+ },
470
+ app_block_id: "",
471
+ block_type_id: "blk_631fefbbae02400430b8f9f4",
472
+ manifest: {
473
+ view_type: "block_h5",
474
+ app_version: "0.0.112"
475
+ },
476
+ comment_details: {},
477
+ interaction_data_token: this.generateRandomId()
478
+ }
479
+ };
480
+ }
481
+ createTextData(segments) {
482
+ if (typeof segments === "string") {
483
+ segments = [{ text: segments }];
484
+ }
485
+ if (!segments || segments.length === 0) {
486
+ return {
487
+ apool: { nextNum: 0, numToAttrib: {} },
488
+ initialAttributedTexts: {
489
+ attribs: "",
490
+ text: { "0": "" },
491
+ rows: {},
492
+ cols: {}
493
+ }
494
+ };
495
+ }
496
+ const apoolNumToAttrib = {
497
+ "0": ["author", this.authorId]
498
+ };
499
+ const attribToNum = {
500
+ [`author,${this.authorId}`]: 0
501
+ };
502
+ let apoolNextNum = 1;
503
+ const attribParts = [];
504
+ const textParts = [];
505
+ for (const segment of segments) {
506
+ const text = segment.text || "";
507
+ const length = text.length;
508
+ if (length === 0) continue;
509
+ textParts.push(text);
510
+ const activeAttrs = ["0"];
511
+ if (segment.linkUrl) {
512
+ const linkAttrNum = apoolNextNum.toString();
513
+ apoolNextNum++;
514
+ const encodedUrl = encodeURIComponent(segment.linkUrl);
515
+ apoolNumToAttrib[linkAttrNum] = ["link", encodedUrl];
516
+ attribToNum[`link,${encodedUrl}`] = parseInt(linkAttrNum);
517
+ activeAttrs.push(linkAttrNum);
518
+ }
519
+ if (segment.bold) {
520
+ const boldAttrKey = "bold,true";
521
+ let boldAttrNum = attribToNum[boldAttrKey];
522
+ if (boldAttrNum === void 0) {
523
+ boldAttrNum = apoolNextNum;
524
+ apoolNextNum++;
525
+ apoolNumToAttrib[boldAttrNum.toString()] = ["bold", "true"];
526
+ attribToNum[boldAttrKey] = boldAttrNum;
527
+ }
528
+ activeAttrs.push(boldAttrNum.toString());
529
+ }
530
+ if (segment.italic) {
531
+ const italicAttrKey = "italic,true";
532
+ let italicAttrNum = attribToNum[italicAttrKey];
533
+ if (italicAttrNum === void 0) {
534
+ italicAttrNum = apoolNextNum;
535
+ apoolNextNum++;
536
+ apoolNumToAttrib[italicAttrNum.toString()] = ["italic", "true"];
537
+ attribToNum[italicAttrKey] = italicAttrNum;
538
+ }
539
+ activeAttrs.push(italicAttrNum.toString());
540
+ }
541
+ if (segment.underline) {
542
+ const underlineAttrKey = "underline,true";
543
+ let underlineAttrNum = attribToNum[underlineAttrKey];
544
+ if (underlineAttrNum === void 0) {
545
+ underlineAttrNum = apoolNextNum;
546
+ apoolNextNum++;
547
+ apoolNumToAttrib[underlineAttrNum.toString()] = ["underline", "true"];
548
+ attribToNum[underlineAttrKey] = underlineAttrNum;
549
+ }
550
+ activeAttrs.push(underlineAttrNum.toString());
551
+ }
552
+ if (segment.strikethrough) {
553
+ const strikeAttrKey = "strikethrough,true";
554
+ let strikeAttrNum = attribToNum[strikeAttrKey];
555
+ if (strikeAttrNum === void 0) {
556
+ strikeAttrNum = apoolNextNum;
557
+ apoolNextNum++;
558
+ apoolNumToAttrib[strikeAttrNum.toString()] = ["strikethrough", "true"];
559
+ attribToNum[strikeAttrKey] = strikeAttrNum;
560
+ }
561
+ activeAttrs.push(strikeAttrNum.toString());
562
+ }
563
+ if (segment.equation) {
564
+ const eqAttrNum = apoolNextNum.toString();
565
+ apoolNextNum++;
566
+ apoolNumToAttrib[eqAttrNum] = ["equation", segment.equation];
567
+ attribToNum[`equation,${segment.equation}`] = parseInt(eqAttrNum);
568
+ activeAttrs.push(eqAttrNum);
569
+ }
570
+ const attrsPart = activeAttrs.join("*");
571
+ attribParts.push(`*${attrsPart}+${length}`);
572
+ }
573
+ const fullText = textParts.join("");
574
+ const attribsStr = attribParts.join("");
575
+ return {
576
+ apool: {
577
+ nextNum: apoolNextNum,
578
+ numToAttrib: apoolNumToAttrib,
579
+ attribToNum
580
+ },
581
+ initialAttributedTexts: {
582
+ attribs: { "0": attribsStr },
583
+ text: { "0": fullText },
584
+ rows: {},
585
+ cols: {}
586
+ }
587
+ };
588
+ }
589
+ createListItemTextData(segments) {
590
+ if (!segments || segments.length === 0) {
591
+ return {
592
+ apool: { nextNum: 0, numToAttrib: {} },
593
+ initialAttributedTexts: {
594
+ attribs: "",
595
+ text: { "0": "" },
596
+ rows: {},
597
+ cols: {}
598
+ }
599
+ };
600
+ }
601
+ const apoolNumToAttrib = {
602
+ "0": ["author", this.authorId]
603
+ };
604
+ const attribToNum = {
605
+ [`author,${this.authorId}`]: 0
606
+ };
607
+ let apoolNextNum = 1;
608
+ const attribParts = [];
609
+ const textParts = [];
610
+ for (const segment of segments) {
611
+ const text = segment.text || "";
612
+ const length = text.length;
613
+ if (length === 0) continue;
614
+ textParts.push(text);
615
+ const activeAttrs = ["0"];
616
+ if (segment.linkUrl) {
617
+ const linkAttrNum = apoolNextNum.toString();
618
+ apoolNextNum++;
619
+ const encodedUrl = encodeURIComponent(segment.linkUrl);
620
+ apoolNumToAttrib[linkAttrNum] = ["link", encodedUrl];
621
+ attribToNum[`link,${encodedUrl}`] = parseInt(linkAttrNum);
622
+ activeAttrs.push(linkAttrNum);
623
+ }
624
+ if (segment.bold) {
625
+ const boldAttrKey = "bold,true";
626
+ let boldAttrNum = attribToNum[boldAttrKey];
627
+ if (boldAttrNum === void 0) {
628
+ boldAttrNum = apoolNextNum;
629
+ apoolNextNum++;
630
+ apoolNumToAttrib[boldAttrNum.toString()] = ["bold", "true"];
631
+ attribToNum[boldAttrKey] = boldAttrNum;
632
+ }
633
+ activeAttrs.push(boldAttrNum.toString());
634
+ }
635
+ if (segment.italic) {
636
+ const italicAttrKey = "italic,true";
637
+ let italicAttrNum = attribToNum[italicAttrKey];
638
+ if (italicAttrNum === void 0) {
639
+ italicAttrNum = apoolNextNum;
640
+ apoolNextNum++;
641
+ apoolNumToAttrib[italicAttrNum.toString()] = ["italic", "true"];
642
+ attribToNum[italicAttrKey] = italicAttrNum;
643
+ }
644
+ activeAttrs.push(italicAttrNum.toString());
645
+ }
646
+ if (segment.underline) {
647
+ const underlineAttrKey = "underline,true";
648
+ let underlineAttrNum = attribToNum[underlineAttrKey];
649
+ if (underlineAttrNum === void 0) {
650
+ underlineAttrNum = apoolNextNum;
651
+ apoolNextNum++;
652
+ apoolNumToAttrib[underlineAttrNum.toString()] = ["underline", "true"];
653
+ attribToNum[underlineAttrKey] = underlineAttrNum;
654
+ }
655
+ activeAttrs.push(underlineAttrNum.toString());
656
+ }
657
+ if (segment.strikethrough) {
658
+ const strikeAttrKey = "strikethrough,true";
659
+ let strikeAttrNum = attribToNum[strikeAttrKey];
660
+ if (strikeAttrNum === void 0) {
661
+ strikeAttrNum = apoolNextNum;
662
+ apoolNextNum++;
663
+ apoolNumToAttrib[strikeAttrNum.toString()] = ["strikethrough", "true"];
664
+ attribToNum[strikeAttrKey] = strikeAttrNum;
665
+ }
666
+ activeAttrs.push(strikeAttrNum.toString());
667
+ }
668
+ if (segment.equation) {
669
+ const eqAttrNum = apoolNextNum.toString();
670
+ apoolNextNum++;
671
+ apoolNumToAttrib[eqAttrNum] = ["equation", segment.equation];
672
+ attribToNum[`equation,${segment.equation}`] = parseInt(eqAttrNum);
673
+ activeAttrs.push(eqAttrNum);
674
+ }
675
+ const attrsPart = activeAttrs.join("*");
676
+ attribParts.push(`*${attrsPart}+${length}`);
677
+ }
678
+ const fullText = textParts.join("");
679
+ const attribsStr = attribParts.join("");
680
+ return {
681
+ apool: {
682
+ nextNum: apoolNextNum,
683
+ numToAttrib: apoolNumToAttrib,
684
+ attribToNum
685
+ },
686
+ initialAttributedTexts: {
687
+ attribs: { "0": attribsStr },
688
+ text: { "0": fullText },
689
+ rows: {},
690
+ cols: {}
691
+ }
692
+ };
693
+ }
694
+ buildClipboardData() {
695
+ const data = {
696
+ isCut: false,
697
+ rootId: this.rootId,
698
+ parentId: this.rootId,
699
+ blockIds: this.blockIds,
700
+ recordIds: this.recordIds,
701
+ recordMap: this.recordMap,
702
+ payloadMap: {},
703
+ selection: [],
704
+ extra: {
705
+ channel: "saas",
706
+ pasteRandomId: this.generateRandomId(),
707
+ mention_page_title: {},
708
+ external_mention_url: {},
709
+ isEqualBlockSelection: true
710
+ },
711
+ isKeepQuoteContainer: false,
712
+ pasteFlag: this.generateRandomId()
713
+ };
714
+ return data;
715
+ }
716
+ generateRandomId() {
717
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
718
+ const r = Math.random() * 16 | 0;
719
+ const v = c === "x" ? r : r & 3 | 8;
720
+ return v.toString(16);
721
+ });
722
+ }
723
+ convertTable(tableNode) {
724
+ const tableRecordId = generateRecordId();
725
+ const children = tableNode.children;
726
+ if (!children || children.length === 0) {
727
+ return { tableId: tableRecordId };
728
+ }
729
+ const alignments = tableNode.align || [];
730
+ const rows = children;
731
+ const columnIds = [];
732
+ const rowIds = [];
733
+ const columnSet = {};
734
+ const cellSet = {};
735
+ const tableCellIds = [];
736
+ const numCols = alignments.length || rows[0]?.children?.length || 0;
737
+ const numRows = rows.length;
738
+ for (let i = 0; i < numCols; i++) {
739
+ const colId = `col${this.generateRandomId().replace(/-/g, "")}`;
740
+ columnIds.push(colId);
741
+ columnSet[colId] = { column_width: 200 };
742
+ }
743
+ for (let i = 0; i < numRows; i++) {
744
+ const rowId = `row${this.generateRandomId().replace(/-/g, "")}`;
745
+ rowIds.push(rowId);
746
+ }
747
+ const processRow = (rowIndex, rowCells) => {
748
+ const rowId = rowIds[rowIndex];
749
+ for (let colIndex = 0; colIndex < rowCells.length && colIndex < numCols; colIndex++) {
750
+ const colId = columnIds[colIndex];
751
+ const cellNode = rowCells[colIndex];
752
+ const cellRecordId = generateRecordId();
753
+ const cellTextSegments = this.parseInlineContent(cellNode.children || []);
754
+ const align = alignments[colIndex] || "left";
755
+ this.recordMap[cellRecordId] = {
756
+ id: cellRecordId,
757
+ snapshot: {
758
+ type: "table_cell",
759
+ parent_id: tableRecordId,
760
+ comments: [],
761
+ revisions: [],
762
+ locked: false,
763
+ hidden: false,
764
+ author: this.authorId,
765
+ children: [],
766
+ text: this.createTextData(cellTextSegments)
767
+ }
768
+ };
769
+ const textRecordId = generateRecordId();
770
+ this.recordMap[textRecordId] = {
771
+ id: textRecordId,
772
+ snapshot: {
773
+ type: "text",
774
+ parent_id: cellRecordId,
775
+ comments: [],
776
+ revisions: [],
777
+ locked: false,
778
+ hidden: false,
779
+ author: this.authorId,
780
+ children: [],
781
+ text: this.createTextData(cellTextSegments),
782
+ folded: false,
783
+ align
784
+ }
785
+ };
786
+ this.recordMap[cellRecordId].snapshot.children.push(textRecordId);
787
+ const cellKey = `${rowId}${colId}`;
788
+ cellSet[cellKey] = {
789
+ block_id: cellRecordId,
790
+ merge_info: { row_span: 1, col_span: 1 }
791
+ };
792
+ tableCellIds.push(cellRecordId);
793
+ }
794
+ };
795
+ for (let i = 0; i < rows.length; i++) {
796
+ processRow(i, rows[i].children);
797
+ }
798
+ this.recordMap[tableRecordId] = {
799
+ id: tableRecordId,
800
+ snapshot: {
801
+ type: "table",
802
+ parent_id: this.rootId,
803
+ comments: [],
804
+ revisions: [],
805
+ locked: false,
806
+ hidden: false,
807
+ author: this.authorId,
808
+ children: tableCellIds,
809
+ columns_id: columnIds,
810
+ rows_id: rowIds,
811
+ column_set: columnSet,
812
+ cell_set: cellSet
813
+ }
814
+ };
815
+ this.recordIds.push(tableRecordId);
816
+ this.blockIds.push(this.blockIds.length + 1);
817
+ return { tableId: tableRecordId };
818
+ }
819
+ };
820
+
821
+ // src/parser/markdownParser.ts
822
+ import { marked } from "marked";
823
+ function parseMarkdown(markdown) {
824
+ const tokens = marked.lexer(markdown);
825
+ return convertTokens(tokens);
826
+ }
827
+ function convertTokens(tokens, parentType = null) {
828
+ const blocks = [];
829
+ for (const token of tokens) {
830
+ const block = convertToken(token, parentType);
831
+ if (Array.isArray(block)) {
832
+ blocks.push(...block);
833
+ } else if (block) {
834
+ blocks.push(block);
835
+ }
836
+ }
837
+ return blocks;
838
+ }
839
+ function convertToken(token, parentType) {
840
+ const { type, raw, text, depth, items, code, lang } = token;
841
+ switch (type) {
842
+ case "heading":
843
+ return {
844
+ type: `heading${depth}`,
845
+ text: parseInlineText(text)
846
+ };
847
+ case "paragraph":
848
+ return {
849
+ type: "text",
850
+ text: parseInlineText(text)
851
+ };
852
+ case "blockquote":
853
+ return {
854
+ type: "quote",
855
+ text: parseInlineText(text)
856
+ };
857
+ case "list":
858
+ return {
859
+ type: "list",
860
+ ordered: token.ordered,
861
+ items: items.map((item) => ({
862
+ text: parseInlineText(item.text),
863
+ task: item.checked !== void 0,
864
+ checked: item.checked
865
+ }))
866
+ };
867
+ case "code":
868
+ return {
869
+ type: "code",
870
+ language: lang || "plaintext",
871
+ text: code
872
+ };
873
+ case "hr":
874
+ return {
875
+ type: "divider"
876
+ };
877
+ case "space":
878
+ return null;
879
+ default:
880
+ return null;
881
+ }
882
+ }
883
+ function parseInlineText(text) {
884
+ if (!text) return "";
885
+ const inlineTokens = marked.lexerInline(text);
886
+ return convertInlineTokens(inlineTokens);
887
+ }
888
+ function convertInlineTokens(tokens) {
889
+ let result = "";
890
+ for (const token of tokens) {
891
+ switch (token.type) {
892
+ case "text":
893
+ result += token.raw;
894
+ break;
895
+ case "strong":
896
+ result += `**${token.text}**`;
897
+ break;
898
+ case "em":
899
+ result += `*${token.text}*`;
900
+ break;
901
+ case "del":
902
+ result += `~~${token.text}~~`;
903
+ break;
904
+ case "codespan":
905
+ result += `\`${token.text}\``;
906
+ break;
907
+ case "link":
908
+ result += `[$(token as any).text}](${token.href})`;
909
+ break;
910
+ case "image":
911
+ result += `![${token.text}](${token.href})`;
912
+ break;
913
+ default:
914
+ result += token.raw || "";
915
+ }
916
+ }
917
+ return result;
918
+ }
919
+
920
+ // src/clipboard/browserClipboard.ts
921
+ async function writeToClipboard(html, jsonData) {
922
+ try {
923
+ const plainText = extractPlainTextFromData(jsonData);
924
+ const clipboardItem = new ClipboardItem({
925
+ "text/html": new Blob([html], { type: "text/html" }),
926
+ "text/plain": new Blob([plainText], { type: "text/plain" })
927
+ });
928
+ await navigator.clipboard.write([clipboardItem]);
929
+ return true;
930
+ } catch (error) {
931
+ console.error("Failed to write to clipboard:", error);
932
+ throw new Error(`\u5199\u5165\u526A\u8D34\u677F\u5931\u8D25: ${error.message}`);
933
+ }
934
+ }
935
+ function extractPlainTextFromData(data) {
936
+ let text = "";
937
+ for (const recordId of data.recordIds) {
938
+ const record = data.recordMap[recordId];
939
+ if (!record) continue;
940
+ const snapshot = record.snapshot;
941
+ const type = snapshot.type;
942
+ if (type === "isv") {
943
+ text += "[Mermaid \u56FE\u8868]\n";
944
+ } else if (type === "code") {
945
+ text += `\`\`\`${snapshot.language || "text"}
946
+ ${snapshot.code}
947
+ \`\`\`
948
+ `;
949
+ } else if (type === "divider") {
950
+ text += "---\n";
951
+ } else if (type.startsWith("heading")) {
952
+ const level = parseInt(type.replace("heading", ""));
953
+ text += `${"#".repeat(level)} ${getTextContent(snapshot.text)}
954
+
955
+ `;
956
+ } else if (type === "text" || type === "quote") {
957
+ text += `${getTextContent(snapshot.text)}
958
+
959
+ `;
960
+ } else if (type === "bullet" || type === "ordered" || type === "todo") {
961
+ const marker = type === "bullet" ? "-" : type === "ordered" ? "1." : snapshot.checked ? "- [x]" : "- [ ]";
962
+ text += `${marker} ${getTextContent(snapshot.text)}
963
+ `;
964
+ }
965
+ }
966
+ return text.trim();
967
+ }
968
+ function getTextContent(textData) {
969
+ if (!textData || !textData.initialAttributedTexts) {
970
+ return "";
971
+ }
972
+ const texts = textData.initialAttributedTexts.text;
973
+ return Object.values(texts).join("");
974
+ }
975
+ async function readClipboard() {
976
+ try {
977
+ const clipboardItems = await navigator.clipboard.read();
978
+ const results = {};
979
+ for (const item of clipboardItems) {
980
+ for (const type of item.types) {
981
+ const blob = await item.getType(type);
982
+ if (type.startsWith("text/")) {
983
+ const text = await blob.text();
984
+ results[type] = text;
985
+ }
986
+ }
987
+ }
988
+ return results;
989
+ } catch (error) {
990
+ console.error("Failed to read clipboard:", error);
991
+ throw new Error(`\u8BFB\u53D6\u526A\u8D34\u677F\u5931\u8D25: ${error.message}`);
992
+ }
993
+ }
994
+
995
+ // src/htmlGenerator.ts
996
+ function generateHtml(data) {
997
+ if (!data || !data.recordIds || !data.recordMap) {
998
+ console.error("Invalid data structure:", data);
999
+ return "";
1000
+ }
1001
+ const jsonStr = JSON.stringify(data);
1002
+ const encodedJson = jsonStr.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1003
+ let html = `<meta charset="utf-8"><div data-page-id="${data.rootId}" data-lark-html-role="root" data-docx-has-block-data="true">`;
1004
+ for (const recordId of data.recordIds) {
1005
+ const record = data.recordMap[recordId];
1006
+ if (!record) continue;
1007
+ const snapshot = record.snapshot;
1008
+ const blockHtml = generateBlockHtml(snapshot, recordId);
1009
+ html += blockHtml;
1010
+ }
1011
+ html += `</div><span data-lark-record-data="${encodedJson}" data-lark-record-format="docx/record" class="lark-record-clipboard"></span>`;
1012
+ return html;
1013
+ }
1014
+ function generateBlockHtml(snapshot, recordId) {
1015
+ const { type, text, code, language, level, data, checked, children } = snapshot;
1016
+ switch (type) {
1017
+ case "page":
1018
+ return "";
1019
+ case "isv":
1020
+ const mermaidCode = data && data.data ? data.data : "";
1021
+ return `<div class="ace-line old-record-id-${recordId}">
1022
+ <span class="block-paste-placeholder">${mermaidCode || "\u6682\u65F6\u65E0\u6CD5\u5728\u98DE\u4E66\u6587\u6863\u5916\u5C55\u793A\u6B64\u5185\u5BB9"}</span>
1023
+ </div>`;
1024
+ case "heading1":
1025
+ const text1 = getTextContent2(text);
1026
+ return `<h1 class="heading-1 ace-line old-record-id-${recordId}">${escapeHtml(text1)}</h1>`;
1027
+ case "heading2":
1028
+ const text2 = getTextContent2(text);
1029
+ return `<h2 class="heading-2 ace-line old-record-id-${recordId}">${escapeHtml(text2)}</h2>`;
1030
+ case "heading3":
1031
+ const text3 = getTextContent2(text);
1032
+ return `<h3 class="heading-3 ace-line old-record-id-${recordId}">${escapeHtml(text3)}</h3>`;
1033
+ case "heading4":
1034
+ const text4 = getTextContent2(text);
1035
+ return `<h4 class="heading-4 ace-line old-record-id-${recordId}">${escapeHtml(text4)}</h4>`;
1036
+ case "heading5":
1037
+ const text5 = getTextContent2(text);
1038
+ return `<h5 class="heading-5 ace-line old-record-id-${recordId}">${escapeHtml(text5)}</h5>`;
1039
+ case "heading6":
1040
+ const text6 = getTextContent2(text);
1041
+ return `<h6 class="heading-6 ace-line old-record-id-${recordId}">${escapeHtml(text6)}</h6>`;
1042
+ case "text":
1043
+ const textContent = getTextContent2(text);
1044
+ return `<div class="ace-line old-record-id-${recordId}">${escapeHtml(textContent)}</div>`;
1045
+ case "quote":
1046
+ const quoteText = getTextContent2(text);
1047
+ return `<blockquote class="ace-line old-record-id-${recordId}">${escapeHtml(quoteText)}</blockquote>`;
1048
+ case "code":
1049
+ const codeContent = code || getTextContent2(text) || "";
1050
+ const escapedCode = escapeHtml(codeContent);
1051
+ return `<pre style="white-space:pre;" class="ace-line old-record-id-${recordId}"><code class="language-${language || "plaintext"}" data-lark-language="${language || "plaintext"}" data-wrap="false"><div>${escapedCode}</div></code></pre>`;
1052
+ case "divider":
1053
+ return `<div data-type="divider" class="old-record-id-${recordId}"><hr></div>`;
1054
+ case "bullet":
1055
+ const bulletText = getTextContent2(text);
1056
+ return `<ul class="list-bullet1"><li class="ace-line old-record-id-${recordId}" data-list="bullet"><div>${escapeHtml(bulletText)}</div></li></ul>`;
1057
+ case "ordered":
1058
+ const orderedText = getTextContent2(text);
1059
+ return `<ol class="list-number1"><li class="ace-line old-record-id-${recordId}" data-list="number"><div>${escapeHtml(orderedText)}</div></li></ol>`;
1060
+ case "todo":
1061
+ const todoText = getTextContent2(text);
1062
+ const isChecked = snapshot.done || false;
1063
+ const listClass = isChecked ? "list-done1" : "list-check";
1064
+ return `<ul class="${listClass}"><li class="ace-line old-record-id-${recordId}" data-list="${isChecked ? "done" : "check"}"><div>${escapeHtml(todoText)}</div></li></ul>`;
1065
+ case "image":
1066
+ return `<div class="ace-line old-record-id-${recordId}">[markdown-to-lark \u6682\u65E0\u6CD5\u652F\u6301\u56FE\u7247\u8F6C\u6362]</div>`;
1067
+ default:
1068
+ return "";
1069
+ }
1070
+ }
1071
+ function getTextContent2(textData) {
1072
+ if (!textData || !textData.initialAttributedTexts) {
1073
+ return "";
1074
+ }
1075
+ const texts = textData.initialAttributedTexts.text;
1076
+ if (!texts) return "";
1077
+ return Object.values(texts).join("");
1078
+ }
1079
+ function escapeHtml(text) {
1080
+ if (typeof text !== "string" || !text) return "";
1081
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
1082
+ }
1083
+
1084
+ // src/index.ts
1085
+ async function markdownToLark(markdown) {
1086
+ const converter = new MarkdownToLarkConverter();
1087
+ return converter.convert(markdown);
1088
+ }
1089
+ function larkToMarkdown(data) {
1090
+ if (!data || !data.recordMap) {
1091
+ return "";
1092
+ }
1093
+ const result = [];
1094
+ let lastType = "";
1095
+ function processRecord(recordId, depth = 0) {
1096
+ const record = data.recordMap[recordId];
1097
+ if (!record || !record.snapshot) return;
1098
+ const snapshot = record.snapshot;
1099
+ if (snapshot.type === "page") {
1100
+ if (snapshot.children && snapshot.children.length > 0) {
1101
+ for (const childId of snapshot.children) {
1102
+ processRecord(childId);
1103
+ }
1104
+ }
1105
+ return;
1106
+ }
1107
+ const isList = ["bullet", "ordered", "todo"].includes(snapshot.type);
1108
+ if (result.length > 0) {
1109
+ if (lastType !== snapshot.type && lastType !== "list" && !isList) {
1110
+ result.push("");
1111
+ } else if (lastType === "text" && snapshot.type === "text") {
1112
+ result.push("");
1113
+ } else if (lastType === "list" && !isList) {
1114
+ result.push("");
1115
+ } else if (!isList && lastType !== "list" && !isList) {
1116
+ result.push("");
1117
+ }
1118
+ }
1119
+ switch (snapshot.type) {
1120
+ case "heading1":
1121
+ case "heading2":
1122
+ case "heading3":
1123
+ case "heading4":
1124
+ case "heading5":
1125
+ case "heading6": {
1126
+ const level = parseInt(snapshot.type.replace("heading", ""));
1127
+ const headingText = getTextContent3(snapshot.text);
1128
+ result.push(`${"#".repeat(level)} ${headingText}`);
1129
+ break;
1130
+ }
1131
+ case "text": {
1132
+ const textContent = getTextContent3(snapshot.text);
1133
+ if (textContent.trim()) {
1134
+ result.push(textContent);
1135
+ }
1136
+ break;
1137
+ }
1138
+ case "quote": {
1139
+ const quoteText = getTextContent3(snapshot.text);
1140
+ result.push(`> ${quoteText}`);
1141
+ break;
1142
+ }
1143
+ case "bullet": {
1144
+ const bulletText = getTextContent3(snapshot.text);
1145
+ const level = snapshot.level || 1;
1146
+ const indent = " ".repeat(level - 1);
1147
+ result.push(`${indent}- ${bulletText}`);
1148
+ break;
1149
+ }
1150
+ case "ordered": {
1151
+ const orderedText = getTextContent3(snapshot.text);
1152
+ const level = snapshot.level || 1;
1153
+ const indent = " ".repeat(level - 1);
1154
+ result.push(`${indent}1. ${orderedText}`);
1155
+ break;
1156
+ }
1157
+ case "todo": {
1158
+ const todoText = getTextContent3(snapshot.text);
1159
+ const isChecked = snapshot.done || false;
1160
+ const level = snapshot.level || 1;
1161
+ const indent = " ".repeat(level - 1);
1162
+ result.push(`${indent}- [${isChecked ? "x" : " "}] ${todoText}`);
1163
+ break;
1164
+ }
1165
+ case "code": {
1166
+ const language = snapshot.language || "";
1167
+ const code = snapshot.code || getTextContent3(snapshot.text) || "";
1168
+ result.push(`\`\`\`${language}`);
1169
+ result.push(code);
1170
+ result.push(`\`\`\``);
1171
+ break;
1172
+ }
1173
+ case "divider": {
1174
+ result.push("---");
1175
+ break;
1176
+ }
1177
+ case "isv": {
1178
+ const mermaidCode = snapshot.data?.data || "";
1179
+ result.push(`\`\`\`mermaid`);
1180
+ result.push(mermaidCode);
1181
+ result.push(`\`\`\``);
1182
+ break;
1183
+ }
1184
+ case "equation": {
1185
+ result.push(`$$${getTextContent3(snapshot.text)}$$`);
1186
+ break;
1187
+ }
1188
+ case "image": {
1189
+ result.push("[lark-to-markdown \u6682\u65E0\u6CD5\u652F\u6301\u56FE\u7247\u8F6C\u6362]");
1190
+ break;
1191
+ }
1192
+ case "table": {
1193
+ const tableMarkdown = convertTableToMarkdown(recordId, data.recordMap);
1194
+ result.push(tableMarkdown);
1195
+ break;
1196
+ }
1197
+ case "table_cell": {
1198
+ return;
1199
+ }
1200
+ default:
1201
+ break;
1202
+ }
1203
+ lastType = isList ? "list" : snapshot.type;
1204
+ if (snapshot.children && snapshot.children.length > 0) {
1205
+ for (const childId of snapshot.children) {
1206
+ processRecord(childId);
1207
+ }
1208
+ }
1209
+ }
1210
+ if (data.rootId) {
1211
+ processRecord(data.rootId);
1212
+ }
1213
+ return result.join("\n").trim();
1214
+ }
1215
+ function getTextContent3(textData) {
1216
+ if (!textData || !textData.initialAttributedTexts) {
1217
+ return "";
1218
+ }
1219
+ const texts = textData.initialAttributedTexts.text;
1220
+ const attribs = textData.initialAttributedTexts.attribs;
1221
+ if (!texts) return "";
1222
+ if (!attribs || typeof attribs === "string" && attribs === "" || !textData.apool || !textData.apool.numToAttrib) {
1223
+ const content = Object.values(texts).join("");
1224
+ const placeholders = [];
1225
+ let result = content.replace(
1226
+ /\[([^\]]+)\]\(([^)]+)\)/g,
1227
+ (match, text, url) => {
1228
+ placeholders.push(match);
1229
+ return `__LINK_PLACEHOLDER_${placeholders.length - 1}__`;
1230
+ }
1231
+ );
1232
+ result = result.replace(
1233
+ /(https?:\/\/[^\s<>"{}|\\^`\[\]]+)/g,
1234
+ "[$1]($1)"
1235
+ );
1236
+ result = result.replace(
1237
+ /__LINK_PLACEHOLDER_(\d+)__/g,
1238
+ (_, index) => placeholders[parseInt(index)]
1239
+ );
1240
+ return result;
1241
+ }
1242
+ let attribsStr = "";
1243
+ if (typeof attribs === "string") {
1244
+ attribsStr = attribs;
1245
+ } else if (attribs && typeof attribs === "object") {
1246
+ const values = Object.values(attribs);
1247
+ if (values.length > 0 && typeof values[0] === "string") {
1248
+ attribsStr = values[0];
1249
+ }
1250
+ }
1251
+ return parseAttributedText(texts, attribsStr, textData.apool.numToAttrib);
1252
+ }
1253
+ function convertTableToMarkdown(tableRecordId, recordMap) {
1254
+ const tableRecord = recordMap[tableRecordId];
1255
+ if (!tableRecord || !tableRecord.snapshot) {
1256
+ return "";
1257
+ }
1258
+ const snapshot = tableRecord.snapshot;
1259
+ const { columns_id, rows_id, cell_set } = snapshot;
1260
+ if (!columns_id || !rows_id || !cell_set) {
1261
+ return "";
1262
+ }
1263
+ const rows = [];
1264
+ for (const rowId of rows_id) {
1265
+ const row = [];
1266
+ for (const colId of columns_id) {
1267
+ const cellKey = `${rowId}${colId}`;
1268
+ const cell = cell_set[cellKey];
1269
+ if (cell && cell.block_id) {
1270
+ const cellRecord = recordMap[cell.block_id];
1271
+ if (cellRecord && cellRecord.snapshot) {
1272
+ const cellSnapshot = cellRecord.snapshot;
1273
+ const childId = cellSnapshot.children && cellSnapshot.children.length > 0 ? cellSnapshot.children[0] : null;
1274
+ if (childId) {
1275
+ const textRecord = recordMap[childId];
1276
+ if (textRecord && textRecord.snapshot) {
1277
+ const cellText = getTextContent3(textRecord.snapshot.text);
1278
+ row.push(cellText);
1279
+ } else {
1280
+ row.push("");
1281
+ }
1282
+ } else {
1283
+ row.push("");
1284
+ }
1285
+ } else {
1286
+ row.push("");
1287
+ }
1288
+ } else {
1289
+ row.push("");
1290
+ }
1291
+ }
1292
+ rows.push(row);
1293
+ }
1294
+ if (rows.length === 0) {
1295
+ return "";
1296
+ }
1297
+ const colCount = columns_id.length;
1298
+ const alignments = [];
1299
+ for (const colId of columns_id) {
1300
+ const cellKey = `${rows_id[0]}${colId}`;
1301
+ const cell = cell_set[cellKey];
1302
+ if (cell && cell.block_id) {
1303
+ const cellRecord = recordMap[cell.block_id];
1304
+ if (cellRecord && cellRecord.snapshot) {
1305
+ const cellSnapshot = cellRecord.snapshot;
1306
+ const childId = cellSnapshot.children && cellSnapshot.children.length > 0 ? cellSnapshot.children[0] : null;
1307
+ if (childId) {
1308
+ const textRecord = recordMap[childId];
1309
+ if (textRecord && textRecord.snapshot && textRecord.snapshot.align) {
1310
+ const align = textRecord.snapshot.align;
1311
+ alignments.push(align);
1312
+ } else {
1313
+ alignments.push("left");
1314
+ }
1315
+ } else {
1316
+ alignments.push("left");
1317
+ }
1318
+ } else {
1319
+ alignments.push("left");
1320
+ }
1321
+ } else {
1322
+ alignments.push("left");
1323
+ }
1324
+ }
1325
+ const separatorRow = alignments.map((align) => {
1326
+ switch (align) {
1327
+ case "center":
1328
+ return ":--:";
1329
+ case "right":
1330
+ return "---:";
1331
+ case "left":
1332
+ default:
1333
+ return ":---";
1334
+ }
1335
+ });
1336
+ const markdownRows = [];
1337
+ for (let i = 0; i < rows.length; i++) {
1338
+ const row = rows[i];
1339
+ const formattedRow = row.map((cell) => {
1340
+ return cell.includes("|") ? `"${cell.replace(/"/g, '""')}"` : cell;
1341
+ }).join(" | ");
1342
+ markdownRows.push(`| ${formattedRow} |`);
1343
+ if (i === 0) {
1344
+ markdownRows.push(`| ${separatorRow.join(" | ")} |`);
1345
+ }
1346
+ }
1347
+ return markdownRows.join("\n");
1348
+ }
1349
+ function parseAttributedText(texts, attribsStr, numToAttrib) {
1350
+ let content = Object.values(texts).join("");
1351
+ const segments = [];
1352
+ let pos = 0;
1353
+ while (pos < attribsStr.length) {
1354
+ if (attribsStr[pos] === "*") {
1355
+ pos++;
1356
+ const attrNums = [];
1357
+ while (pos < attribsStr.length && /[0-9]/.test(attribsStr[pos])) {
1358
+ let numStr = "";
1359
+ while (pos < attribsStr.length && /[0-9]/.test(attribsStr[pos])) {
1360
+ numStr += attribsStr[pos];
1361
+ pos++;
1362
+ }
1363
+ attrNums.push(numStr);
1364
+ if (pos < attribsStr.length && attribsStr[pos] === "*") {
1365
+ pos++;
1366
+ } else {
1367
+ break;
1368
+ }
1369
+ }
1370
+ if (pos >= attribsStr.length || attribsStr[pos] !== "+") break;
1371
+ pos++;
1372
+ let lengthStr = "";
1373
+ while (pos < attribsStr.length) {
1374
+ const char = attribsStr[pos];
1375
+ if (/[0-9]/.test(char)) {
1376
+ lengthStr += char;
1377
+ pos++;
1378
+ } else {
1379
+ break;
1380
+ }
1381
+ }
1382
+ if (!lengthStr) {
1383
+ continue;
1384
+ }
1385
+ const length = parseInt(lengthStr, 10) || 0;
1386
+ const text = content.substring(0, length);
1387
+ content = content.substring(length);
1388
+ const attrs = {};
1389
+ for (const num of attrNums) {
1390
+ const attrValue = numToAttrib[num];
1391
+ if (attrValue && Array.isArray(attrValue) && attrValue.length >= 2) {
1392
+ attrs[String(attrValue[0])] = attrValue[1];
1393
+ }
1394
+ }
1395
+ if (text) {
1396
+ segments.push({ text, attrs });
1397
+ }
1398
+ } else {
1399
+ pos++;
1400
+ }
1401
+ }
1402
+ if (content) {
1403
+ segments.push({ text: content, attrs: {} });
1404
+ }
1405
+ let result = "";
1406
+ for (const segment of segments) {
1407
+ const { text, attrs } = segment;
1408
+ if (attrs.link) {
1409
+ const url = decodeURIComponent(String(attrs.link));
1410
+ result += `[${text}](${url})`;
1411
+ } else if (attrs.equation) {
1412
+ const equation = String(attrs.equation).trim();
1413
+ const isDisplay = equation.endsWith("_display");
1414
+ const cleanEquation = isDisplay ? equation.slice(0, -8) : equation;
1415
+ result += isDisplay ? `$$${cleanEquation}$$` : `$${cleanEquation}$`;
1416
+ } else {
1417
+ let formattedText = text;
1418
+ if (attrs.strikethrough === "true") {
1419
+ formattedText = `~~${formattedText}~~`;
1420
+ }
1421
+ if (attrs.bold === "true") {
1422
+ formattedText = `**${formattedText}**`;
1423
+ }
1424
+ if (attrs.italic === "true") {
1425
+ formattedText = `*${formattedText}*`;
1426
+ }
1427
+ result += formattedText;
1428
+ }
1429
+ }
1430
+ return result;
1431
+ }
1432
+ var TEST_CASES = {
1433
+ heading: `# \u4E00\u7EA7\u6807\u9898
1434
+ ## \u4E8C\u7EA7\u6807\u9898
1435
+ ### \u4E09\u7EA7\u6807\u9898
1436
+ `,
1437
+ paragraph: `\u8FD9\u662F\u666E\u901A\u6587\u672C\u6BB5\u843D\u3002
1438
+
1439
+ \u8FD9\u662F\u7B2C\u4E8C\u6BB5\u3002`,
1440
+ list: `- \u9879\u76EE 1
1441
+ - \u9879\u76EE 2
1442
+ - \u9879\u76EE 3
1443
+ `,
1444
+ ordered: `1. \u7B2C\u4E00\u9879
1445
+ 2. \u7B2C\u4E8C\u9879
1446
+ 3. \u7B2C\u4E09\u9879
1447
+ `,
1448
+ todo: `- [ ] \u672A\u5B8C\u6210\u4EFB\u52A1
1449
+ - [x] \u5DF2\u5B8C\u6210\u4EFB\u52A1
1450
+ `,
1451
+ quote: `> \u8FD9\u662F\u4E00\u6BB5\u5F15\u7528\u6587\u672C\u3002
1452
+
1453
+ > \u591A\u884C\u5F15\u7528\u3002`,
1454
+ code: `\`\`\`javascript
1455
+ function hello() {
1456
+ console.log('Hello');
1457
+ }
1458
+ \`\`\``,
1459
+ divider: `---
1460
+ `,
1461
+ link: `\u8FD9\u662F\u4E00\u4E2A [\u94FE\u63A5](https://feishu.cn)\u3002
1462
+ `,
1463
+ image: `![\u56FE\u7247](https://example.com/img.png)
1464
+ `,
1465
+ mermaid: `\`\`\`mermaid
1466
+ graph TD
1467
+ A[\u5F00\u59CB] --> B[\u7ED3\u675F]
1468
+ \`\`\``,
1469
+ nested: `- \u4E00\u7EA7\u9879\u76EE
1470
+ - \u4E8C\u7EA7\u9879\u76EE
1471
+ - \u4E09\u7EA7\u9879\u76EE
1472
+ `,
1473
+ mixed: `# \u6807\u9898
1474
+
1475
+ \u8FD9\u662F\u6BB5\u843D\uFF0C\u5305\u542B**\u7C97\u4F53**\u548C*\u659C\u4F53*\u3002
1476
+
1477
+ - \u5217\u8868\u9879
1478
+ - \u53E6\u4E00\u9879
1479
+
1480
+ \`\`\`\u4EE3\u7801\`\`\``,
1481
+ complex: `# \u5B8C\u6574\u6587\u6863
1482
+
1483
+ ## \u7AE0\u8282
1484
+
1485
+ \u8FD9\u662F\u6BB5\u843D\u3002
1486
+
1487
+ - \u5217\u8868\u9879 1
1488
+ - \u5217\u8868\u9879 2
1489
+
1490
+
1491
+ > \u5F15\u7528\u5757
1492
+
1493
+ \`\`\`javascript
1494
+ const a = 1;
1495
+ \`\`\`
1496
+
1497
+ ---
1498
+
1499
+ ## \u4E0B\u4E00\u4E2A\u7AE0\u8282
1500
+
1501
+ \u5185\u5BB9\u3002`
1502
+ };
1503
+ export {
1504
+ MarkdownToLarkConverter,
1505
+ TEST_CASES,
1506
+ generateBlockHtml,
1507
+ generateBlockId,
1508
+ generateHtml,
1509
+ generatePageId,
1510
+ generateRecordId,
1511
+ larkToMarkdown,
1512
+ markdownToLark,
1513
+ parseMarkdown,
1514
+ readClipboard,
1515
+ writeToClipboard
1516
+ };
1517
+ //# sourceMappingURL=index.mjs.map