@haklex/rich-litexml 0.24.0 → 0.25.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/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # @haklex/rich-litexml
2
+
3
+ Bidirectional Lexical editor state ↔ XML serialization for LLM-friendly document I/O. Converts Lexical `SerializedEditorState` to a compact, token-efficient XML format and back again — enabling AI agents to read and write structured rich text documents with minimal token overhead.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @haklex/rich-litexml
9
+ ```
10
+
11
+ ## Peer Dependencies
12
+
13
+ | Package | Version |
14
+ | --------- | --------- |
15
+ | `lexical` | `^0.45.0` |
16
+
17
+ ## Usage
18
+
19
+ ### Serialize editor state to XML
20
+
21
+ ```ts
22
+ import { serializeToXml } from '@haklex/rich-litexml';
23
+
24
+ const xml = serializeToXml(serializedEditorState);
25
+ // '<root><p>Hello <strong>world</strong></p><img src="..." /></root>'
26
+ ```
27
+
28
+ ### Deserialize XML to editor state
29
+
30
+ ```ts
31
+ import { deserializeFromXml } from '@haklex/rich-litexml';
32
+
33
+ const editorState = deserializeFromXml(xmlString);
34
+ ```
35
+
36
+ ### Register custom node types
37
+
38
+ ```ts
39
+ import { LitexmlRegistry } from '@haklex/rich-litexml';
40
+ import { registerBuiltinReaders, registerCustomReaders } from '@haklex/rich-litexml';
41
+ import { registerBuiltinWriters, registerCustomWriters } from '@haklex/rich-litexml';
42
+
43
+ const registry = new LitexmlRegistry();
44
+ registerBuiltinReaders(registry);
45
+ registerBuiltinWriters(registry);
46
+
47
+ // Add custom node readers/writers
48
+ registerCustomReaders(registry, [myReader]);
49
+ registerCustomWriters(registry, [myWriter]);
50
+ ```
51
+
52
+ ## Exports
53
+
54
+ ### Serialization
55
+
56
+ | Export | Description |
57
+ | -------------------------------------- | ------------------------------------------------ |
58
+ | `serializeToXml(state, options?)` | Convert `SerializedEditorState` to XML string |
59
+ | `serializeNodesToXml(nodes, options?)` | Convert an array of serialized nodes to XML |
60
+ | `deserializeFromXml(xml)` | Convert an XML string to `SerializedEditorState` |
61
+ | `deserializeNodesFromXml(xml)` | Convert an XML string to serialized nodes array |
62
+
63
+ ### Registry
64
+
65
+ | Export | Description |
66
+ | ------------------------------------------ | ----------------------------------------------------- |
67
+ | `LitexmlRegistry` | Plugin registry class for custom node readers/writers |
68
+ | `createDefaultRegistry()` | Create a registry pre-populated with builtins |
69
+ | `registerBuiltinReaders(registry)` | Register builtin XML → node readers |
70
+ | `registerBuiltinWriters(registry)` | Register builtin node → XML writers |
71
+ | `registerCustomReaders(registry, readers)` | Register custom readers |
72
+ | `registerCustomWriters(registry, writers)` | Register custom writers |
73
+
74
+ ### Types
75
+
76
+ | Export | Description |
77
+ | ------------------------------- | ------------------------------------------ |
78
+ | `XmlSerializerOptions` | Options for XML serialization |
79
+ | `LitexmlNodeReader` | Reader interface for XML → node conversion |
80
+ | `LitexmlNodeWriter` | Writer interface for node → XML conversion |
81
+ | `XmlNodeData`, `XmlNodeElement` | XML AST types |
82
+ | `XmlRenderOptions` | Rendering style options for XML output |
83
+
84
+ ### Sub-path Exports
85
+
86
+ | Import Path | Description |
87
+ | ---------------------- | ------------------------------------------------ |
88
+ | `@haklex/rich-litexml` | Full exports (browser or Node.js, auto-selected) |
89
+
90
+ The package selects between browser and Node.js entry points automatically: Node.js uses `linkedom` for HTML parsing, while the browser entry uses the native `DOMParser`.
91
+
92
+ ---
93
+
94
+ > **Note:** LiteXML is XML-based, not a custom DSL. The compact tag vocabulary minimizes token count for LLM consumption. For AI agent integration, see `@haklex/rich-agent-core`.
95
+
96
+ ## Part of Haklex
97
+
98
+ This package is part of the [Haklex](../../README.md) rich editor ecosystem.
99
+
100
+ ## License
101
+
102
+ MIT
package/dist/browser.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as createDefaultRegistry, c as LitexmlRegistry, d as registerParseHTML, i as deserializeNodesFromXml, l as registerCustomReaders, n as serializeToXml, o as registerCustomWriters, r as deserializeFromXml, s as registerBuiltinWriters, t as serializeNodesToXml, u as registerBuiltinReaders } from "./src-BHEK3mCO.js";
1
+ import { a as createDefaultRegistry, c as LitexmlRegistry, d as registerParseHTML, i as deserializeNodesFromXml, l as registerCustomReaders, n as serializeToXml, o as registerCustomWriters, r as deserializeFromXml, s as registerBuiltinWriters, t as serializeNodesToXml, u as registerBuiltinReaders } from "./src-1idECb05.js";
2
2
  //#region src/index-browser.ts
3
3
  registerParseHTML((html) => new DOMParser().parseFromString(html, "text/html"));
4
4
  //#endregion
package/dist/node.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as createDefaultRegistry, c as LitexmlRegistry, d as registerParseHTML, i as deserializeNodesFromXml, l as registerCustomReaders, n as serializeToXml, o as registerCustomWriters, r as deserializeFromXml, s as registerBuiltinWriters, t as serializeNodesToXml, u as registerBuiltinReaders } from "./src-BHEK3mCO.js";
1
+ import { a as createDefaultRegistry, c as LitexmlRegistry, d as registerParseHTML, i as deserializeNodesFromXml, l as registerCustomReaders, n as serializeToXml, o as registerCustomWriters, r as deserializeFromXml, s as registerBuiltinWriters, t as serializeNodesToXml, u as registerBuiltinReaders } from "./src-1idECb05.js";
2
2
  import { parseHTML } from "linkedom";
3
3
  //#region src/index-node.ts
4
4
  registerParseHTML((html) => parseHTML(html).document);
@@ -1 +1 @@
1
- {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/readers/custom.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAoDnD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAidrE"}
1
+ {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/readers/custom.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAoDnD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CA0erE"}
@@ -405,6 +405,22 @@ function registerCustomReaders(registry) {
405
405
  snapshot: extractCdataText(el) || el.getAttribute("snapshot") || el.textContent?.trim() || "",
406
406
  version: 1
407
407
  }));
408
+ registry.registerReader("dynamic", (el) => {
409
+ let props = {};
410
+ const raw = (extractCdataText(el) ?? el.textContent ?? "").trim();
411
+ if (raw) try {
412
+ const parsed = JSON.parse(raw);
413
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) props = parsed;
414
+ } catch {}
415
+ return {
416
+ type: "dynamic",
417
+ ...extractBlockId(el),
418
+ url: el.getAttribute("url") ?? "",
419
+ props,
420
+ initialHeight: numAttr(el, "initial-height") ?? 320,
421
+ version: 1
422
+ };
423
+ });
408
424
  registry.registerReader("grid", (el, ctx) => {
409
425
  const cells = [];
410
426
  for (const child of el.children) if (child.tagName.toLowerCase() === "cell") {
@@ -795,6 +811,24 @@ function registerCustomWriters(registry) {
795
811
  children: [{ cdata: n.snapshot }]
796
812
  };
797
813
  });
814
+ registry.registerWriter("dynamic", (node) => {
815
+ const n = node;
816
+ const attrs = optAttr({
817
+ ...blockId(n),
818
+ "url": n.url,
819
+ "initial-height": n.initialHeight != null ? String(n.initialHeight) : void 0
820
+ });
821
+ if (!n.props || Object.keys(n.props).length === 0) return {
822
+ tag: "dynamic",
823
+ attrs,
824
+ selfClosing: true
825
+ };
826
+ return {
827
+ tag: "dynamic",
828
+ attrs,
829
+ children: [{ cdata: JSON.stringify(n.props) }]
830
+ };
831
+ });
798
832
  registry.registerWriter("grid-container", (node, ctx) => {
799
833
  const n = node;
800
834
  const cells = (n.cells ?? []).map((cellState) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/writers/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAenD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAwUrE"}
1
+ {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/writers/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAenD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CA2VrE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haklex/rich-litexml",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "Bidirectional Lexical SerializedNode <-> XML conversion with plugin registry",
5
5
  "repository": {
6
6
  "type": "git",