@haklex/rich-litexml 0.9.1 → 0.9.3

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 CHANGED
@@ -1,1122 +1,4 @@
1
- import { customAlphabet } from "nanoid";
2
- import { parseHTML } from "linkedom";
3
- //#region src/readers/builtin.ts
4
- function extractBlockId$1(el) {
5
- const id = el.getAttribute("id");
6
- return id ? { $: { blockId: id } } : {};
7
- }
8
- var ELEMENT_DEFAULTS = {
9
- direction: "ltr",
10
- format: "",
11
- indent: 0,
12
- textFormat: 0,
13
- textStyle: "",
14
- version: 1
15
- };
16
- function registerBuiltinReaders(registry) {
17
- registry.registerReader("p", (el, ctx) => ({
18
- type: "paragraph",
19
- ...extractBlockId$1(el),
20
- children: ctx.parseChildren(el),
21
- ...ELEMENT_DEFAULTS
22
- }));
23
- for (let level = 1; level <= 6; level++) registry.registerReader(`h${level}`, (el, ctx) => ({
24
- type: "heading",
25
- tag: `h${level}`,
26
- ...extractBlockId$1(el),
27
- children: ctx.parseChildren(el),
28
- ...ELEMENT_DEFAULTS
29
- }));
30
- registry.registerReader("blockquote", (el, ctx) => ({
31
- type: "quote",
32
- ...extractBlockId$1(el),
33
- children: ctx.parseChildren(el),
34
- ...ELEMENT_DEFAULTS
35
- }));
36
- registry.registerReader("hr", (el) => ({
37
- type: "horizontalrule",
38
- ...extractBlockId$1(el),
39
- version: 1
40
- }));
41
- registry.registerReader("ul", (el, ctx) => {
42
- return {
43
- type: "list",
44
- listType: el.getAttribute("type") === "check" ? "check" : "bullet",
45
- tag: "ul",
46
- start: 1,
47
- ...extractBlockId$1(el),
48
- children: ctx.parseChildren(el),
49
- direction: "ltr",
50
- format: "",
51
- indent: 0,
52
- version: 1
53
- };
54
- });
55
- registry.registerReader("ol", (el, ctx) => ({
56
- type: "list",
57
- listType: "number",
58
- tag: "ol",
59
- start: Number(el.getAttribute("start") ?? 1),
60
- ...extractBlockId$1(el),
61
- children: ctx.parseChildren(el),
62
- direction: "ltr",
63
- format: "",
64
- indent: 0,
65
- version: 1
66
- }));
67
- registry.registerReader("li", (el, ctx) => {
68
- const checked = el.getAttribute("checked");
69
- return {
70
- type: "listitem",
71
- ...extractBlockId$1(el),
72
- ...checked !== null ? { checked: checked === "true" } : {},
73
- children: ctx.parseChildren(el),
74
- ...ELEMENT_DEFAULTS,
75
- value: 1
76
- };
77
- });
78
- registry.registerReader("a", (el, ctx) => ({
79
- type: "link",
80
- url: el.getAttribute("href") ?? "",
81
- target: el.getAttribute("target") ?? null,
82
- title: el.getAttribute("title") ?? null,
83
- rel: null,
84
- children: ctx.parseChildren(el),
85
- direction: "ltr",
86
- format: "",
87
- indent: 0,
88
- version: 1
89
- }));
90
- registry.registerReader("table", (el, ctx) => ({
91
- type: "table",
92
- ...extractBlockId$1(el),
93
- children: ctx.parseChildren(el),
94
- direction: "ltr",
95
- format: "",
96
- indent: 0,
97
- version: 1
98
- }));
99
- registry.registerReader("tr", (el, ctx) => ({
100
- type: "tablerow",
101
- children: ctx.parseChildren(el),
102
- direction: "ltr",
103
- format: "",
104
- indent: 0,
105
- version: 1
106
- }));
107
- registry.registerReader("th", (el, ctx) => ({
108
- type: "tablecell",
109
- headerState: 1,
110
- children: ctx.parseChildren(el),
111
- direction: "ltr",
112
- format: "",
113
- indent: 0,
114
- version: 1
115
- }));
116
- registry.registerReader("td", (el, ctx) => ({
117
- type: "tablecell",
118
- headerState: 0,
119
- children: ctx.parseChildren(el),
120
- direction: "ltr",
121
- format: "",
122
- indent: 0,
123
- version: 1
124
- }));
125
- }
126
- //#endregion
127
- //#region src/readers/custom.ts
128
- var idAlphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
129
- var makePollIdSuffix = customAlphabet(idAlphabet, 10);
130
- var makeOptionIdSuffix = customAlphabet(idAlphabet, 6);
131
- var makeChatParticipantId = customAlphabet(idAlphabet, 6);
132
- var makeChatMessageId = customAlphabet(idAlphabet, 8);
133
- function extractBlockId(el) {
134
- const id = el.getAttribute("id");
135
- return id ? { $: { blockId: id } } : {};
136
- }
137
- function numAttr(el, name) {
138
- const v = el.getAttribute(name);
139
- return v !== null ? Number(v) : void 0;
140
- }
141
- /**
142
- * Extract CDATA text content from an element.
143
- * linkedom (HTML parser) converts <![CDATA[...]]> to a comment node
144
- * with value "[CDATA[...]]", so we detect that pattern.
145
- */
146
- function extractCdataText(el) {
147
- for (const child of el.childNodes) if (child.nodeType === 8) {
148
- const val = child.nodeValue ?? "";
149
- if (val.startsWith("[CDATA[") && val.endsWith("]]")) return val.slice(7, -2);
150
- }
151
- return el.textContent?.trim() ?? "";
152
- }
153
- function registerCustomReaders(registry) {
154
- registry.registerReader("img", (el) => {
155
- if (el.parentElement?.tagName.toLowerCase() === "gallery") return false;
156
- return {
157
- type: "image",
158
- ...extractBlockId(el),
159
- src: el.getAttribute("src") ?? "",
160
- altText: el.getAttribute("alt") ?? "",
161
- width: numAttr(el, "width"),
162
- height: numAttr(el, "height"),
163
- caption: el.getAttribute("caption") ?? void 0,
164
- thumbhash: el.getAttribute("thumbhash") ?? void 0,
165
- accent: el.getAttribute("accent") ?? void 0,
166
- version: 1
167
- };
168
- });
169
- registry.registerReader("video", (el) => ({
170
- type: "video",
171
- ...extractBlockId(el),
172
- src: el.getAttribute("src") ?? "",
173
- poster: el.getAttribute("poster") ?? void 0,
174
- width: numAttr(el, "width"),
175
- height: numAttr(el, "height"),
176
- version: 1
177
- }));
178
- registry.registerReader("linkcard", (el) => ({
179
- type: "link-card",
180
- ...extractBlockId(el),
181
- url: el.getAttribute("url") ?? "",
182
- source: el.getAttribute("source") ?? void 0,
183
- title: el.getAttribute("title") ?? void 0,
184
- description: el.getAttribute("description") ?? void 0,
185
- favicon: el.getAttribute("favicon") ?? void 0,
186
- image: el.getAttribute("image") ?? void 0,
187
- version: 1
188
- }));
189
- registry.registerReader("embed", (el) => ({
190
- type: "embed",
191
- ...extractBlockId(el),
192
- url: el.getAttribute("url") ?? "",
193
- source: el.getAttribute("source") ?? null,
194
- version: 1
195
- }));
196
- registry.registerReader("codeblock", (el) => ({
197
- type: "code-block",
198
- ...extractBlockId(el),
199
- code: el.textContent ?? "",
200
- language: el.getAttribute("lang") ?? "",
201
- version: 1
202
- }));
203
- registry.registerReader("mermaid", (el) => ({
204
- type: "mermaid",
205
- ...extractBlockId(el),
206
- diagram: el.textContent ?? "",
207
- version: 1
208
- }));
209
- registry.registerReader("math", (el) => {
210
- if (el.getAttribute("display") === "block") return {
211
- type: "katex-block",
212
- ...extractBlockId(el),
213
- equation: el.textContent ?? "",
214
- version: 1
215
- };
216
- const color = el.getAttribute("color");
217
- return {
218
- type: "katex-inline",
219
- equation: el.textContent ?? "",
220
- ...color ? { color } : {},
221
- version: 1
222
- };
223
- });
224
- registry.registerReader("alert", (el, ctx) => {
225
- const content = { root: {
226
- type: "root",
227
- children: ctx.parseChildren(el),
228
- direction: "ltr",
229
- format: "",
230
- indent: 0,
231
- version: 1
232
- } };
233
- return {
234
- type: "alert-quote",
235
- ...extractBlockId(el),
236
- alertType: el.getAttribute("type") ?? "note",
237
- content,
238
- version: 1
239
- };
240
- });
241
- registry.registerReader("banner", (el, ctx) => {
242
- const content = { root: {
243
- type: "root",
244
- children: ctx.parseChildren(el),
245
- direction: "ltr",
246
- format: "",
247
- indent: 0,
248
- version: 1
249
- } };
250
- return {
251
- type: "banner",
252
- ...extractBlockId(el),
253
- bannerType: el.getAttribute("type") ?? "note",
254
- content,
255
- version: 1
256
- };
257
- });
258
- registry.registerReader("nesteddoc", (el, ctx) => {
259
- const content = { root: {
260
- type: "root",
261
- children: ctx.parseChildren(el),
262
- direction: "ltr",
263
- format: "",
264
- indent: 0,
265
- version: 1
266
- } };
267
- return {
268
- type: "nested-doc",
269
- ...extractBlockId(el),
270
- content,
271
- version: 1
272
- };
273
- });
274
- registry.registerReader("details", (el, ctx) => ({
275
- type: "details",
276
- ...extractBlockId(el),
277
- summary: el.getAttribute("summary") ?? "",
278
- open: el.getAttribute("open") === "true",
279
- children: ctx.parseChildren(el),
280
- direction: "ltr",
281
- format: "",
282
- indent: 0,
283
- version: 1
284
- }));
285
- registry.registerReader("spoiler", (el, ctx) => ({
286
- type: "spoiler",
287
- children: ctx.parseChildren(el),
288
- direction: "ltr",
289
- format: "",
290
- indent: 0,
291
- textFormat: 0,
292
- textStyle: "",
293
- version: 1
294
- }));
295
- registry.registerReader("ruby", (el, ctx) => ({
296
- type: "ruby",
297
- reading: el.getAttribute("rt") ?? "",
298
- children: ctx.parseChildren(el),
299
- direction: "ltr",
300
- format: "",
301
- indent: 0,
302
- textFormat: 0,
303
- textStyle: "",
304
- version: 1
305
- }));
306
- registry.registerReader("mention", (el) => ({
307
- type: "mention",
308
- platform: el.getAttribute("platform") ?? "",
309
- handle: el.getAttribute("handle") ?? "",
310
- displayName: el.textContent || void 0,
311
- version: 1
312
- }));
313
- registry.registerReader("tag", (el) => ({
314
- type: "tag",
315
- text: el.textContent ?? "",
316
- format: 0,
317
- detail: 0,
318
- mode: "normal",
319
- style: "",
320
- version: 1
321
- }));
322
- registry.registerReader("comment", (el) => ({
323
- type: "comment",
324
- text: el.textContent ?? "",
325
- format: 0,
326
- detail: 0,
327
- mode: "normal",
328
- style: "",
329
- version: 1
330
- }));
331
- registry.registerReader("footnote", (el) => ({
332
- type: "footnote",
333
- identifier: el.getAttribute("ref") ?? "",
334
- version: 1
335
- }));
336
- registry.registerReader("footnotesection", (el) => {
337
- const definitions = {};
338
- for (const child of el.children) if (child.tagName.toLowerCase() === "def") {
339
- const ref = child.getAttribute("ref") ?? "";
340
- definitions[ref] = child.textContent ?? "";
341
- }
342
- return {
343
- type: "footnote-section",
344
- ...extractBlockId(el),
345
- definitions,
346
- version: 1
347
- };
348
- });
349
- registry.registerReader("gallery", (el) => {
350
- const images = [];
351
- for (const child of el.children) if (child.tagName.toLowerCase() === "img") images.push({
352
- src: child.getAttribute("src") ?? "",
353
- alt: child.getAttribute("alt") ?? void 0
354
- });
355
- return {
356
- type: "gallery",
357
- ...extractBlockId(el),
358
- images,
359
- layout: el.getAttribute("layout") ?? "grid",
360
- version: 1
361
- };
362
- });
363
- registry.registerReader("excalidraw", (el) => ({
364
- type: "excalidraw",
365
- ...extractBlockId(el),
366
- snapshot: extractCdataText(el) || el.getAttribute("snapshot") || "",
367
- version: 1
368
- }));
369
- registry.registerReader("grid", (el, ctx) => {
370
- const cells = [];
371
- for (const child of el.children) if (child.tagName.toLowerCase() === "cell") {
372
- const children = ctx.parseChildren(child);
373
- cells.push({ root: {
374
- type: "root",
375
- children,
376
- direction: "ltr",
377
- format: "",
378
- indent: 0,
379
- version: 1
380
- } });
381
- }
382
- return {
383
- type: "grid-container",
384
- ...extractBlockId(el),
385
- cols: numAttr(el, "cols") ?? 2,
386
- gap: el.getAttribute("gap") ?? "16px",
387
- cells,
388
- version: 1
389
- };
390
- });
391
- registry.registerReader("agentdiff", (el) => ({
392
- type: "agent-diff",
393
- ...extractBlockId(el),
394
- opType: el.getAttribute("op") ?? "insert",
395
- diffEntryId: el.getAttribute("entry") ?? "",
396
- version: 1
397
- }));
398
- registry.registerReader("codesnippet", (el) => {
399
- const files = [];
400
- for (const child of el.children) if (child.tagName.toLowerCase() === "file") files.push({
401
- filename: child.getAttribute("name") ?? "",
402
- code: child.textContent ?? "",
403
- language: child.getAttribute("lang") ?? ""
404
- });
405
- return {
406
- type: "code-snippet",
407
- ...extractBlockId(el),
408
- files,
409
- version: 1
410
- };
411
- });
412
- registry.registerReader("chat", (el) => {
413
- const variant = el.getAttribute("variant") === "user-user" ? "user-user" : "user-agent";
414
- const participants = [];
415
- const messages = [];
416
- for (const child of el.children) {
417
- const tag = child.tagName.toLowerCase();
418
- if (tag === "participants") for (const p of child.children) {
419
- if (p.tagName.toLowerCase() !== "participant") continue;
420
- const kind = p.getAttribute("kind") === "agent" ? "agent" : "user";
421
- participants.push({
422
- id: p.getAttribute("id") || `p_${makeChatParticipantId()}`,
423
- kind,
424
- name: p.getAttribute("name") || void 0,
425
- avatar: p.getAttribute("avatar") || void 0
426
- });
427
- }
428
- else if (tag === "messages") for (const m of child.children) {
429
- if (m.tagName.toLowerCase() !== "message") continue;
430
- messages.push({
431
- id: m.getAttribute("id") || `m_${makeChatMessageId()}`,
432
- participantId: m.getAttribute("participant") ?? "",
433
- content: m.textContent ?? ""
434
- });
435
- }
436
- }
437
- return {
438
- type: "chat",
439
- ...extractBlockId(el),
440
- variant,
441
- participants,
442
- messages,
443
- version: 1
444
- };
445
- });
446
- registry.registerReader("poll", (el) => {
447
- let question = "";
448
- const options = [];
449
- for (const child of el.children) {
450
- const tag = child.tagName.toLowerCase();
451
- if (tag === "question") question = child.textContent ?? "";
452
- else if (tag === "option") {
453
- const id = child.getAttribute("id") || `o_${makeOptionIdSuffix()}`;
454
- options.push({
455
- id,
456
- label: child.textContent ?? ""
457
- });
458
- }
459
- }
460
- const mode = el.getAttribute("mode") === "multiple" ? "multiple" : "single";
461
- const closeAt = el.getAttribute("close-at");
462
- const showResultsAttr = el.getAttribute("show-results");
463
- const showResults = showResultsAttr === "always" || showResultsAttr === "after-vote" || showResultsAttr === "after-close" ? showResultsAttr : void 0;
464
- return {
465
- type: "poll",
466
- ...extractBlockId(el),
467
- pollId: el.getAttribute("poll-id") || `p_${makePollIdSuffix()}`,
468
- question,
469
- options,
470
- mode,
471
- ...closeAt ? { closeAt } : {},
472
- ...showResults ? { showResults } : {},
473
- version: 1
474
- };
475
- });
476
- }
477
- //#endregion
478
- //#region src/registry.ts
479
- var LitexmlRegistry = class {
480
- constructor() {
481
- this.writers = /* @__PURE__ */ new Map();
482
- this.readers = /* @__PURE__ */ new Map();
483
- }
484
- registerWriter(nodeType, writer) {
485
- this.writers.set(nodeType, writer);
486
- }
487
- registerReader(tagName, reader) {
488
- this.readers.set(tagName.toLowerCase(), reader);
489
- }
490
- getWriter(nodeType) {
491
- return this.writers.get(nodeType);
492
- }
493
- getReader(tagName) {
494
- return this.readers.get(tagName.toLowerCase());
495
- }
496
- };
497
- //#endregion
498
- //#region src/writers/builtin.ts
499
- function blockId$1(node) {
500
- return node.$?.blockId ? { id: node.$.blockId } : {};
501
- }
502
- function registerBuiltinWriters(registry) {
503
- registry.registerWriter("paragraph", (node, ctx) => {
504
- const n = node;
505
- return {
506
- tag: "p",
507
- attrs: blockId$1(n),
508
- children: ctx.serializeChildren(n.children ?? [])
509
- };
510
- });
511
- registry.registerWriter("heading", (node, ctx) => {
512
- const n = node;
513
- return {
514
- tag: n.tag ?? "h1",
515
- attrs: blockId$1(n),
516
- children: ctx.serializeChildren(n.children ?? [])
517
- };
518
- });
519
- registry.registerWriter("quote", (node, ctx) => {
520
- const n = node;
521
- return {
522
- tag: "blockquote",
523
- attrs: blockId$1(n),
524
- children: ctx.serializeChildren(n.children ?? [])
525
- };
526
- });
527
- registry.registerWriter("horizontalrule", (node) => {
528
- return {
529
- tag: "hr",
530
- attrs: blockId$1(node),
531
- selfClosing: true
532
- };
533
- });
534
- registry.registerWriter("list", (node, ctx) => {
535
- const n = node;
536
- const tag = n.listType === "number" ? "ol" : "ul";
537
- const attrs = { ...blockId$1(n) };
538
- if (n.listType === "check") attrs.type = "check";
539
- return {
540
- tag,
541
- attrs,
542
- children: ctx.serializeChildren(n.children ?? [])
543
- };
544
- });
545
- registry.registerWriter("listitem", (node, ctx) => {
546
- const n = node;
547
- const attrs = { ...blockId$1(n) };
548
- if (n.checked !== void 0) attrs.checked = String(n.checked);
549
- return {
550
- tag: "li",
551
- attrs,
552
- children: ctx.serializeChildren(n.children ?? [])
553
- };
554
- });
555
- registry.registerWriter("link", (node, ctx) => {
556
- const n = node;
557
- const attrs = { href: n.url ?? "" };
558
- if (n.target) attrs.target = n.target;
559
- if (n.title) attrs.title = n.title;
560
- return {
561
- tag: "a",
562
- attrs,
563
- children: ctx.serializeChildren(n.children ?? [])
564
- };
565
- });
566
- registry.registerWriter("autolink", (node, ctx) => {
567
- const n = node;
568
- return {
569
- tag: "a",
570
- attrs: { href: n.url ?? "" },
571
- children: ctx.serializeChildren(n.children ?? [])
572
- };
573
- });
574
- registry.registerWriter("table", (node, ctx) => {
575
- const n = node;
576
- return {
577
- tag: "table",
578
- attrs: blockId$1(n),
579
- children: ctx.serializeChildren(n.children ?? [])
580
- };
581
- });
582
- registry.registerWriter("tablerow", (node, ctx) => {
583
- const n = node;
584
- return {
585
- tag: "tr",
586
- children: ctx.serializeChildren(n.children ?? [])
587
- };
588
- });
589
- registry.registerWriter("tablecell", (node, ctx) => {
590
- const n = node;
591
- return {
592
- tag: n.headerState === 1 ? "th" : "td",
593
- children: ctx.serializeChildren(n.children ?? [])
594
- };
595
- });
596
- }
597
- //#endregion
598
- //#region src/writers/custom.ts
599
- function blockId(node) {
600
- return node.$?.blockId ? { id: node.$.blockId } : {};
601
- }
602
- function optAttr(attrs) {
603
- const result = {};
604
- for (const [k, v] of Object.entries(attrs)) if (v !== void 0 && v !== null && v !== "") result[k] = String(v);
605
- return result;
606
- }
607
- function registerCustomWriters(registry) {
608
- registry.registerWriter("image", (node) => {
609
- const n = node;
610
- return {
611
- tag: "img",
612
- attrs: optAttr({
613
- ...blockId(n),
614
- src: n.src,
615
- alt: n.altText,
616
- width: n.width != null ? String(n.width) : void 0,
617
- height: n.height != null ? String(n.height) : void 0,
618
- caption: n.caption,
619
- thumbhash: n.thumbhash,
620
- accent: n.accent
621
- }),
622
- selfClosing: true
623
- };
624
- });
625
- registry.registerWriter("video", (node) => {
626
- const n = node;
627
- return {
628
- tag: "video",
629
- attrs: optAttr({
630
- ...blockId(n),
631
- src: n.src,
632
- poster: n.poster
633
- }),
634
- selfClosing: true
635
- };
636
- });
637
- registry.registerWriter("link-card", (node) => {
638
- const n = node;
639
- return {
640
- tag: "linkcard",
641
- attrs: optAttr({
642
- ...blockId(n),
643
- url: n.url,
644
- source: n.source,
645
- title: n.title,
646
- description: n.description,
647
- favicon: n.favicon,
648
- image: n.image
649
- }),
650
- selfClosing: true
651
- };
652
- });
653
- registry.registerWriter("embed", (node) => {
654
- const n = node;
655
- return {
656
- tag: "embed",
657
- attrs: optAttr({
658
- ...blockId(n),
659
- url: n.url,
660
- source: n.source
661
- }),
662
- selfClosing: true
663
- };
664
- });
665
- registry.registerWriter("code-block", (node) => {
666
- const n = node;
667
- return {
668
- tag: "codeblock",
669
- attrs: optAttr({
670
- ...blockId(n),
671
- lang: n.language
672
- }),
673
- children: [n.code ?? ""]
674
- };
675
- });
676
- registry.registerWriter("mermaid", (node) => {
677
- const n = node;
678
- return {
679
- tag: "mermaid",
680
- attrs: blockId(n),
681
- children: [n.diagram ?? ""]
682
- };
683
- });
684
- registry.registerWriter("katex-block", (node) => {
685
- const n = node;
686
- return {
687
- tag: "math",
688
- attrs: {
689
- ...blockId(n),
690
- display: "block"
691
- },
692
- children: [n.equation ?? ""]
693
- };
694
- });
695
- registry.registerWriter("katex-inline", (node) => {
696
- const n = node;
697
- const attrs = {};
698
- if (n.color) attrs.color = n.color;
699
- return {
700
- tag: "math",
701
- attrs: Object.keys(attrs).length > 0 ? attrs : void 0,
702
- children: [n.equation ?? ""]
703
- };
704
- });
705
- registry.registerWriter("alert-quote", (node, ctx) => {
706
- const n = node;
707
- return {
708
- tag: "alert",
709
- attrs: optAttr({
710
- ...blockId(n),
711
- type: n.alertType
712
- }),
713
- children: ctx.serializeNestedState(n.content)
714
- };
715
- });
716
- registry.registerWriter("banner", (node, ctx) => {
717
- const n = node;
718
- return {
719
- tag: "banner",
720
- attrs: optAttr({
721
- ...blockId(n),
722
- type: n.bannerType
723
- }),
724
- children: ctx.serializeNestedState(n.content)
725
- };
726
- });
727
- registry.registerWriter("nested-doc", (node, ctx) => {
728
- const n = node;
729
- return {
730
- tag: "nesteddoc",
731
- attrs: blockId(n),
732
- children: ctx.serializeNestedState(n.content ?? n.contentState)
733
- };
734
- });
735
- registry.registerWriter("excalidraw", (node) => {
736
- const n = node;
737
- if (!n.snapshot) return {
738
- tag: "excalidraw",
739
- attrs: optAttr(blockId(n)),
740
- selfClosing: true
741
- };
742
- return {
743
- tag: "excalidraw",
744
- attrs: optAttr(blockId(n)),
745
- children: [{ cdata: n.snapshot }]
746
- };
747
- });
748
- registry.registerWriter("grid-container", (node, ctx) => {
749
- const n = node;
750
- const cells = (n.cells ?? []).map((cellState) => ({
751
- tag: "cell",
752
- children: ctx.serializeNestedState(cellState)
753
- }));
754
- return {
755
- tag: "grid",
756
- attrs: optAttr({
757
- ...blockId(n),
758
- cols: n.cols != null ? String(n.cols) : void 0,
759
- gap: n.gap
760
- }),
761
- children: cells
762
- };
763
- });
764
- registry.registerWriter("agent-diff", (node) => {
765
- const n = node;
766
- return {
767
- tag: "agentdiff",
768
- attrs: optAttr({
769
- ...blockId(n),
770
- op: n.opType,
771
- entry: n.diffEntryId
772
- }),
773
- selfClosing: true
774
- };
775
- });
776
- registry.registerWriter("details", (node, ctx) => {
777
- const n = node;
778
- return {
779
- tag: "details",
780
- attrs: optAttr({
781
- ...blockId(n),
782
- summary: n.summary,
783
- open: n.open != null ? String(n.open) : void 0
784
- }),
785
- children: ctx.serializeChildren(n.children ?? [])
786
- };
787
- });
788
- registry.registerWriter("spoiler", (node, ctx) => {
789
- const n = node;
790
- return {
791
- tag: "spoiler",
792
- children: ctx.serializeChildren(n.children ?? [])
793
- };
794
- });
795
- registry.registerWriter("ruby", (node, ctx) => {
796
- const n = node;
797
- return {
798
- tag: "ruby",
799
- attrs: optAttr({ rt: n.reading }),
800
- children: ctx.serializeChildren(n.children ?? [])
801
- };
802
- });
803
- registry.registerWriter("mention", (node) => {
804
- const n = node;
805
- return {
806
- tag: "mention",
807
- attrs: optAttr({
808
- platform: n.platform,
809
- handle: n.handle
810
- }),
811
- children: [n.displayName ?? n.handle ?? ""]
812
- };
813
- });
814
- registry.registerWriter("tag", (node) => {
815
- return {
816
- tag: "tag",
817
- children: [node.text ?? ""]
818
- };
819
- });
820
- registry.registerWriter("comment", (node) => {
821
- return {
822
- tag: "comment",
823
- children: [node.text ?? ""]
824
- };
825
- });
826
- registry.registerWriter("footnote", (node) => {
827
- return {
828
- tag: "footnote",
829
- attrs: { ref: node.identifier ?? "" },
830
- selfClosing: true
831
- };
832
- });
833
- registry.registerWriter("footnote-section", (node) => {
834
- const n = node;
835
- const defs = n.definitions ?? {};
836
- const children = Object.entries(defs).map(([ref, text]) => ({
837
- tag: "def",
838
- attrs: { ref },
839
- children: [text]
840
- }));
841
- return {
842
- tag: "footnotesection",
843
- attrs: blockId(n),
844
- children
845
- };
846
- });
847
- registry.registerWriter("gallery", (node) => {
848
- const n = node;
849
- const images = (n.images ?? []).map((img) => ({
850
- tag: "img",
851
- attrs: optAttr({
852
- src: img.src,
853
- alt: img.alt
854
- }),
855
- selfClosing: true
856
- }));
857
- return {
858
- tag: "gallery",
859
- attrs: optAttr({
860
- ...blockId(n),
861
- layout: n.layout
862
- }),
863
- children: images
864
- };
865
- });
866
- registry.registerWriter("code-snippet", (node) => {
867
- const n = node;
868
- const files = (n.files ?? []).map((f) => ({
869
- tag: "file",
870
- attrs: optAttr({
871
- name: f.filename,
872
- lang: f.language
873
- }),
874
- children: [f.code ?? ""]
875
- }));
876
- return {
877
- tag: "codesnippet",
878
- attrs: blockId(n),
879
- children: files
880
- };
881
- });
882
- registry.registerWriter("chat", (node) => {
883
- const n = node;
884
- const participantsEl = {
885
- tag: "participants",
886
- children: (n.participants ?? []).map((p) => ({
887
- tag: "participant",
888
- attrs: optAttr({
889
- id: p.id,
890
- kind: p.kind,
891
- name: p.name,
892
- avatar: p.avatar
893
- }),
894
- children: []
895
- }))
896
- };
897
- const messagesEl = {
898
- tag: "messages",
899
- children: (n.messages ?? []).map((m) => ({
900
- tag: "message",
901
- attrs: optAttr({
902
- id: m.id,
903
- participant: m.participantId
904
- }),
905
- children: [m.content ?? ""]
906
- }))
907
- };
908
- return {
909
- tag: "chat",
910
- attrs: optAttr({
911
- ...blockId(n),
912
- variant: n.variant
913
- }),
914
- children: [participantsEl, messagesEl]
915
- };
916
- });
917
- registry.registerWriter("poll", (node) => {
918
- const n = node;
919
- const optionElements = (n.options ?? []).map((option) => ({
920
- tag: "option",
921
- attrs: optAttr({ id: option.id }),
922
- children: [option.label ?? ""]
923
- }));
924
- return {
925
- tag: "poll",
926
- attrs: optAttr({
927
- ...blockId(n),
928
- "poll-id": n.pollId,
929
- "mode": n.mode,
930
- "close-at": n.closeAt,
931
- "show-results": n.showResults
932
- }),
933
- children: [{
934
- tag: "question",
935
- children: [n.question ?? ""]
936
- }, ...optionElements]
937
- };
938
- });
939
- }
940
- //#endregion
941
- //#region src/default-registry.ts
942
- function createDefaultRegistry() {
943
- const registry = new LitexmlRegistry();
944
- registerBuiltinWriters(registry);
945
- registerBuiltinReaders(registry);
946
- registerCustomWriters(registry);
947
- registerCustomReaders(registry);
948
- return registry;
949
- }
950
- //#endregion
951
- //#region src/text-format.ts
952
- /** Ordered list: bit value → XML tag. Order determines nesting (outer→inner). */
953
- var FORMAT_BIT_TO_TAG = [
954
- [1, "b"],
955
- [2, "i"],
956
- [4, "s"],
957
- [8, "u"],
958
- [16, "code"],
959
- [32, "sub"],
960
- [64, "sup"],
961
- [128, "mark"]
962
- ];
963
- /** Reverse map: XML tag name → bit value (includes aliases) */
964
- var FORMAT_TAG_TO_BIT = {
965
- b: 1,
966
- strong: 1,
967
- i: 2,
968
- em: 2,
969
- s: 4,
970
- del: 4,
971
- strike: 4,
972
- u: 8,
973
- code: 16,
974
- sub: 32,
975
- sup: 64,
976
- mark: 128
977
- };
978
- /** Wrap text content with nested format tags based on bitmask. */
979
- function wrapWithFormatTags(text, format) {
980
- if (format === 0) return [text];
981
- let content = [text];
982
- for (let idx = FORMAT_BIT_TO_TAG.length - 1; idx >= 0; idx--) {
983
- const [bit, tag] = FORMAT_BIT_TO_TAG[idx];
984
- if (format & bit) content = [{
985
- tag,
986
- children: content
987
- }];
988
- }
989
- return content;
990
- }
991
- /** Check if a tag name is a known text format tag. */
992
- function isFormatTag(tagName) {
993
- return tagName.toLowerCase() in FORMAT_TAG_TO_BIT;
994
- }
995
- /** Get the format bit for a tag name. Returns 0 if not a format tag. */
996
- function getFormatBit(tagName) {
997
- return FORMAT_TAG_TO_BIT[tagName.toLowerCase()] ?? 0;
998
- }
999
- //#endregion
1000
- //#region src/deserializer.ts
1001
- function parseXml(xml) {
1002
- const { document } = parseHTML(`<!DOCTYPE html><html><body>${xml}</body></html>`);
1003
- return document;
1004
- }
1005
- function deserializeFromXml(xml, registry) {
1006
- const doc = parseXml(xml);
1007
- const docEl = doc.querySelector("doc") ?? doc.body;
1008
- return { root: {
1009
- type: "root",
1010
- children: createReaderContext(registry).parseChildren(docEl),
1011
- direction: "ltr",
1012
- format: "",
1013
- indent: 0,
1014
- version: 1
1015
- } };
1016
- }
1017
- function deserializeNodesFromXml(xml, registry) {
1018
- const doc = parseXml(`<fragment>${xml}</fragment>`);
1019
- const fragment = doc.querySelector("fragment") ?? doc.body;
1020
- return createReaderContext(registry).parseChildren(fragment);
1021
- }
1022
- /** Structural containers whose whitespace-only text nodes are layout artifacts, not content */
1023
- var BLOCK_TAGS = new Set([
1024
- "doc",
1025
- "fragment",
1026
- "root",
1027
- "ul",
1028
- "ol",
1029
- "table",
1030
- "tr",
1031
- "alert",
1032
- "banner",
1033
- "details",
1034
- "nesteddoc",
1035
- "gallery",
1036
- "codesnippet",
1037
- "footnotesection",
1038
- "grid",
1039
- "cell",
1040
- "excalidraw"
1041
- ]);
1042
- function isBlockContainer(element) {
1043
- return BLOCK_TAGS.has(element.tagName.toLowerCase());
1044
- }
1045
- function createReaderContext(registry) {
1046
- const ctx = {
1047
- parseChildren(element) {
1048
- const blockLevel = isBlockContainer(element);
1049
- const nodes = [];
1050
- for (const child of element.childNodes) if (child.nodeType === 3) {
1051
- const text = child.textContent ?? "";
1052
- if (blockLevel && text.trim() === "") continue;
1053
- if (text === "") continue;
1054
- nodes.push(makeTextNode(text, 0));
1055
- } else if (child.nodeType === 1) {
1056
- const parsed = parseElement(child, registry, ctx, 0);
1057
- if (parsed) if (Array.isArray(parsed)) nodes.push(...parsed);
1058
- else nodes.push(parsed);
1059
- }
1060
- return nodes;
1061
- },
1062
- parseNestedState(xml) {
1063
- return deserializeFromXml(xml, registry);
1064
- }
1065
- };
1066
- return ctx;
1067
- }
1068
- function parseElement(element, registry, ctx, inheritedFormat) {
1069
- const tag = element.tagName.toLowerCase();
1070
- if (isFormatTag(tag)) return parseInlineChildren(element, registry, ctx, inheritedFormat | getFormatBit(tag));
1071
- if (tag === "br") return {
1072
- type: "linebreak",
1073
- version: 1
1074
- };
1075
- if (tag === "node") return parseFallbackNode(element);
1076
- const reader = registry.getReader(tag);
1077
- if (reader) {
1078
- const result = reader(element, ctx);
1079
- if (result !== false) return result;
1080
- }
1081
- return ctx.parseChildren(element);
1082
- }
1083
- function parseInlineChildren(element, registry, ctx, format) {
1084
- const nodes = [];
1085
- for (const child of element.childNodes) if (child.nodeType === 3) {
1086
- const text = child.textContent ?? "";
1087
- if (text === "") continue;
1088
- nodes.push(makeTextNode(text, format));
1089
- } else if (child.nodeType === 1) {
1090
- const parsed = parseElement(child, registry, ctx, format);
1091
- if (parsed) if (Array.isArray(parsed)) nodes.push(...parsed);
1092
- else nodes.push(parsed);
1093
- }
1094
- return nodes;
1095
- }
1096
- function parseFallbackNode(element) {
1097
- const type = element.getAttribute("type") ?? "unknown";
1098
- const id = element.getAttribute("id");
1099
- const dataStr = element.getAttribute("data");
1100
- const data = dataStr ? JSON.parse(dataStr) : {};
1101
- return {
1102
- type,
1103
- ...id ? { $: { blockId: id } } : {},
1104
- ...data,
1105
- version: 1
1106
- };
1107
- }
1108
- function makeTextNode(text, format) {
1109
- return {
1110
- type: "text",
1111
- text,
1112
- format,
1113
- detail: 0,
1114
- mode: "normal",
1115
- style: "",
1116
- version: 1
1117
- };
1118
- }
1119
- //#endregion
1
+ import { a as registerCustomWriters, c as registerCustomReaders, i as createDefaultRegistry, l as registerBuiltinReaders, n as deserializeNodesFromXml, o as registerBuiltinWriters, r as wrapWithFormatTags, s as LitexmlRegistry, t as deserializeFromXml } from "./deserializer-Du_gQd-x.js";
1120
2
  //#region src/xml-utils.ts
1121
3
  var ESCAPE_MAP = {
1122
4
  "&": "&amp;",