react-next-editor-js 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +877 -0
  3. package/dist/chunk-3QWXTDLY.cjs +486 -0
  4. package/dist/chunk-3QWXTDLY.cjs.map +1 -0
  5. package/dist/chunk-5F6SPYCN.cjs +180 -0
  6. package/dist/chunk-5F6SPYCN.cjs.map +1 -0
  7. package/dist/chunk-6NTSXJX4.js +174 -0
  8. package/dist/chunk-6NTSXJX4.js.map +1 -0
  9. package/dist/chunk-7VYJDBH7.js +261 -0
  10. package/dist/chunk-7VYJDBH7.js.map +1 -0
  11. package/dist/chunk-DBSFCCBG.cjs +1712 -0
  12. package/dist/chunk-DBSFCCBG.cjs.map +1 -0
  13. package/dist/chunk-EFE6RHDL.cjs +4 -0
  14. package/dist/chunk-EFE6RHDL.cjs.map +1 -0
  15. package/dist/chunk-G6YRIEK4.js +3 -0
  16. package/dist/chunk-G6YRIEK4.js.map +1 -0
  17. package/dist/chunk-GFNFJ3FL.cjs +119 -0
  18. package/dist/chunk-GFNFJ3FL.cjs.map +1 -0
  19. package/dist/chunk-IG2YLUFW.js +114 -0
  20. package/dist/chunk-IG2YLUFW.js.map +1 -0
  21. package/dist/chunk-JQXTWLHL.js +176 -0
  22. package/dist/chunk-JQXTWLHL.js.map +1 -0
  23. package/dist/chunk-NJCEHQV3.cjs +454 -0
  24. package/dist/chunk-NJCEHQV3.cjs.map +1 -0
  25. package/dist/chunk-O4GTLC3T.js +478 -0
  26. package/dist/chunk-O4GTLC3T.js.map +1 -0
  27. package/dist/chunk-ODHABIIC.cjs +82 -0
  28. package/dist/chunk-ODHABIIC.cjs.map +1 -0
  29. package/dist/chunk-PZ5AY32C.js +9 -0
  30. package/dist/chunk-PZ5AY32C.js.map +1 -0
  31. package/dist/chunk-Q7SFCCGT.cjs +11 -0
  32. package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
  33. package/dist/chunk-QIUIYBCZ.js +80 -0
  34. package/dist/chunk-QIUIYBCZ.js.map +1 -0
  35. package/dist/chunk-QROUNVQK.js +450 -0
  36. package/dist/chunk-QROUNVQK.js.map +1 -0
  37. package/dist/chunk-T6FR37IC.js +41 -0
  38. package/dist/chunk-T6FR37IC.js.map +1 -0
  39. package/dist/chunk-TI44I654.cjs +265 -0
  40. package/dist/chunk-TI44I654.cjs.map +1 -0
  41. package/dist/chunk-TXPLBAH5.cjs +47 -0
  42. package/dist/chunk-TXPLBAH5.cjs.map +1 -0
  43. package/dist/chunk-U3O54IYI.cjs +187 -0
  44. package/dist/chunk-U3O54IYI.cjs.map +1 -0
  45. package/dist/chunk-VLC7SZMT.js +1669 -0
  46. package/dist/chunk-VLC7SZMT.js.map +1 -0
  47. package/dist/core/index.cjs +232 -0
  48. package/dist/core/index.cjs.map +1 -0
  49. package/dist/core/index.d.cts +122 -0
  50. package/dist/core/index.d.ts +122 -0
  51. package/dist/core/index.js +7 -0
  52. package/dist/core/index.js.map +1 -0
  53. package/dist/defaults-EQD5QKCU.js +4 -0
  54. package/dist/defaults-EQD5QKCU.js.map +1 -0
  55. package/dist/defaults-MLYXD2BG.cjs +49 -0
  56. package/dist/defaults-MLYXD2BG.cjs.map +1 -0
  57. package/dist/docx-BUrf4PFj.d.ts +49 -0
  58. package/dist/docx-DLfSdvXm.d.cts +49 -0
  59. package/dist/docx-LDETXV3L.js +5 -0
  60. package/dist/docx-LDETXV3L.js.map +1 -0
  61. package/dist/docx-N2LKIOK3.cjs +14 -0
  62. package/dist/docx-N2LKIOK3.cjs.map +1 -0
  63. package/dist/export/index.cjs +54 -0
  64. package/dist/export/index.cjs.map +1 -0
  65. package/dist/export/index.d.cts +60 -0
  66. package/dist/export/index.d.ts +60 -0
  67. package/dist/export/index.js +9 -0
  68. package/dist/export/index.js.map +1 -0
  69. package/dist/html-5BXJPQU3.js +7 -0
  70. package/dist/html-5BXJPQU3.js.map +1 -0
  71. package/dist/html-KU2KHLRF.cjs +24 -0
  72. package/dist/html-KU2KHLRF.cjs.map +1 -0
  73. package/dist/import/index.cjs +15 -0
  74. package/dist/import/index.cjs.map +1 -0
  75. package/dist/import/index.d.cts +37 -0
  76. package/dist/import/index.d.ts +37 -0
  77. package/dist/import/index.js +6 -0
  78. package/dist/import/index.js.map +1 -0
  79. package/dist/index.cjs +1035 -0
  80. package/dist/index.cjs.map +1 -0
  81. package/dist/index.d.cts +248 -0
  82. package/dist/index.d.ts +248 -0
  83. package/dist/index.js +885 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/persistence/index.cjs +37 -0
  86. package/dist/persistence/index.cjs.map +1 -0
  87. package/dist/persistence/index.d.cts +279 -0
  88. package/dist/persistence/index.d.ts +279 -0
  89. package/dist/persistence/index.js +4 -0
  90. package/dist/persistence/index.js.map +1 -0
  91. package/dist/sanitize-7IZ-SW1f.d.ts +361 -0
  92. package/dist/sanitize-CvmgqbsA.d.cts +361 -0
  93. package/dist/server/index.cjs +400 -0
  94. package/dist/server/index.cjs.map +1 -0
  95. package/dist/server/index.d.cts +229 -0
  96. package/dist/server/index.d.ts +229 -0
  97. package/dist/server/index.js +390 -0
  98. package/dist/server/index.js.map +1 -0
  99. package/dist/styles.css +680 -0
  100. package/dist/types-B4z0Quvv.d.cts +193 -0
  101. package/dist/types-B4z0Quvv.d.ts +193 -0
  102. package/package.json +183 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-PZ5AY32C.js"}
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __export = (target, all) => {
5
+ for (var name in all)
6
+ __defProp(target, name, { get: all[name], enumerable: true });
7
+ };
8
+
9
+ exports.__export = __export;
10
+ //# sourceMappingURL=chunk-Q7SFCCGT.cjs.map
11
+ //# sourceMappingURL=chunk-Q7SFCCGT.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-Q7SFCCGT.cjs"}
@@ -0,0 +1,80 @@
1
+ import { sanitizeHtml } from './chunk-6NTSXJX4.js';
2
+ import { DOMParser } from 'prosemirror-model';
3
+
4
+ var mammothPromise = null;
5
+ async function loadMammoth() {
6
+ if (!mammothPromise) {
7
+ mammothPromise = (async () => {
8
+ try {
9
+ const spec = "mammoth";
10
+ const mod = await import(spec);
11
+ return mod.default ?? mod;
12
+ } catch {
13
+ throw new Error(
14
+ "react-next-editor: DOCX import requires 'mammoth'. Install it (npm i mammoth)."
15
+ );
16
+ }
17
+ })();
18
+ }
19
+ return mammothPromise;
20
+ }
21
+ var DEFAULT_STYLE_MAP = [
22
+ "p[style-name='Title'] => h1:fresh",
23
+ "p[style-name='Subtitle'] => h2:fresh",
24
+ "p[style-name='Heading 7'] => h6:fresh",
25
+ "p[style-name='Heading 8'] => h6:fresh",
26
+ "p[style-name='Heading 9'] => h6:fresh",
27
+ "p[style-name='Quote'] => blockquote:fresh",
28
+ "p[style-name='Intense Quote'] => blockquote:fresh",
29
+ "p[style-name='Caption'] => p.rne-caption:fresh > em",
30
+ "r[style-name='Strong'] => strong",
31
+ "r[style-name='Emphasis'] => em",
32
+ "r[style-name='Book Title'] => em"
33
+ ];
34
+ async function buildMammothInput(input) {
35
+ const isBlob = typeof Blob !== "undefined" && input instanceof Blob;
36
+ if (typeof Buffer !== "undefined") {
37
+ if (Buffer.isBuffer(input)) return { buffer: input };
38
+ if (input instanceof Uint8Array) return { buffer: Buffer.from(input) };
39
+ if (input instanceof ArrayBuffer) return { buffer: Buffer.from(new Uint8Array(input)) };
40
+ if (isBlob) return { buffer: Buffer.from(new Uint8Array(await input.arrayBuffer())) };
41
+ }
42
+ if (input instanceof ArrayBuffer) return { arrayBuffer: input };
43
+ if (isBlob) return { arrayBuffer: await input.arrayBuffer() };
44
+ if (input instanceof Uint8Array) {
45
+ return {
46
+ arrayBuffer: input.buffer.slice(
47
+ input.byteOffset,
48
+ input.byteOffset + input.byteLength
49
+ )
50
+ };
51
+ }
52
+ throw new Error("react-next-editor: unsupported DOCX input type.");
53
+ }
54
+ async function importDocx(input, schema, options = {}) {
55
+ if (typeof document === "undefined") {
56
+ throw new Error("react-next-editor: importDocx requires a DOM (browser or jsdom).");
57
+ }
58
+ const mammoth = await loadMammoth();
59
+ const mammothInput = await buildMammothInput(input);
60
+ const { value: rawHtml, messages } = await mammoth.convertToHtml(mammothInput, {
61
+ styleMap: [...DEFAULT_STYLE_MAP, ...options.styleMap ?? []],
62
+ includeDefaultStyleMap: true,
63
+ // Preserve blank paragraphs so Word's spacing-by-empty-paragraph survives.
64
+ ignoreEmptyParagraphs: false
65
+ });
66
+ const html = await sanitizeHtml(rawHtml);
67
+ const container = document.createElement("div");
68
+ container.innerHTML = html;
69
+ const parsed = DOMParser.fromSchema(schema).parse(container);
70
+ parsed.check();
71
+ return {
72
+ doc: parsed.toJSON(),
73
+ warnings: messages.map((m) => m.message),
74
+ html
75
+ };
76
+ }
77
+
78
+ export { importDocx };
79
+ //# sourceMappingURL=chunk-QIUIYBCZ.js.map
80
+ //# sourceMappingURL=chunk-QIUIYBCZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/import/docx.ts"],"names":["PMDOMParser"],"mappings":"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","file":"chunk-QIUIYBCZ.js","sourcesContent":["import { DOMParser as PMDOMParser, type Schema } from 'prosemirror-model';\nimport type { DocumentJSON } from '../config/types';\nimport { sanitizeHtml } from '../security/sanitize';\n\n/**\n * Best-effort DOCX import (F-7.2 / F-7.3). External `.docx` files are converted\n * to HTML with `mammoth` (BSD), sanitized (§5.12), then parsed into the editor\n * schema via ProseMirror's DOMParser. Fidelity is best-effort: supported\n * structures (headings, lists, tables, bold/italic/underline, links, images)\n * map across; unsupported Word constructs degrade gracefully. `mammoth` is an\n * optional dependency, lazily imported, so it never bloats the editor bundle.\n *\n * Browser-oriented (needs a DOM to parse HTML). For server-side import, run in\n * an environment that provides `document` (e.g. jsdom).\n */\n\nexport interface DocxImportResult {\n /** The imported document as ProseMirror JSON. */\n doc: DocumentJSON;\n /** Non-fatal conversion warnings from mammoth (unsupported features, etc.). */\n warnings: string[];\n /** The sanitized intermediate HTML (useful for debugging/inspection). */\n html: string;\n}\n\nexport interface DocxImportOptions {\n /**\n * Additional mammoth style mappings (e.g. `\"p[style-name='Quote'] => blockquote\"`).\n * Merged with the built-in defaults.\n */\n styleMap?: string[];\n}\n\n/** Input accepted by mammoth: an ArrayBuffer (browser) or a Buffer (Node). */\ntype MammothInput = { arrayBuffer: ArrayBuffer } | { buffer: Uint8Array };\n\n/** Minimal structural type for the parts of mammoth we use. */\ninterface MammothModule {\n convertToHtml(\n input: MammothInput,\n options?: {\n styleMap?: string[];\n includeDefaultStyleMap?: boolean;\n ignoreEmptyParagraphs?: boolean;\n },\n ): Promise<{ value: string; messages: Array<{ type: string; message: string }> }>;\n}\n\nlet mammothPromise: Promise<MammothModule> | null = null;\nasync function loadMammoth(): Promise<MammothModule> {\n if (!mammothPromise) {\n mammothPromise = (async () => {\n try {\n // Variable specifier so the optional dependency is not resolved at\n // type-check/build time when it is absent.\n const spec = 'mammoth';\n const mod = (await import(spec)) as { default?: MammothModule } & MammothModule;\n return (mod.default ?? mod) as MammothModule;\n } catch {\n throw new Error(\n \"react-next-editor: DOCX import requires 'mammoth'. Install it (npm i mammoth).\",\n );\n }\n })();\n }\n return mammothPromise;\n}\n\n/**\n * Default style mappings improving fidelity for common Word styles. Mammoth's\n * built-in map already covers Heading 1–6, bold/italic, lists, tables, links and\n * images; these extend it to titles, quotes, captions and higher heading levels\n * so more structure survives import.\n */\nconst DEFAULT_STYLE_MAP = [\n \"p[style-name='Title'] => h1:fresh\",\n \"p[style-name='Subtitle'] => h2:fresh\",\n \"p[style-name='Heading 7'] => h6:fresh\",\n \"p[style-name='Heading 8'] => h6:fresh\",\n \"p[style-name='Heading 9'] => h6:fresh\",\n \"p[style-name='Quote'] => blockquote:fresh\",\n \"p[style-name='Intense Quote'] => blockquote:fresh\",\n \"p[style-name='Caption'] => p.rne-caption:fresh > em\",\n \"r[style-name='Strong'] => strong\",\n \"r[style-name='Emphasis'] => em\",\n \"r[style-name='Book Title'] => em\",\n];\n\n/**\n * Build the mammoth input. In Node (server/tests) a `Buffer` is used to avoid\n * cross-realm `instanceof ArrayBuffer` issues; in the browser an `ArrayBuffer`\n * is passed.\n */\nasync function buildMammothInput(input: ArrayBuffer | Uint8Array | Blob): Promise<MammothInput> {\n const isBlob = typeof Blob !== 'undefined' && input instanceof Blob;\n if (typeof Buffer !== 'undefined') {\n if (Buffer.isBuffer(input)) return { buffer: input };\n if (input instanceof Uint8Array) return { buffer: Buffer.from(input) };\n if (input instanceof ArrayBuffer) return { buffer: Buffer.from(new Uint8Array(input)) };\n if (isBlob) return { buffer: Buffer.from(new Uint8Array(await input.arrayBuffer())) };\n }\n if (input instanceof ArrayBuffer) return { arrayBuffer: input };\n if (isBlob) return { arrayBuffer: await input.arrayBuffer() };\n if (input instanceof Uint8Array) {\n return {\n arrayBuffer: input.buffer.slice(\n input.byteOffset,\n input.byteOffset + input.byteLength,\n ) as ArrayBuffer,\n };\n }\n throw new Error('react-next-editor: unsupported DOCX input type.');\n}\n\n/**\n * Import a `.docx` file into the given schema. Returns the document JSON plus\n * any conversion warnings. Never throws on unsupported content — only on a\n * genuinely unreadable file or a missing DOM/mammoth.\n */\nexport async function importDocx(\n input: ArrayBuffer | Uint8Array | Blob,\n schema: Schema,\n options: DocxImportOptions = {},\n): Promise<DocxImportResult> {\n if (typeof document === 'undefined') {\n throw new Error('react-next-editor: importDocx requires a DOM (browser or jsdom).');\n }\n\n const mammoth = await loadMammoth();\n const mammothInput = await buildMammothInput(input);\n\n const { value: rawHtml, messages } = await mammoth.convertToHtml(mammothInput, {\n styleMap: [...DEFAULT_STYLE_MAP, ...(options.styleMap ?? [])],\n includeDefaultStyleMap: true,\n // Preserve blank paragraphs so Word's spacing-by-empty-paragraph survives.\n ignoreEmptyParagraphs: false,\n });\n\n const html = await sanitizeHtml(rawHtml);\n\n const container = document.createElement('div');\n container.innerHTML = html;\n const parsed = PMDOMParser.fromSchema(schema).parse(container);\n // Guarantee a valid, renderable document (F-11.5). Throws here only if the\n // schema cannot represent the content at all — caught by the caller.\n parsed.check();\n\n return {\n doc: parsed.toJSON() as DocumentJSON,\n warnings: messages.map((m) => m.message),\n html,\n };\n}\n"]}
@@ -0,0 +1,450 @@
1
+ import { sanitizeUrl } from './chunk-6NTSXJX4.js';
2
+ import { DEFAULT_PAGE, resolvePageDimensions } from './chunk-JQXTWLHL.js';
3
+
4
+ // src/export/text.ts
5
+ function documentToText(doc, options = {}) {
6
+ const opts = {
7
+ includeLinkUrls: options.includeLinkUrls ?? false,
8
+ images: options.images ?? "alt",
9
+ newline: options.newline ?? "\n"
10
+ };
11
+ const blocks = (doc.content ?? []).map((node) => serializeBlock(node, opts, 0));
12
+ return blocks.filter((b) => b !== null).join(opts.newline + opts.newline).replace(/\n{3,}/g, "\n\n").trim();
13
+ }
14
+ function serializeBlock(node, opts, depth) {
15
+ switch (node.type) {
16
+ case "paragraph":
17
+ case "heading":
18
+ return serializeInline(node.content ?? [], opts);
19
+ case "blockquote":
20
+ return (node.content ?? []).map((child) => serializeBlock(child, opts, depth)).filter((b) => b !== null).map((line) => `> ${line}`).join(opts.newline);
21
+ case "bullet_list":
22
+ case "ordered_list":
23
+ return serializeList(node, opts, depth);
24
+ case "horizontal_rule":
25
+ return "---";
26
+ case "page_break":
27
+ return "\f";
28
+ case "table":
29
+ return serializeTable(node, opts);
30
+ default:
31
+ if (node.content) {
32
+ return node.content.map((child) => serializeBlock(child, opts, depth)).filter((b) => b !== null).join(opts.newline);
33
+ }
34
+ return node.text ?? null;
35
+ }
36
+ }
37
+ function serializeList(node, opts, depth) {
38
+ const ordered = node.type === "ordered_list";
39
+ const start = ordered ? Number(node.attrs?.order ?? 1) : 0;
40
+ const indent = " ".repeat(depth);
41
+ const lines = [];
42
+ let index = start;
43
+ for (const item of node.content ?? []) {
44
+ if (item.type !== "list_item") continue;
45
+ const checked = item.attrs?.checked;
46
+ let marker;
47
+ if (checked === true) marker = "[x]";
48
+ else if (checked === false) marker = "[ ]";
49
+ else if (ordered) marker = `${index}.`;
50
+ else marker = "-";
51
+ const children = item.content ?? [];
52
+ const firstBlock = children[0];
53
+ const firstText = firstBlock ? serializeBlock(firstBlock, opts, depth) ?? "" : "";
54
+ lines.push(`${indent}${marker} ${firstText}`.trimEnd());
55
+ for (let i = 1; i < children.length; i++) {
56
+ const child = children[i];
57
+ if (child.type === "bullet_list" || child.type === "ordered_list") {
58
+ lines.push(serializeList(child, opts, depth + 1));
59
+ } else {
60
+ const text = serializeBlock(child, opts, depth + 1);
61
+ if (text) lines.push(`${indent} ${text}`);
62
+ }
63
+ }
64
+ if (ordered) index++;
65
+ }
66
+ return lines.join(opts.newline);
67
+ }
68
+ function serializeTable(node, opts) {
69
+ const rows = [];
70
+ for (const row of node.content ?? []) {
71
+ if (row.type !== "table_row") continue;
72
+ const cells = (row.content ?? []).map(
73
+ (cell) => (cell.content ?? []).map((block) => serializeBlock(block, opts, 0)).filter((b) => b !== null).join(" ").replace(/\t/g, " ")
74
+ );
75
+ rows.push(cells.join(" "));
76
+ }
77
+ return rows.join(opts.newline);
78
+ }
79
+ function serializeInline(content, opts) {
80
+ let out = "";
81
+ for (const node of content) {
82
+ if (node.type === "text") {
83
+ let text = node.text ?? "";
84
+ if (opts.includeLinkUrls && node.marks) {
85
+ const link = node.marks.find((m) => m.type === "link");
86
+ if (link?.attrs?.href) text = `${text} (${String(link.attrs.href)})`;
87
+ }
88
+ out += text;
89
+ } else if (node.type === "hard_break") {
90
+ out += opts.newline;
91
+ } else if (node.type === "image") {
92
+ if (opts.images === "alt") {
93
+ const alt = node.attrs?.alt;
94
+ if (alt) out += String(alt);
95
+ }
96
+ } else if (node.content) {
97
+ out += serializeInline(node.content, opts);
98
+ }
99
+ }
100
+ return out;
101
+ }
102
+
103
+ // src/export/docx.ts
104
+ var docxModulePromise = null;
105
+ async function loadDocx() {
106
+ if (!docxModulePromise) docxModulePromise = import('docx');
107
+ return docxModulePromise;
108
+ }
109
+ var HALF_POINT = 2;
110
+ var INDENT_TWIP_PER_LEVEL = 720;
111
+ function toHex(value) {
112
+ const v = String(value ?? "").trim();
113
+ const m = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.exec(v);
114
+ if (!m) return null;
115
+ const hex = m[1];
116
+ return hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
117
+ }
118
+ var DocxSerializer = class {
119
+ constructor(converters = {}) {
120
+ this.numberingConfigs = [];
121
+ this.refCounter = 0;
122
+ this.converters = converters;
123
+ }
124
+ allocListRef(ordered) {
125
+ const d = this.docx;
126
+ const reference = `rne-list-${this.refCounter++}`;
127
+ const levels = Array.from({ length: 9 }, (_, level) => {
128
+ if (ordered) {
129
+ const formats = [
130
+ d.LevelFormat.DECIMAL,
131
+ d.LevelFormat.LOWER_LETTER,
132
+ d.LevelFormat.LOWER_ROMAN
133
+ ];
134
+ return {
135
+ level,
136
+ format: formats[level % 3],
137
+ text: `%${level + 1}.`,
138
+ alignment: d.AlignmentType.START,
139
+ style: { paragraph: { indent: { left: (level + 1) * 720, hanging: 360 } } }
140
+ };
141
+ }
142
+ const bullets = ["\u2022", "\u25E6", "\u25AA"];
143
+ return {
144
+ level,
145
+ format: d.LevelFormat.BULLET,
146
+ text: bullets[level % 3],
147
+ alignment: d.AlignmentType.START,
148
+ style: { paragraph: { indent: { left: (level + 1) * 720, hanging: 360 } } }
149
+ };
150
+ });
151
+ this.numberingConfigs.push({ reference, levels });
152
+ return reference;
153
+ }
154
+ /** Build run options from a text node's marks. */
155
+ runOptions(marks) {
156
+ const d = this.docx;
157
+ const o = {};
158
+ for (const mark of marks) {
159
+ switch (mark.type) {
160
+ case "strong":
161
+ o.bold = true;
162
+ break;
163
+ case "em":
164
+ o.italics = true;
165
+ break;
166
+ case "underline":
167
+ o.underline = {};
168
+ break;
169
+ case "strikethrough":
170
+ o.strike = true;
171
+ break;
172
+ case "superscript":
173
+ o.superScript = true;
174
+ break;
175
+ case "subscript":
176
+ o.subScript = true;
177
+ break;
178
+ case "code":
179
+ o.font = "Courier New";
180
+ break;
181
+ case "fontFamily":
182
+ o.font = String(mark.attrs?.family ?? "");
183
+ break;
184
+ case "fontSize": {
185
+ const size = Number(mark.attrs?.size);
186
+ if (Number.isFinite(size) && size > 0) o.size = Math.round(size * HALF_POINT);
187
+ break;
188
+ }
189
+ case "textColor": {
190
+ const hex = toHex(mark.attrs?.color);
191
+ if (hex) o.color = hex;
192
+ break;
193
+ }
194
+ case "highlight": {
195
+ const hex = toHex(mark.attrs?.color);
196
+ if (hex) o.shading = { type: d.ShadingType.CLEAR, fill: hex };
197
+ break;
198
+ }
199
+ }
200
+ }
201
+ return o;
202
+ }
203
+ /** Serialize inline content into docx runs / hyperlinks. */
204
+ inlineChildren(content) {
205
+ const d = this.docx;
206
+ if (!content) return [];
207
+ const out = [];
208
+ for (const node of content) {
209
+ if (node.type === "text") {
210
+ const marks = node.marks ?? [];
211
+ const link = marks.find((m) => m.type === "link");
212
+ const runOpts = this.runOptions(marks.filter((m) => m.type !== "link"));
213
+ const run = new d.TextRun({ text: node.text ?? "", ...runOpts });
214
+ if (link?.attrs?.href) {
215
+ const href = sanitizeUrl(String(link.attrs.href));
216
+ if (href) {
217
+ out.push(new d.ExternalHyperlink({ children: [run], link: href }));
218
+ continue;
219
+ }
220
+ }
221
+ out.push(run);
222
+ } else if (node.type === "hard_break") {
223
+ out.push(new d.TextRun({ break: 1 }));
224
+ } else if (node.type === "image") {
225
+ const img = this.imageRun(node);
226
+ if (img) {
227
+ out.push(img);
228
+ } else {
229
+ const alt = node.attrs?.alt ? String(node.attrs.alt) : "[image]";
230
+ out.push(new d.TextRun({ text: alt, italics: true }));
231
+ }
232
+ }
233
+ }
234
+ return out;
235
+ }
236
+ imageRun(node) {
237
+ const d = this.docx;
238
+ const src = String(node.attrs?.src ?? "");
239
+ const match = /^data:image\/(png|jpe?g|gif|bmp);base64,([A-Za-z0-9+/=]+)$/.exec(src);
240
+ if (!match) return null;
241
+ const raw = match[1];
242
+ const type = raw === "jpeg" ? "jpg" : raw;
243
+ const data = base64ToUint8(match[2]);
244
+ const width = Number(node.attrs?.width) || 300;
245
+ const height = Math.round(width * 0.75);
246
+ try {
247
+ return new d.ImageRun({
248
+ data,
249
+ type,
250
+ transformation: { width, height }
251
+ });
252
+ } catch {
253
+ return null;
254
+ }
255
+ }
256
+ alignment(attrs) {
257
+ const d = this.docx;
258
+ switch (attrs?.align) {
259
+ case "center":
260
+ return d.AlignmentType.CENTER;
261
+ case "right":
262
+ return d.AlignmentType.RIGHT;
263
+ case "justify":
264
+ return d.AlignmentType.JUSTIFIED;
265
+ case "left":
266
+ return d.AlignmentType.LEFT;
267
+ default:
268
+ return void 0;
269
+ }
270
+ }
271
+ paragraphProps(node) {
272
+ const props = {};
273
+ const align = this.alignment(node.attrs);
274
+ if (align !== void 0) props.alignment = align;
275
+ const indent = Number(node.attrs?.indent ?? 0);
276
+ if (indent > 0) props.indent = { left: indent * INDENT_TWIP_PER_LEVEL };
277
+ const lineHeight = Number(node.attrs?.lineHeight);
278
+ if (Number.isFinite(lineHeight) && lineHeight > 0) {
279
+ props.spacing = { line: Math.round(lineHeight * 240), lineRule: "auto" };
280
+ }
281
+ return props;
282
+ }
283
+ headingLevel(level) {
284
+ const d = this.docx;
285
+ const map = [
286
+ d.HeadingLevel.HEADING_1,
287
+ d.HeadingLevel.HEADING_2,
288
+ d.HeadingLevel.HEADING_3,
289
+ d.HeadingLevel.HEADING_4,
290
+ d.HeadingLevel.HEADING_5,
291
+ d.HeadingLevel.HEADING_6
292
+ ];
293
+ return map[Math.min(5, Math.max(0, level - 1))];
294
+ }
295
+ serializeBlocks(nodes) {
296
+ const out = [];
297
+ for (const node of nodes) out.push(...this.serializeBlock(node));
298
+ return out;
299
+ }
300
+ serializeBlock(node) {
301
+ const d = this.docx;
302
+ const custom = this.converters[node.type];
303
+ if (custom) {
304
+ return custom(node, { serializeBlocks: (n) => this.serializeBlocks(n), docx: this.docx });
305
+ }
306
+ switch (node.type) {
307
+ case "paragraph":
308
+ return [
309
+ new d.Paragraph({
310
+ ...this.paragraphProps(node),
311
+ children: this.inlineChildren(node.content)
312
+ })
313
+ ];
314
+ case "heading":
315
+ return [
316
+ new d.Paragraph({
317
+ ...this.paragraphProps(node),
318
+ heading: this.headingLevel(Number(node.attrs?.level ?? 1)),
319
+ children: this.inlineChildren(node.content)
320
+ })
321
+ ];
322
+ case "blockquote":
323
+ return (node.content ?? []).flatMap((child) => {
324
+ const blocks = this.serializeBlock(child);
325
+ return blocks;
326
+ });
327
+ case "horizontal_rule":
328
+ return [
329
+ new d.Paragraph({
330
+ border: { bottom: { style: d.BorderStyle.SINGLE, size: 6, space: 1, color: "999999" } },
331
+ children: []
332
+ })
333
+ ];
334
+ case "page_break":
335
+ return [new d.Paragraph({ children: [new d.PageBreak()] })];
336
+ case "bullet_list":
337
+ case "ordered_list":
338
+ return this.serializeList(node, node.type === "ordered_list", 0);
339
+ case "table":
340
+ return [this.serializeTable(node)];
341
+ default:
342
+ if (node.content) return this.serializeBlocks(node.content);
343
+ return [];
344
+ }
345
+ }
346
+ serializeList(node, ordered, level) {
347
+ const d = this.docx;
348
+ const reference = this.allocListRef(ordered);
349
+ const out = [];
350
+ for (const item of node.content ?? []) {
351
+ if (item.type !== "list_item") continue;
352
+ const children = item.content ?? [];
353
+ const checked = item.attrs?.checked;
354
+ const prefix = checked === true ? "\u2611 " : checked === false ? "\u2610 " : "";
355
+ children.forEach((child, idx) => {
356
+ if (child.type === "bullet_list" || child.type === "ordered_list") {
357
+ out.push(...this.serializeList(child, child.type === "ordered_list", level + 1));
358
+ } else if (idx === 0) {
359
+ const runs = this.inlineChildren(child.content);
360
+ const first = prefix ? [new d.TextRun({ text: prefix }), ...runs] : runs;
361
+ out.push(
362
+ new d.Paragraph({
363
+ numbering: { reference, level },
364
+ children: first
365
+ })
366
+ );
367
+ } else {
368
+ out.push(
369
+ new d.Paragraph({
370
+ indent: { left: (level + 1) * INDENT_TWIP_PER_LEVEL },
371
+ children: this.inlineChildren(child.content)
372
+ })
373
+ );
374
+ }
375
+ });
376
+ }
377
+ return out;
378
+ }
379
+ serializeTable(node) {
380
+ const d = this.docx;
381
+ const rows = (node.content ?? []).filter((row) => row.type === "table_row").map((row) => {
382
+ const cells = (row.content ?? []).map((cell) => {
383
+ const fill = toHex(cell.attrs?.background);
384
+ return new d.TableCell({
385
+ children: this.serializeBlocks(cell.content ?? []),
386
+ columnSpan: Number(cell.attrs?.colspan ?? 1) || 1,
387
+ rowSpan: Number(cell.attrs?.rowspan ?? 1) || 1,
388
+ ...fill ? { shading: { type: d.ShadingType.CLEAR, fill } } : {}
389
+ });
390
+ });
391
+ return new d.TableRow({ children: cells });
392
+ });
393
+ return new d.Table({
394
+ rows,
395
+ width: { size: 100, type: d.WidthType.PERCENTAGE }
396
+ });
397
+ }
398
+ async build(doc, options) {
399
+ this.docx = await loadDocx();
400
+ const d = this.docx;
401
+ const page = options.page ?? DEFAULT_PAGE;
402
+ const { width, height } = resolvePageDimensions(page);
403
+ const children = this.serializeBlocks(doc.content ?? []);
404
+ const mmToTwip = (mm) => Math.round(mm / 25.4 * 1440);
405
+ return new d.Document({
406
+ numbering: { config: this.numberingConfigs },
407
+ sections: [
408
+ {
409
+ properties: {
410
+ page: {
411
+ size: { width: mmToTwip(width), height: mmToTwip(height) },
412
+ margin: {
413
+ top: mmToTwip(page.margins.top),
414
+ right: mmToTwip(page.margins.right),
415
+ bottom: mmToTwip(page.margins.bottom),
416
+ left: mmToTwip(page.margins.left)
417
+ }
418
+ }
419
+ },
420
+ children
421
+ }
422
+ ]
423
+ });
424
+ }
425
+ };
426
+ function base64ToUint8(b64) {
427
+ if (typeof atob === "function") {
428
+ const binary = atob(b64);
429
+ const bytes = new Uint8Array(binary.length);
430
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
431
+ return bytes;
432
+ }
433
+ return new Uint8Array(Buffer.from(b64, "base64"));
434
+ }
435
+ async function documentToDocxBlob(doc, options = {}) {
436
+ const serializer = new DocxSerializer(options.nodeConverters);
437
+ const document = await serializer.build(doc, options);
438
+ const { Packer } = await loadDocx();
439
+ return Packer.toBlob(document);
440
+ }
441
+ async function documentToDocxBuffer(doc, options = {}) {
442
+ const serializer = new DocxSerializer(options.nodeConverters);
443
+ const document = await serializer.build(doc, options);
444
+ const { Packer } = await loadDocx();
445
+ return Packer.toBuffer(document);
446
+ }
447
+
448
+ export { documentToDocxBlob, documentToDocxBuffer, documentToText };
449
+ //# sourceMappingURL=chunk-QROUNVQK.js.map
450
+ //# sourceMappingURL=chunk-QROUNVQK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/export/text.ts","../src/export/docx.ts"],"names":[],"mappings":"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","file":"chunk-QROUNVQK.js","sourcesContent":["import type { DocumentJSON } from '../config/types';\n\n/**\n * Options governing plain-text conversion (F-6.20). Defaults follow the\n * documented structure rules: blocks separated by blank lines, list items on\n * their own lines, table cells tab-delimited, images replaced by alt text,\n * links rendered as their text.\n */\nexport interface TextConversionOptions {\n /** Append the URL after link text as \" (url)\". Default false. */\n includeLinkUrls?: boolean;\n /** Replacement for images: 'alt' uses alt text, 'omit' drops them. Default 'alt'. */\n images?: 'alt' | 'omit';\n /** Newline sequence. Default '\\n'. */\n newline?: string;\n}\n\ninterface ResolvedOptions {\n includeLinkUrls: boolean;\n images: 'alt' | 'omit';\n newline: string;\n}\n\n/**\n * Convert a ProseMirror document (JSON) to plain text (F-6.18). Pure and\n * isomorphic: identical output in the browser and on the server (F-6.19).\n */\nexport function documentToText(doc: DocumentJSON, options: TextConversionOptions = {}): string {\n const opts: ResolvedOptions = {\n includeLinkUrls: options.includeLinkUrls ?? false,\n images: options.images ?? 'alt',\n newline: options.newline ?? '\\n',\n };\n const blocks = (doc.content ?? []).map((node) => serializeBlock(node, opts, 0));\n return blocks\n .filter((b) => b !== null)\n .join(opts.newline + opts.newline)\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n}\n\nfunction serializeBlock(node: DocumentJSON, opts: ResolvedOptions, depth: number): string | null {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return serializeInline(node.content ?? [], opts);\n case 'blockquote':\n return (node.content ?? [])\n .map((child) => serializeBlock(child, opts, depth))\n .filter((b) => b !== null)\n .map((line) => `> ${line}`)\n .join(opts.newline);\n case 'bullet_list':\n case 'ordered_list':\n return serializeList(node, opts, depth);\n case 'horizontal_rule':\n return '---';\n case 'page_break':\n return '\\f';\n case 'table':\n return serializeTable(node, opts);\n default:\n // Unknown block: best-effort recurse so custom nodes still contribute text.\n if (node.content) {\n return node.content\n .map((child) => serializeBlock(child, opts, depth))\n .filter((b) => b !== null)\n .join(opts.newline);\n }\n return node.text ?? null;\n }\n}\n\nfunction serializeList(node: DocumentJSON, opts: ResolvedOptions, depth: number): string {\n const ordered = node.type === 'ordered_list';\n const start = ordered ? Number(node.attrs?.order ?? 1) : 0;\n const indent = ' '.repeat(depth);\n const lines: string[] = [];\n let index = start;\n\n for (const item of node.content ?? []) {\n if (item.type !== 'list_item') continue;\n const checked = item.attrs?.checked;\n let marker: string;\n if (checked === true) marker = '[x]';\n else if (checked === false) marker = '[ ]';\n else if (ordered) marker = `${index}.`;\n else marker = '-';\n\n const children = item.content ?? [];\n const firstBlock = children[0];\n const firstText = firstBlock ? (serializeBlock(firstBlock, opts, depth) ?? '') : '';\n lines.push(`${indent}${marker} ${firstText}`.trimEnd());\n\n for (let i = 1; i < children.length; i++) {\n const child = children[i]!;\n if (child.type === 'bullet_list' || child.type === 'ordered_list') {\n lines.push(serializeList(child, opts, depth + 1));\n } else {\n const text = serializeBlock(child, opts, depth + 1);\n if (text) lines.push(`${indent} ${text}`);\n }\n }\n if (ordered) index++;\n }\n return lines.join(opts.newline);\n}\n\nfunction serializeTable(node: DocumentJSON, opts: ResolvedOptions): string {\n const rows: string[] = [];\n for (const row of node.content ?? []) {\n if (row.type !== 'table_row') continue;\n const cells = (row.content ?? []).map((cell) =>\n (cell.content ?? [])\n .map((block) => serializeBlock(block, opts, 0))\n .filter((b) => b !== null)\n .join(' ')\n .replace(/\\t/g, ' '),\n );\n rows.push(cells.join('\\t'));\n }\n return rows.join(opts.newline);\n}\n\nfunction serializeInline(content: DocumentJSON[], opts: ResolvedOptions): string {\n let out = '';\n for (const node of content) {\n if (node.type === 'text') {\n let text = node.text ?? '';\n if (opts.includeLinkUrls && node.marks) {\n const link = node.marks.find((m) => m.type === 'link');\n if (link?.attrs?.href) text = `${text} (${String(link.attrs.href)})`;\n }\n out += text;\n } else if (node.type === 'hard_break') {\n out += opts.newline;\n } else if (node.type === 'image') {\n if (opts.images === 'alt') {\n const alt = node.attrs?.alt;\n if (alt) out += String(alt);\n }\n } else if (node.content) {\n out += serializeInline(node.content, opts);\n }\n }\n return out;\n}\n","import type * as DocxNamespace from 'docx';\nimport type { DocumentJSON, PageConfig } from '../config/types';\nimport { DEFAULT_PAGE, resolvePageDimensions } from '../config/defaults';\nimport { sanitizeUrl } from '../security/sanitize';\n\n/**\n * Isomorphic DOCX serializer (§8.3). Walks the document JSON and emits OOXML via\n * the `docx` library, which runs in both the browser (Blob) and Node\n * (Buffer/Stream). A per-node mapping is used so custom nodes can register their\n * own conversion (F-6.16, F-10.14). The `docx` module is imported lazily so it\n * stays out of the initial bundle (NF-2) and remains optional.\n */\n\n/** A converter for a custom node type, returning docx block elements. */\nexport type DocxNodeConverter = (\n node: DocumentJSON,\n ctx: DocxContext,\n) => unknown[];\n\nexport interface DocxExportOptions {\n page?: PageConfig;\n title?: string;\n /** Custom node converters keyed by node type name (extension mapping). */\n nodeConverters?: Record<string, DocxNodeConverter>;\n}\n\nexport interface DocxContext {\n serializeBlocks: (nodes: DocumentJSON[]) => unknown[];\n docx: DocxModule;\n}\n\ntype DocxModule = typeof DocxNamespace;\n\nlet docxModulePromise: Promise<DocxModule> | null = null;\nasync function loadDocx(): Promise<DocxModule> {\n if (!docxModulePromise) docxModulePromise = import('docx');\n return docxModulePromise;\n}\n\nconst HALF_POINT = 2; // docx font sizes are in half-points\nconst INDENT_TWIP_PER_LEVEL = 720; // 0.5 inch\n\nfunction toHex(value: unknown): string | null {\n const v = String(value ?? '').trim();\n const m = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.exec(v);\n if (!m) return null;\n const hex = m[1]!;\n return hex.length === 3\n ? hex\n .split('')\n .map((c) => c + c)\n .join('')\n : hex;\n}\n\ninterface MarkJSON {\n type: string;\n attrs?: Record<string, unknown>;\n}\n\nclass DocxSerializer {\n private docx!: DocxModule;\n private numberingConfigs: unknown[] = [];\n private refCounter = 0;\n private converters: Record<string, DocxNodeConverter>;\n\n constructor(converters: Record<string, DocxNodeConverter> = {}) {\n this.converters = converters;\n }\n\n private allocListRef(ordered: boolean): string {\n const d = this.docx;\n const reference = `rne-list-${this.refCounter++}`;\n const levels = Array.from({ length: 9 }, (_, level) => {\n if (ordered) {\n const formats = [\n d.LevelFormat.DECIMAL,\n d.LevelFormat.LOWER_LETTER,\n d.LevelFormat.LOWER_ROMAN,\n ];\n return {\n level,\n format: formats[level % 3]!,\n text: `%${level + 1}.`,\n alignment: d.AlignmentType.START,\n style: { paragraph: { indent: { left: (level + 1) * 720, hanging: 360 } } },\n };\n }\n const bullets = ['•', '◦', '▪'];\n return {\n level,\n format: d.LevelFormat.BULLET,\n text: bullets[level % 3]!,\n alignment: d.AlignmentType.START,\n style: { paragraph: { indent: { left: (level + 1) * 720, hanging: 360 } } },\n };\n });\n this.numberingConfigs.push({ reference, levels });\n return reference;\n }\n\n /** Build run options from a text node's marks. */\n private runOptions(marks: MarkJSON[]): Record<string, unknown> {\n const d = this.docx;\n const o: Record<string, unknown> = {};\n for (const mark of marks) {\n switch (mark.type) {\n case 'strong':\n o.bold = true;\n break;\n case 'em':\n o.italics = true;\n break;\n case 'underline':\n o.underline = {};\n break;\n case 'strikethrough':\n o.strike = true;\n break;\n case 'superscript':\n o.superScript = true;\n break;\n case 'subscript':\n o.subScript = true;\n break;\n case 'code':\n o.font = 'Courier New';\n break;\n case 'fontFamily':\n o.font = String(mark.attrs?.family ?? '');\n break;\n case 'fontSize': {\n const size = Number(mark.attrs?.size);\n if (Number.isFinite(size) && size > 0) o.size = Math.round(size * HALF_POINT);\n break;\n }\n case 'textColor': {\n const hex = toHex(mark.attrs?.color);\n if (hex) o.color = hex;\n break;\n }\n case 'highlight': {\n const hex = toHex(mark.attrs?.color);\n if (hex) o.shading = { type: d.ShadingType.CLEAR, fill: hex };\n break;\n }\n default:\n break;\n }\n }\n return o;\n }\n\n /** Serialize inline content into docx runs / hyperlinks. */\n private inlineChildren(content: DocumentJSON[] | undefined): unknown[] {\n const d = this.docx;\n if (!content) return [];\n const out: unknown[] = [];\n for (const node of content) {\n if (node.type === 'text') {\n const marks = (node.marks ?? []) as MarkJSON[];\n const link = marks.find((m) => m.type === 'link');\n const runOpts = this.runOptions(marks.filter((m) => m.type !== 'link'));\n const run = new d.TextRun({ text: node.text ?? '', ...runOpts });\n if (link?.attrs?.href) {\n const href = sanitizeUrl(String(link.attrs.href));\n if (href) {\n out.push(new d.ExternalHyperlink({ children: [run], link: href }));\n continue;\n }\n }\n out.push(run);\n } else if (node.type === 'hard_break') {\n out.push(new d.TextRun({ break: 1 }));\n } else if (node.type === 'image') {\n const img = this.imageRun(node);\n if (img) {\n out.push(img);\n } else {\n // Remote images can't be embedded synchronously; preserve the alt text\n // (or a placeholder) so information is not silently lost (F-6.17).\n const alt = node.attrs?.alt ? String(node.attrs.alt) : '[image]';\n out.push(new d.TextRun({ text: alt, italics: true }));\n }\n }\n }\n return out;\n }\n\n private imageRun(node: DocumentJSON): unknown | null {\n const d = this.docx;\n const src = String(node.attrs?.src ?? '');\n const match = /^data:image\\/(png|jpe?g|gif|bmp);base64,([A-Za-z0-9+/=]+)$/.exec(src);\n if (!match) return null; // remote images can't be fetched synchronously; skipped\n const raw = match[1]!;\n const type = raw === 'jpeg' ? 'jpg' : raw;\n const data = base64ToUint8(match[2]!);\n const width = Number(node.attrs?.width) || 300;\n const height = Math.round(width * 0.75);\n try {\n return new d.ImageRun({\n data,\n type: type as 'png' | 'jpg' | 'gif' | 'bmp',\n transformation: { width, height },\n });\n } catch {\n return null;\n }\n }\n\n private alignment(attrs: Record<string, unknown> | undefined): unknown {\n const d = this.docx;\n switch (attrs?.align) {\n case 'center':\n return d.AlignmentType.CENTER;\n case 'right':\n return d.AlignmentType.RIGHT;\n case 'justify':\n return d.AlignmentType.JUSTIFIED;\n case 'left':\n return d.AlignmentType.LEFT;\n default:\n return undefined;\n }\n }\n\n private paragraphProps(node: DocumentJSON): Record<string, unknown> {\n const props: Record<string, unknown> = {};\n const align = this.alignment(node.attrs);\n if (align !== undefined) props.alignment = align;\n const indent = Number(node.attrs?.indent ?? 0);\n if (indent > 0) props.indent = { left: indent * INDENT_TWIP_PER_LEVEL };\n const lineHeight = Number(node.attrs?.lineHeight);\n if (Number.isFinite(lineHeight) && lineHeight > 0) {\n props.spacing = { line: Math.round(lineHeight * 240), lineRule: 'auto' };\n }\n return props;\n }\n\n private headingLevel(level: number): unknown {\n const d = this.docx;\n const map = [\n d.HeadingLevel.HEADING_1,\n d.HeadingLevel.HEADING_2,\n d.HeadingLevel.HEADING_3,\n d.HeadingLevel.HEADING_4,\n d.HeadingLevel.HEADING_5,\n d.HeadingLevel.HEADING_6,\n ];\n return map[Math.min(5, Math.max(0, level - 1))];\n }\n\n serializeBlocks(nodes: DocumentJSON[]): unknown[] {\n const out: unknown[] = [];\n for (const node of nodes) out.push(...this.serializeBlock(node));\n return out;\n }\n\n private serializeBlock(node: DocumentJSON): unknown[] {\n const d = this.docx;\n const custom = this.converters[node.type];\n if (custom) {\n return custom(node, { serializeBlocks: (n) => this.serializeBlocks(n), docx: this.docx });\n }\n switch (node.type) {\n case 'paragraph':\n return [\n new d.Paragraph({\n ...this.paragraphProps(node),\n children: this.inlineChildren(node.content) as never,\n }),\n ];\n case 'heading':\n return [\n new d.Paragraph({\n ...this.paragraphProps(node),\n heading: this.headingLevel(Number(node.attrs?.level ?? 1)) as never,\n children: this.inlineChildren(node.content) as never,\n }),\n ];\n case 'blockquote':\n return (node.content ?? []).flatMap((child) => {\n const blocks = this.serializeBlock(child);\n return blocks;\n });\n case 'horizontal_rule':\n return [\n new d.Paragraph({\n border: { bottom: { style: d.BorderStyle.SINGLE, size: 6, space: 1, color: '999999' } },\n children: [],\n }),\n ];\n case 'page_break':\n return [new d.Paragraph({ children: [new d.PageBreak()] })];\n case 'bullet_list':\n case 'ordered_list':\n return this.serializeList(node, node.type === 'ordered_list', 0);\n case 'table':\n return [this.serializeTable(node)];\n default:\n if (node.content) return this.serializeBlocks(node.content);\n return [];\n }\n }\n\n private serializeList(node: DocumentJSON, ordered: boolean, level: number): unknown[] {\n const d = this.docx;\n const reference = this.allocListRef(ordered);\n const out: unknown[] = [];\n for (const item of node.content ?? []) {\n if (item.type !== 'list_item') continue;\n const children = item.content ?? [];\n const checked = item.attrs?.checked;\n const prefix =\n checked === true ? '☑ ' : checked === false ? '☐ ' : '';\n\n children.forEach((child, idx) => {\n if (child.type === 'bullet_list' || child.type === 'ordered_list') {\n out.push(...this.serializeList(child, child.type === 'ordered_list', level + 1));\n } else if (idx === 0) {\n const runs = this.inlineChildren(child.content);\n const first = prefix ? [new d.TextRun({ text: prefix }), ...runs] : runs;\n out.push(\n new d.Paragraph({\n numbering: { reference, level },\n children: first as never,\n }),\n );\n } else {\n out.push(\n new d.Paragraph({\n indent: { left: (level + 1) * INDENT_TWIP_PER_LEVEL },\n children: this.inlineChildren(child.content) as never,\n }),\n );\n }\n });\n }\n return out;\n }\n\n private serializeTable(node: DocumentJSON): unknown {\n const d = this.docx;\n const rows = (node.content ?? [])\n .filter((row) => row.type === 'table_row')\n .map((row) => {\n const cells = (row.content ?? []).map((cell) => {\n const fill = toHex(cell.attrs?.background);\n return new d.TableCell({\n children: this.serializeBlocks(cell.content ?? []) as never,\n columnSpan: Number(cell.attrs?.colspan ?? 1) || 1,\n rowSpan: Number(cell.attrs?.rowspan ?? 1) || 1,\n ...(fill ? { shading: { type: d.ShadingType.CLEAR, fill } } : {}),\n });\n });\n return new d.TableRow({ children: cells });\n });\n return new d.Table({\n rows,\n width: { size: 100, type: d.WidthType.PERCENTAGE },\n });\n }\n\n async build(doc: DocumentJSON, options: DocxExportOptions): Promise<unknown> {\n this.docx = await loadDocx();\n const d = this.docx;\n const page = options.page ?? DEFAULT_PAGE;\n const { width, height } = resolvePageDimensions(page);\n const children = this.serializeBlocks(doc.content ?? []);\n const mmToTwip = (mm: number) => Math.round((mm / 25.4) * 1440);\n\n return new d.Document({\n numbering: { config: this.numberingConfigs as never },\n sections: [\n {\n properties: {\n page: {\n size: { width: mmToTwip(width), height: mmToTwip(height) },\n margin: {\n top: mmToTwip(page.margins.top),\n right: mmToTwip(page.margins.right),\n bottom: mmToTwip(page.margins.bottom),\n left: mmToTwip(page.margins.left),\n },\n },\n },\n children: children as never,\n },\n ],\n });\n }\n}\n\nfunction base64ToUint8(b64: string): Uint8Array {\n if (typeof atob === 'function') {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n }\n // Node fallback.\n return new Uint8Array(Buffer.from(b64, 'base64'));\n}\n\n/** Serialize a document to a DOCX Blob for client-side download (F-6.1, F-6.6). */\nexport async function documentToDocxBlob(\n doc: DocumentJSON,\n options: DocxExportOptions = {},\n): Promise<Blob> {\n const serializer = new DocxSerializer(options.nodeConverters);\n const document = await serializer.build(doc, options);\n const { Packer } = await loadDocx();\n return Packer.toBlob(document as never);\n}\n\n/** Serialize a document to a DOCX Buffer for server-side storage (F-6.10). */\nexport async function documentToDocxBuffer(\n doc: DocumentJSON,\n options: DocxExportOptions = {},\n): Promise<Buffer> {\n const serializer = new DocxSerializer(options.nodeConverters);\n const document = await serializer.build(doc, options);\n const { Packer } = await loadDocx();\n return Packer.toBuffer(document as never);\n}\n"]}