@docen/docx 0.3.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{blockquote-DY80QC06.d.mts → blockquote-D-1aSxEn.d.mts} +5 -1
- package/dist/converters/docx.d.mts +40 -66
- package/dist/converters/docx.mjs +248 -665
- package/dist/converters/html.d.mts +1 -1
- package/dist/converters/html.mjs +3 -4
- package/dist/converters/markdown.d.mts +1 -1
- package/dist/converters/markdown.mjs +1 -1
- package/dist/converters/patch.d.mts +1 -1
- package/dist/converters/prepare.d.mts +1 -1
- package/dist/converters/styles.d.mts +58 -14
- package/dist/converters/styles.mjs +124 -16
- package/dist/{core-DC0_-WcE.d.mts → core-BqyLL84S.d.mts} +34 -13
- package/dist/{core-BnF8XhVE.mjs → core-wNNPJiKr.mjs} +357 -25
- package/dist/core.d.mts +1 -1
- package/dist/core.mjs +1 -1
- package/dist/details-DsJhDP5K.d.mts +31 -0
- package/dist/editor.d.mts +1 -1
- package/dist/editor.mjs +1 -1
- package/dist/extensions/blockquote.d.mts +2 -3
- package/dist/extensions/blockquote.mjs +50 -2
- package/dist/extensions/bullet-list.mjs +1 -1
- package/dist/extensions/code-block.d.mts +2 -2
- package/dist/extensions/code-block.mjs +51 -5
- package/dist/extensions/column-break.d.mts +2 -2
- package/dist/extensions/column-break.mjs +2 -2
- package/dist/extensions/details.d.mts +2 -3
- package/dist/extensions/details.mjs +48 -2
- package/dist/extensions/document.mjs +1 -1
- package/dist/extensions/extensions.d.mts +13 -9
- package/dist/extensions/extensions.mjs +7 -3
- package/dist/extensions/formatting-marks.d.mts +1 -1
- package/dist/extensions/formatting-marks.mjs +1 -1
- package/dist/extensions/heading.d.mts +2 -2
- package/dist/extensions/heading.mjs +61 -5
- package/dist/extensions/image.d.mts +2 -2
- package/dist/extensions/image.mjs +23 -4
- package/dist/extensions/index.d.mts +14 -10
- package/dist/extensions/index.mjs +8 -4
- package/dist/extensions/link.d.mts +2 -2
- package/dist/extensions/link.mjs +30 -2
- package/dist/extensions/list-aggregator.d.mts +8 -0
- package/dist/extensions/list-aggregator.mjs +2 -0
- package/dist/extensions/marks.d.mts +2 -0
- package/dist/extensions/marks.mjs +41 -0
- package/dist/extensions/mention.d.mts +2 -3
- package/dist/extensions/mention.mjs +16 -2
- package/dist/extensions/ordered-list.mjs +1 -1
- package/dist/extensions/page-break.d.mts +2 -2
- package/dist/extensions/page-break.mjs +2 -2
- package/dist/extensions/paragraph.mjs +3 -3
- package/dist/extensions/passthrough.d.mts +1 -1
- package/dist/extensions/passthrough.mjs +1 -1
- package/dist/extensions/scroll.d.mts +1 -1
- package/dist/extensions/scroll.mjs +30 -5
- package/dist/extensions/section-break.d.mts +1 -1
- package/dist/extensions/section-break.mjs +1 -1
- package/dist/extensions/strike.d.mts +2 -2
- package/dist/extensions/strike.mjs +5 -24
- package/dist/extensions/tab.d.mts +2 -2
- package/dist/extensions/tab.mjs +2 -2
- package/dist/extensions/table-cell.mjs +2 -2
- package/dist/extensions/table-header.mjs +2 -2
- package/dist/extensions/table-row.mjs +2 -2
- package/dist/extensions/table.d.mts +2 -2
- package/dist/extensions/table.mjs +122 -11
- package/dist/extensions/task-item.d.mts +2 -3
- package/dist/extensions/task-item.mjs +2 -2
- package/dist/extensions/text-style.d.mts +2 -2
- package/dist/extensions/text-style.mjs +27 -28
- package/dist/extensions/toc-field.d.mts +2 -2
- package/dist/extensions/toc-field.mjs +2 -2
- package/dist/extensions/track-change.d.mts +2 -0
- package/dist/extensions/track-change.mjs +2 -0
- package/dist/extensions/types.d.mts +127 -8
- package/dist/extensions/utils.d.mts +2 -2
- package/dist/extensions/utils.mjs +74 -1
- package/dist/extensions/wpg-group.d.mts +2 -2
- package/dist/extensions/wpg-group.mjs +2 -2
- package/dist/extensions/wps-shape.d.mts +2 -2
- package/dist/extensions/wps-shape.mjs +2 -2
- package/dist/heading-Bwpa8iZY.d.mts +24 -0
- package/dist/index.d.mts +29 -11
- package/dist/index.mjs +9 -5
- package/dist/{link-BawPjQZR.d.mts → link-gUqW45mE.d.mts} +3 -1
- package/dist/marks-Dz9Vb22Q.d.mts +10 -0
- package/dist/{mention-BGLzLVYw.d.mts → mention-CkONDrw9.d.mts} +5 -1
- package/dist/{scroll-ZNeThJsJ.d.mts → scroll-BARiZ5Gm.d.mts} +9 -3
- package/dist/strike-Brn9sWFy.d.mts +16 -0
- package/dist/table-CdcjR6HD.d.mts +18 -0
- package/dist/{task-item-B0ntvQ1Y.d.mts → task-item-CCAC4QLi.d.mts} +3 -1
- package/dist/text-style-BzfcbufI.d.mts +4 -0
- package/dist/{utils-BJwDQts7.d.mts → utils-CfwwOowz.d.mts} +25 -1
- package/package.json +1 -1
- package/dist/details-Dd5MqqmR.d.mts +0 -17
- package/dist/extensions/tiptap.d.mts +0 -2
- package/dist/extensions/tiptap.mjs +0 -31
- package/dist/heading-BvqBD2zX.d.mts +0 -8
- package/dist/strike-BgWGvjKr.d.mts +0 -33
- package/dist/table-BFkfeRp9.d.mts +0 -9
- package/dist/text-style-BHdtXkMb.d.mts +0 -8
- package/dist/tiptap-BKqn41uT.d.mts +0 -31
package/dist/converters/docx.mjs
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { alignmentFromCss } from "../extensions/utils.mjs";
|
|
2
|
+
import { buildTextBlock } from "./styles.mjs";
|
|
3
|
+
import { applyBlockquoteStyle } from "../extensions/blockquote.mjs";
|
|
4
|
+
import { h as docxExtensions } from "../core-wNNPJiKr.mjs";
|
|
3
5
|
import { DETAILS_SUMMARY_STYLE, DETAILS_TAG } from "../extensions/details.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { createMention, isMention, readMention } from "../extensions/mention.mjs";
|
|
6
|
+
import { createTaskCheckbox } from "../extensions/task-item.mjs";
|
|
7
|
+
import { createMention } from "../extensions/mention.mjs";
|
|
7
8
|
import { ORDERED_REFERENCE_PREFIX, buildOrderedLevels } from "../extensions/ordered-list.mjs";
|
|
8
|
-
import { parseDocx as parseDocx$2, renderDocx as renderDocx$3 } from "../extensions/paragraph.mjs";
|
|
9
|
-
import { parseDocx as parseDocx$3, renderDocx as renderDocx$4 } from "../extensions/strike.mjs";
|
|
10
|
-
import { parseDocx as parseDocx$4, renderDocx as renderDocx$5 } from "../extensions/table.mjs";
|
|
11
|
-
import { parseDocx as parseDocx$5, renderDocx as renderDocx$6 } from "../extensions/table-cell.mjs";
|
|
12
|
-
import { parseDocx as parseDocx$6, renderDocx as renderDocx$7 } from "../extensions/table-header.mjs";
|
|
13
|
-
import { parseDocx as parseDocx$7, renderDocx as renderDocx$8 } from "../extensions/table-row.mjs";
|
|
14
|
-
import { createTaskCheckbox, isTaskCheckbox, readCheckboxState } from "../extensions/task-item.mjs";
|
|
15
|
-
import { parseDocx as parseDocx$8, renderDocx as renderDocx$9 } from "../extensions/text-style.mjs";
|
|
16
9
|
import { prepareDocument } from "./prepare.mjs";
|
|
17
|
-
import {
|
|
10
|
+
import { flattenExtensions, getExtensionField, getSchema } from "@tiptap/core";
|
|
18
11
|
import { emojis, shortcodeToEmoji } from "@tiptap/extension-emoji";
|
|
19
12
|
import { generateDocument, generateDocumentStream, generateDocumentSync, parseDocument } from "@office-open/docx";
|
|
20
|
-
import { encodeBase64 } from "@office-open/core";
|
|
21
13
|
//#region src/converters/docx.ts
|
|
22
|
-
/** Remove keys with null/undefined values */
|
|
23
|
-
function cleanAttrs(attrs) {
|
|
24
|
-
const result = {};
|
|
25
|
-
for (const [key, value] of Object.entries(attrs)) if (value !== null && value !== void 0) result[key] = value;
|
|
26
|
-
return result;
|
|
27
|
-
}
|
|
28
14
|
/** True when two cell-margin sets (w:tcMar / w:tblCellMar) match on every side's
|
|
29
15
|
* size — used to detect a cell that merely echoes the table's default so its
|
|
30
16
|
* redundant tcMar can be dropped for a near-identity round-trip. */
|
|
@@ -37,6 +23,14 @@ function sameCellMargins(a, b) {
|
|
|
37
23
|
"left"
|
|
38
24
|
].every((k) => sz(a, k) === sz(b, k));
|
|
39
25
|
}
|
|
26
|
+
/** True when two single-side borders match on style/size/color — used to detect
|
|
27
|
+
* a cell side that merely echoes the table's insideHorizontal/insideVertical
|
|
28
|
+
* so it can be dropped for a near-identity round-trip (resolveTable pushes
|
|
29
|
+
* those table-level grid lines onto cell sides lacking their own tcBorder). */
|
|
30
|
+
function sameBorder(a, b) {
|
|
31
|
+
if (!a || !b) return false;
|
|
32
|
+
return a.style === b.style && a.size === b.size && a.color === b.color;
|
|
33
|
+
}
|
|
40
34
|
/** Keys round-tripped between DocumentOptions core properties and `doc.attrs.core`. */
|
|
41
35
|
const CORE_PROPERTY_KEYS = [
|
|
42
36
|
"title",
|
|
@@ -55,7 +49,7 @@ const CORE_PROPERTY_KEYS = [
|
|
|
55
49
|
* carries in dedicated attrs (styles/background/core). Excluded from the
|
|
56
50
|
* documentExtras pass-through so they aren't duplicated.
|
|
57
51
|
*/
|
|
58
|
-
const COMPILE_OWNED_KEYS = new Set([
|
|
52
|
+
const COMPILE_OWNED_KEYS = /* @__PURE__ */ new Set([
|
|
59
53
|
"sections",
|
|
60
54
|
"numbering",
|
|
61
55
|
"styles",
|
|
@@ -72,21 +66,6 @@ function extractCoreProperties(docOpts) {
|
|
|
72
66
|
}
|
|
73
67
|
return Object.keys(core).length > 0 ? core : null;
|
|
74
68
|
}
|
|
75
|
-
/** Merge consecutive text nodes with same marks */
|
|
76
|
-
function mergeTextNodes(nodes) {
|
|
77
|
-
const result = [];
|
|
78
|
-
for (const node of nodes) {
|
|
79
|
-
if (node.type === "text" && result.length > 0 && result[result.length - 1].type === "text") {
|
|
80
|
-
const prev = result[result.length - 1];
|
|
81
|
-
if (JSON.stringify(prev.marks) === JSON.stringify(node.marks)) {
|
|
82
|
-
prev.text = (prev.text ?? "") + (node.text ?? "");
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
result.push({ ...node });
|
|
87
|
-
}
|
|
88
|
-
return result;
|
|
89
|
-
}
|
|
90
69
|
/**
|
|
91
70
|
* Manages DOCX serialization (Tiptap JSON ↔ DocumentOptions).
|
|
92
71
|
*
|
|
@@ -97,6 +76,63 @@ var DocxManager = class {
|
|
|
97
76
|
numberingConfigs = [];
|
|
98
77
|
orderedInstanceCounter = 0;
|
|
99
78
|
resolveStyles;
|
|
79
|
+
resolveNumberingLookup;
|
|
80
|
+
markRender = /* @__PURE__ */ new Map();
|
|
81
|
+
markParse = [];
|
|
82
|
+
nodeRender = /* @__PURE__ */ new Map();
|
|
83
|
+
nodeParse = /* @__PURE__ */ new Map();
|
|
84
|
+
blockRules = [];
|
|
85
|
+
inlineRules = [];
|
|
86
|
+
paragraphRules = [];
|
|
87
|
+
aggregatorRules = [];
|
|
88
|
+
resolveCtx;
|
|
89
|
+
constructor(extensions = docxExtensions) {
|
|
90
|
+
const schema = getSchema(extensions);
|
|
91
|
+
for (const ext of flattenExtensions(extensions)) {
|
|
92
|
+
const name = ext.name;
|
|
93
|
+
if (!name) continue;
|
|
94
|
+
if (schema.marks[name]) {
|
|
95
|
+
const render = getExtensionField(ext, "renderDocx");
|
|
96
|
+
const parse = getExtensionField(ext, "parseDocx");
|
|
97
|
+
if (render) this.markRender.set(name, render);
|
|
98
|
+
if (parse) this.markParse.push({
|
|
99
|
+
name,
|
|
100
|
+
parse
|
|
101
|
+
});
|
|
102
|
+
} else if (schema.nodes[name]) {
|
|
103
|
+
const render = getExtensionField(ext, "renderDocx");
|
|
104
|
+
const parse = getExtensionField(ext, "parseDocx");
|
|
105
|
+
if (render) this.nodeRender.set(name, render);
|
|
106
|
+
if (parse) this.nodeParse.set(name, parse);
|
|
107
|
+
const blockRule = getExtensionField(ext, "parseDocxBlock");
|
|
108
|
+
if (blockRule) this.blockRules.push({
|
|
109
|
+
name,
|
|
110
|
+
rule: blockRule
|
|
111
|
+
});
|
|
112
|
+
const paraRule = getExtensionField(ext, "parseDocxParagraph");
|
|
113
|
+
if (paraRule) this.paragraphRules.push({
|
|
114
|
+
name,
|
|
115
|
+
rule: paraRule
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const inlineRule = getExtensionField(ext, "parseDocxInline");
|
|
119
|
+
if (inlineRule) this.inlineRules.push({
|
|
120
|
+
name,
|
|
121
|
+
rule: inlineRule
|
|
122
|
+
});
|
|
123
|
+
const aggregator = getExtensionField(ext, "parseDocxAggregator");
|
|
124
|
+
if (aggregator) this.aggregatorRules.push({
|
|
125
|
+
name,
|
|
126
|
+
rule: aggregator
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** Reflective node renderDocx lookup: the node's DOCX opts, or {} when the
|
|
131
|
+
* node type has no renderDocx hook (degrades to a plain paragraph). node.type
|
|
132
|
+
* is optional on JSONContent — an absent type simply misses the map. */
|
|
133
|
+
renderNodeOpts(node) {
|
|
134
|
+
return this.nodeRender.get(node.type ?? "")?.(node) ?? {};
|
|
135
|
+
}
|
|
100
136
|
compile(json) {
|
|
101
137
|
this.numberingConfigs = [];
|
|
102
138
|
this.orderedInstanceCounter = 0;
|
|
@@ -170,7 +206,7 @@ var DocxManager = class {
|
|
|
170
206
|
* Resolve a section's header/footer group (SectionChild[] per slot) into
|
|
171
207
|
* Tiptap JSON slots. Returns null when no slot has content.
|
|
172
208
|
*/
|
|
173
|
-
resolveHeaderFooter(group
|
|
209
|
+
resolveHeaderFooter(group) {
|
|
174
210
|
if (!group) return null;
|
|
175
211
|
const slots = {};
|
|
176
212
|
for (const slot of [
|
|
@@ -179,7 +215,7 @@ var DocxManager = class {
|
|
|
179
215
|
"even"
|
|
180
216
|
]) {
|
|
181
217
|
const children = group[slot];
|
|
182
|
-
if (children?.length) slots[slot] = this.resolveSectionChildren(children
|
|
218
|
+
if (children?.length) slots[slot] = this.resolveSectionChildren(children);
|
|
183
219
|
}
|
|
184
220
|
return Object.keys(slots).length > 0 ? slots : null;
|
|
185
221
|
}
|
|
@@ -190,17 +226,29 @@ var DocxManager = class {
|
|
|
190
226
|
type: "doc",
|
|
191
227
|
content: [{ type: "paragraph" }]
|
|
192
228
|
};
|
|
193
|
-
|
|
229
|
+
this.resolveNumberingLookup = this.buildNumberingLookup(docOpts);
|
|
230
|
+
const styles = this.resolveStyles;
|
|
231
|
+
this.resolveCtx = {
|
|
232
|
+
resolveBlockStream: (children) => this.resolveSectionChildren(children),
|
|
233
|
+
resolveBlock: (child) => this.resolveSectionChild(child),
|
|
234
|
+
resolveInlineContent: (para) => this.resolveInlineContent(para),
|
|
235
|
+
resolveInlineChildren: (children) => this.resolveParagraphChildren(children),
|
|
236
|
+
resolveParagraph: (para) => this.resolveParagraph(para),
|
|
237
|
+
parseNodeAttrs: (type, opts) => this.nodeParse.get(type)?.(opts) ?? {},
|
|
238
|
+
resolveMarks: (opts) => this.resolveMarks(opts),
|
|
239
|
+
styles,
|
|
240
|
+
numberingLookup: this.resolveNumberingLookup
|
|
241
|
+
};
|
|
194
242
|
const content = [];
|
|
195
243
|
const lastIndex = sections.length - 1;
|
|
196
244
|
for (let i = 0; i < sections.length; i++) {
|
|
197
245
|
const section = sections[i];
|
|
198
|
-
const sectionContent = this.resolveSectionChildren(section.children ?? []
|
|
246
|
+
const sectionContent = this.resolveSectionChildren(section.children ?? []);
|
|
199
247
|
if (i < lastIndex) {
|
|
200
248
|
const sectAttrs = {
|
|
201
249
|
sectionProperties: section.properties ?? null,
|
|
202
|
-
sectionHeaders: this.resolveHeaderFooter(section.headers
|
|
203
|
-
sectionFooters: this.resolveHeaderFooter(section.footers
|
|
250
|
+
sectionHeaders: this.resolveHeaderFooter(section.headers),
|
|
251
|
+
sectionFooters: this.resolveHeaderFooter(section.footers)
|
|
204
252
|
};
|
|
205
253
|
const last = sectionContent[sectionContent.length - 1];
|
|
206
254
|
if (last?.type === "paragraph") last.attrs = {
|
|
@@ -226,9 +274,9 @@ var DocxManager = class {
|
|
|
226
274
|
if (core) attrs.core = core;
|
|
227
275
|
const lastSection = sections[lastIndex];
|
|
228
276
|
if (lastSection.properties) attrs.sectionProperties = lastSection.properties;
|
|
229
|
-
const lastHeaders = this.resolveHeaderFooter(lastSection.headers
|
|
277
|
+
const lastHeaders = this.resolveHeaderFooter(lastSection.headers);
|
|
230
278
|
if (lastHeaders) attrs.sectionHeaders = lastHeaders;
|
|
231
|
-
const lastFooters = this.resolveHeaderFooter(lastSection.footers
|
|
279
|
+
const lastFooters = this.resolveHeaderFooter(lastSection.footers);
|
|
232
280
|
if (lastFooters) attrs.sectionFooters = lastFooters;
|
|
233
281
|
const documentExtras = {};
|
|
234
282
|
for (const [k, v] of Object.entries(docOpts)) {
|
|
@@ -255,7 +303,7 @@ var DocxManager = class {
|
|
|
255
303
|
return items.length > 0 ? items : null;
|
|
256
304
|
}
|
|
257
305
|
case "codeBlock": {
|
|
258
|
-
const opts =
|
|
306
|
+
const opts = this.renderNodeOpts(node);
|
|
259
307
|
const childList = this.compileInlineContent(node.content);
|
|
260
308
|
if (childList.length > 0) opts.children = childList;
|
|
261
309
|
return { paragraph: this.simplifyParagraph(opts) };
|
|
@@ -263,7 +311,7 @@ var DocxManager = class {
|
|
|
263
311
|
case "horizontalRule": return { paragraph: { thematicBreak: true } };
|
|
264
312
|
case "table": return { table: this.compileTableNode(node) };
|
|
265
313
|
case "image": {
|
|
266
|
-
const imageRun =
|
|
314
|
+
const imageRun = this.nodeRender.get(node.type)?.(node) ?? null;
|
|
267
315
|
if (!imageRun) return null;
|
|
268
316
|
return { paragraph: { children: [imageRun] } };
|
|
269
317
|
}
|
|
@@ -297,13 +345,13 @@ var DocxManager = class {
|
|
|
297
345
|
}
|
|
298
346
|
}
|
|
299
347
|
compileParagraphNode(node) {
|
|
300
|
-
const opts =
|
|
348
|
+
const opts = this.renderNodeOpts(node);
|
|
301
349
|
const childList = this.compileInlineContent(node.content);
|
|
302
350
|
if (childList.length > 0) opts.children = childList;
|
|
303
351
|
return this.simplifyParagraph(opts);
|
|
304
352
|
}
|
|
305
353
|
compileHeadingNode(node) {
|
|
306
|
-
const opts =
|
|
354
|
+
const opts = this.renderNodeOpts(node);
|
|
307
355
|
const childList = this.compileInlineContent(node.content);
|
|
308
356
|
if (childList.length > 0) opts.children = childList;
|
|
309
357
|
return this.simplifyParagraph(opts);
|
|
@@ -321,14 +369,17 @@ var DocxManager = class {
|
|
|
321
369
|
return opts;
|
|
322
370
|
}
|
|
323
371
|
compileTableNode(node) {
|
|
324
|
-
const opts =
|
|
372
|
+
const opts = this.renderNodeOpts(node);
|
|
325
373
|
const colCount = this.getTableColumnCount(node);
|
|
326
374
|
const tableCellMargins = opts.cellMargin ?? opts.margins ?? null;
|
|
375
|
+
const tableBorders = opts.borders ?? null;
|
|
376
|
+
const insideH = tableBorders?.insideHorizontal ?? null;
|
|
377
|
+
const insideV = tableBorders?.insideVertical ?? null;
|
|
327
378
|
const rows = [];
|
|
328
379
|
let activeSpans = [];
|
|
329
380
|
for (const rowNode of node.content ?? []) {
|
|
330
381
|
if (rowNode.type !== "tableRow") continue;
|
|
331
|
-
const rowOpts =
|
|
382
|
+
const rowOpts = this.nodeRender.get(rowNode.type)?.(rowNode) ?? {};
|
|
332
383
|
const pmCells = (rowNode.content ?? []).filter((c) => c.type === "tableCell" || c.type === "tableHeader");
|
|
333
384
|
const currentSpans = [...activeSpans].sort((a, b) => a.colStart - b.colStart);
|
|
334
385
|
const newSpans = [];
|
|
@@ -349,7 +400,7 @@ var DocxManager = class {
|
|
|
349
400
|
colIdx += span.colspan;
|
|
350
401
|
spanIdx++;
|
|
351
402
|
} else {
|
|
352
|
-
const cell = this.compileTableCellNode(pmCells[cellIdx], tableCellMargins);
|
|
403
|
+
const cell = this.compileTableCellNode(pmCells[cellIdx], tableCellMargins, insideH, insideV);
|
|
353
404
|
const cs = cell.columnSpan ?? 1;
|
|
354
405
|
const rs = cell.rowSpan ?? 1;
|
|
355
406
|
if (rs > 1) {
|
|
@@ -446,16 +497,35 @@ var DocxManager = class {
|
|
|
446
497
|
}
|
|
447
498
|
};
|
|
448
499
|
}
|
|
449
|
-
compileTableCellNode(cellNode, tableMargins) {
|
|
450
|
-
const cellOpts =
|
|
500
|
+
compileTableCellNode(cellNode, tableMargins, insideH, insideV) {
|
|
501
|
+
const cellOpts = this.renderNodeOpts(cellNode);
|
|
451
502
|
if (tableMargins && cellOpts.margins && sameCellMargins(cellOpts.margins, tableMargins)) delete cellOpts.margins;
|
|
452
|
-
|
|
503
|
+
if ((insideH || insideV) && cellOpts.borders) {
|
|
504
|
+
const b = cellOpts.borders;
|
|
505
|
+
if (insideH && sameBorder(b.top, insideH)) delete b.top;
|
|
506
|
+
if (insideH && sameBorder(b.bottom, insideH)) delete b.bottom;
|
|
507
|
+
if (insideV && sameBorder(b.left, insideV)) delete b.left;
|
|
508
|
+
if (insideV && sameBorder(b.right, insideV)) delete b.right;
|
|
509
|
+
if (Object.keys(b).length === 0) delete cellOpts.borders;
|
|
510
|
+
}
|
|
511
|
+
const cellAlign = alignmentFromCss(cellNode.attrs?.align ?? null);
|
|
453
512
|
const cellChildren = [];
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
513
|
+
const pushChild = (child) => {
|
|
514
|
+
if (cellAlign && typeof child === "object" && child !== null && "paragraph" in child) {
|
|
515
|
+
const p = child.paragraph;
|
|
516
|
+
if (typeof p === "string") child.paragraph = {
|
|
517
|
+
text: p,
|
|
518
|
+
alignment: cellAlign
|
|
519
|
+
};
|
|
520
|
+
else if (p && typeof p === "object" && !p.alignment) p.alignment = cellAlign;
|
|
521
|
+
}
|
|
522
|
+
cellChildren.push(child);
|
|
523
|
+
};
|
|
524
|
+
for (const childNode of cellNode.content ?? []) {
|
|
525
|
+
const compiled = this.compileSectionChild(childNode);
|
|
526
|
+
if (compiled == null) continue;
|
|
527
|
+
if (Array.isArray(compiled)) compiled.forEach(pushChild);
|
|
528
|
+
else pushChild(compiled);
|
|
459
529
|
}
|
|
460
530
|
if (cellChildren.length > 0) cellOpts.children = cellChildren;
|
|
461
531
|
return cellOpts;
|
|
@@ -582,7 +652,7 @@ var DocxManager = class {
|
|
|
582
652
|
break;
|
|
583
653
|
}
|
|
584
654
|
case "image": {
|
|
585
|
-
const imageRun =
|
|
655
|
+
const imageRun = this.nodeRender.get(node.type)?.(node) ?? null;
|
|
586
656
|
if (imageRun) children.push(imageRun);
|
|
587
657
|
break;
|
|
588
658
|
}
|
|
@@ -630,69 +700,65 @@ var DocxManager = class {
|
|
|
630
700
|
/** Emit a single run for `text` with all inline marks applied. */
|
|
631
701
|
compileTextRun(text, marks, children) {
|
|
632
702
|
const runOpts = { text };
|
|
633
|
-
for (const mark of marks ?? [])
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
runOpts.superScript = true;
|
|
653
|
-
break;
|
|
654
|
-
case "highlight":
|
|
655
|
-
runOpts.highlight = mark.attrs?.color ?? "yellow";
|
|
656
|
-
break;
|
|
657
|
-
case "code":
|
|
658
|
-
runOpts.style = "CodeChar";
|
|
659
|
-
runOpts.font = "Consolas";
|
|
660
|
-
break;
|
|
661
|
-
case "textStyle": {
|
|
662
|
-
const tsProps = renderDocx$9(mark.attrs ?? {});
|
|
663
|
-
Object.assign(runOpts, tsProps);
|
|
664
|
-
break;
|
|
665
|
-
}
|
|
666
|
-
case "link": {
|
|
667
|
-
const href = mark.attrs?.href;
|
|
668
|
-
if (href) {
|
|
669
|
-
const { text: _, ...runWithoutText } = runOpts;
|
|
670
|
-
const linkChildren = [];
|
|
671
|
-
if (text) linkChildren.push({
|
|
672
|
-
...runWithoutText,
|
|
673
|
-
text
|
|
674
|
-
});
|
|
675
|
-
children.push({ hyperlink: {
|
|
676
|
-
link: href.startsWith("#") ? void 0 : href,
|
|
677
|
-
anchor: href.startsWith("#") ? href.slice(1) : void 0,
|
|
678
|
-
children: linkChildren
|
|
679
|
-
} });
|
|
680
|
-
return;
|
|
703
|
+
for (const mark of marks ?? []) {
|
|
704
|
+
switch (mark.type) {
|
|
705
|
+
case "link": {
|
|
706
|
+
const href = mark.attrs?.href;
|
|
707
|
+
if (href) {
|
|
708
|
+
const { text: _, ...runWithoutText } = runOpts;
|
|
709
|
+
const linkChildren = [];
|
|
710
|
+
if (text) linkChildren.push({
|
|
711
|
+
...runWithoutText,
|
|
712
|
+
text
|
|
713
|
+
});
|
|
714
|
+
children.push({ hyperlink: {
|
|
715
|
+
link: href.startsWith("#") ? void 0 : href,
|
|
716
|
+
anchor: href.startsWith("#") ? href.slice(1) : void 0,
|
|
717
|
+
children: linkChildren
|
|
718
|
+
} });
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
break;
|
|
681
722
|
}
|
|
682
|
-
|
|
723
|
+
case "insertion":
|
|
724
|
+
case "deletion":
|
|
725
|
+
children.push(this.compileTrackedChangeRun(mark.type, mark.attrs, text, runOpts));
|
|
726
|
+
return;
|
|
683
727
|
}
|
|
728
|
+
const render = this.markRender.get(mark.type);
|
|
729
|
+
if (render) Object.assign(runOpts, render(mark.attrs ?? {}));
|
|
684
730
|
}
|
|
685
731
|
children.push(runOpts);
|
|
686
732
|
}
|
|
733
|
+
/**
|
|
734
|
+
* Wrap a run back into a w:ins/w:del container — the reverse of
|
|
735
|
+
* resolveTrackedChange. A literal-key ternary (`{insertion: body}` /
|
|
736
|
+
* `{deletion: body}`) lets TS narrow to the ParagraphChild branch without a
|
|
737
|
+
* cast, and `typeof` guards read `attrs` type-safely (no `as number/string`).
|
|
738
|
+
* stringifyDeletedRun emits `<w:delText>` automatically for deletion children.
|
|
739
|
+
*/
|
|
740
|
+
compileTrackedChangeRun(type, attrs, text, runOpts) {
|
|
741
|
+
const { text: _, ...runWithoutText } = runOpts;
|
|
742
|
+
const trackChildren = [];
|
|
743
|
+
if (text) trackChildren.push({
|
|
744
|
+
...runWithoutText,
|
|
745
|
+
text
|
|
746
|
+
});
|
|
747
|
+
const body = {
|
|
748
|
+
id: typeof attrs?.id === "number" ? attrs.id : 0,
|
|
749
|
+
author: typeof attrs?.author === "string" ? attrs.author : "",
|
|
750
|
+
date: typeof attrs?.date === "string" ? attrs.date : "",
|
|
751
|
+
children: trackChildren
|
|
752
|
+
};
|
|
753
|
+
return type === "insertion" ? { insertion: body } : { deletion: body };
|
|
754
|
+
}
|
|
687
755
|
resolveSectionChild(child) {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
if (sdt.properties?.tag === "docen-details") return this.resolveDetailsSdt(sdt);
|
|
693
|
-
return this.resolvePassthrough(child);
|
|
756
|
+
const ctx = this.resolveCtx;
|
|
757
|
+
for (const { rule } of this.blockRules) if (rule.match(child, ctx)) {
|
|
758
|
+
const node = rule.convert(child, ctx);
|
|
759
|
+
if (node) return node;
|
|
694
760
|
}
|
|
695
|
-
if ("
|
|
761
|
+
if ("paragraph" in child) return this.resolveParagraph(child.paragraph);
|
|
696
762
|
return this.resolvePassthrough(child);
|
|
697
763
|
}
|
|
698
764
|
/** Wrap an opaque SectionChild in a passthrough atom (attrs.data = JSON). */
|
|
@@ -702,116 +768,15 @@ var DocxManager = class {
|
|
|
702
768
|
attrs: { data: JSON.stringify(child) }
|
|
703
769
|
};
|
|
704
770
|
}
|
|
705
|
-
/**
|
|
706
|
-
* Resolve a table of contents into an editable `tableOfContents` container:
|
|
707
|
-
* `attrs.options` carries the field switches, `content` is the entry
|
|
708
|
-
* paragraphs. Each entry's inner HYPERLINK field has content-less runs that
|
|
709
|
-
* office-open parses as `null`; resolving the entries through
|
|
710
|
-
* `resolveSectionChild` → `resolveParagraphChildren` drops those nulls, so the
|
|
711
|
-
* TOC no longer reaches the generate path as an opaque blob of nulls (the
|
|
712
|
-
* `stringifyRunInline(null).break` crash). When `entries` is absent/empty
|
|
713
|
-
* (a fresh, unrendered TOC), keep the node valid for `content: "block+"` with
|
|
714
|
-
* a placeholder empty paragraph.
|
|
715
|
-
*/
|
|
716
|
-
resolveToc(toc) {
|
|
717
|
-
const { entries, ...options } = toc;
|
|
718
|
-
const content = [];
|
|
719
|
-
for (const entry of entries ?? []) {
|
|
720
|
-
const node = this.resolveSectionChild(entry);
|
|
721
|
-
if (!node) continue;
|
|
722
|
-
if (Array.isArray(node)) content.push(...node);
|
|
723
|
-
else content.push(node);
|
|
724
|
-
}
|
|
725
|
-
if (content.length === 0) content.push({ type: "paragraph" });
|
|
726
|
-
const node = {
|
|
727
|
-
type: "tocField",
|
|
728
|
-
content
|
|
729
|
-
};
|
|
730
|
-
const cleanOptions = cleanAttrs(options);
|
|
731
|
-
if (Object.keys(cleanOptions).length > 0) node.attrs = { options: cleanOptions };
|
|
732
|
-
return node;
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* Resolve a details group-SDT: the summary-style paragraph becomes
|
|
736
|
-
* detailsSummary, the remaining blocks fold into detailsContent.
|
|
737
|
-
*/
|
|
738
|
-
resolveDetailsSdt(sdt) {
|
|
739
|
-
const content = [];
|
|
740
|
-
let summary = null;
|
|
741
|
-
for (const child of sdt.children ?? []) {
|
|
742
|
-
if ("paragraph" in child) {
|
|
743
|
-
const para = child.paragraph;
|
|
744
|
-
if (para.style === "DocenDetailsSummary") {
|
|
745
|
-
summary = this.resolveInlineContent(para);
|
|
746
|
-
continue;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
const node = this.resolveSectionChild(child);
|
|
750
|
-
if (!node) continue;
|
|
751
|
-
if (Array.isArray(node)) content.push(...node);
|
|
752
|
-
else content.push(node);
|
|
753
|
-
}
|
|
754
|
-
const details = {
|
|
755
|
-
type: "details",
|
|
756
|
-
content: []
|
|
757
|
-
};
|
|
758
|
-
if (summary !== null) details.content.push({
|
|
759
|
-
type: "detailsSummary",
|
|
760
|
-
content: summary
|
|
761
|
-
});
|
|
762
|
-
if (content.length > 0) details.content.push({
|
|
763
|
-
type: "detailsContent",
|
|
764
|
-
content
|
|
765
|
-
});
|
|
766
|
-
return details;
|
|
767
|
-
}
|
|
768
771
|
resolveParagraph(opts) {
|
|
769
772
|
const resolved = typeof opts === "string" ? { text: opts } : opts;
|
|
770
773
|
if (resolved.thematicBreak) return { type: "horizontalRule" };
|
|
771
|
-
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
if (headingLevel && attrs.level == null) attrs.level = headingLevel;
|
|
776
|
-
const content = this.resolveInlineContent(resolved);
|
|
777
|
-
const cleanAttrsObj = cleanAttrs(attrs);
|
|
778
|
-
const node = { type: nodeType };
|
|
779
|
-
if (Object.keys(cleanAttrsObj).length > 0) node.attrs = cleanAttrsObj;
|
|
780
|
-
if (content.length > 0) node.content = content;
|
|
781
|
-
return node;
|
|
782
|
-
}
|
|
783
|
-
/** Heading level (1-9) for a paragraph, or undefined when it isn't a heading.
|
|
784
|
-
* DOCX marks a heading several ways, checked in priority order:
|
|
785
|
-
* 1. office-open lifts a HeadingLevel pStyle ("Heading1".."Title") into `heading`.
|
|
786
|
-
* 2. An explicit `outlineLevel` (0-8 → 1-9) — Word's outline/TOC key off this
|
|
787
|
-
* even without a heading pStyle; the Heading1-9 styles carry outlineLvl 0-8.
|
|
788
|
-
* 3. A pStyle that names a heading style: directly ("Heading7", which stays on
|
|
789
|
-
* `style` because office-open's HeadingLevel type caps at 6), by localized
|
|
790
|
-
* NAME ("heading 1"/"标题 1"), or via the `basedOn` chain (a custom style
|
|
791
|
-
* "MyTitle" basedOn="Heading1"). `heading` and `style` carry the same pStyle.
|
|
792
|
-
* `outlineLevel` is read loosely — office-open's public type omits the field
|
|
793
|
-
* even though it round-trips (w:outlineLvl) at runtime. */
|
|
794
|
-
detectHeadingLevel(resolved) {
|
|
795
|
-
if (resolved.heading) {
|
|
796
|
-
const lvl = HEADING_LEVEL_MAP[resolved.heading];
|
|
797
|
-
if (lvl) return lvl;
|
|
798
|
-
}
|
|
799
|
-
const outline = resolved.outlineLevel;
|
|
800
|
-
if (typeof outline === "number" && outline >= 0 && outline <= 8) return outline + 1;
|
|
801
|
-
const styleId = resolved.style;
|
|
802
|
-
if (!styleId || !this.resolveStyles) return void 0;
|
|
803
|
-
const byId = indexParagraphStyles(this.resolveStyles);
|
|
804
|
-
const visited = /* @__PURE__ */ new Set();
|
|
805
|
-
let curId = styleId;
|
|
806
|
-
while (curId && !visited.has(curId)) {
|
|
807
|
-
visited.add(curId);
|
|
808
|
-
if (HEADING_LEVEL_MAP[curId]) return HEADING_LEVEL_MAP[curId];
|
|
809
|
-
const style = byId.get(curId);
|
|
810
|
-
if (!style) break;
|
|
811
|
-
const lvl = headingLevelFromName(style.name);
|
|
812
|
-
if (lvl) return lvl;
|
|
813
|
-
curId = style.basedOn ?? void 0;
|
|
774
|
+
const ctx = this.resolveCtx;
|
|
775
|
+
for (const { rule } of this.paragraphRules) if (rule.match(resolved, ctx)) {
|
|
776
|
+
const node = rule.convert(resolved, ctx);
|
|
777
|
+
if (node) return node;
|
|
814
778
|
}
|
|
779
|
+
return buildTextBlock("paragraph", resolved, ctx);
|
|
815
780
|
}
|
|
816
781
|
/** reference → level-0 format/start, for classifying numbering paragraphs. */
|
|
817
782
|
buildNumberingLookup(docOpts) {
|
|
@@ -827,309 +792,43 @@ var DocxManager = class {
|
|
|
827
792
|
return lookup;
|
|
828
793
|
}
|
|
829
794
|
/**
|
|
830
|
-
* Walk
|
|
831
|
-
*
|
|
832
|
-
*
|
|
795
|
+
* Walk a SectionChild[] block stream — a section's body, a header/footer
|
|
796
|
+
* slot, or a table cell's children (a cell is just another block stream). An
|
|
797
|
+
* aggregator rule (list/blockquote) claims consecutive paragraphs sharing its
|
|
798
|
+
* predicate and rebuilds them as a composite; everything else resolves
|
|
799
|
+
* individually via resolveSectionChild. The manager owns only the generic
|
|
800
|
+
* group-by loop — the predicate (belongs) + builder (build) come from each
|
|
801
|
+
* rule, so a custom composite plugs in by declaring parseDocxAggregator.
|
|
833
802
|
*/
|
|
834
|
-
resolveSectionChildren(children
|
|
803
|
+
resolveSectionChildren(children) {
|
|
804
|
+
const ctx = this.resolveCtx;
|
|
835
805
|
const content = [];
|
|
836
806
|
let i = 0;
|
|
837
807
|
while (i < children.length) {
|
|
838
808
|
const child = children[i];
|
|
839
809
|
const firstPara = "paragraph" in child ? child.paragraph : null;
|
|
840
|
-
if (
|
|
841
|
-
|
|
810
|
+
if (firstPara && typeof firstPara !== "string") {
|
|
811
|
+
const rule = this.aggregatorRules.find((r) => r.rule.belongs(firstPara, ctx));
|
|
812
|
+
if (rule) {
|
|
842
813
|
const group = [];
|
|
843
814
|
while (i < children.length) {
|
|
844
815
|
const member = children[i];
|
|
845
816
|
if (!("paragraph" in member)) break;
|
|
846
817
|
const para = member.paragraph;
|
|
847
|
-
if (typeof para === "string" || !
|
|
818
|
+
if (typeof para === "string" || !rule.rule.belongs(para, ctx)) break;
|
|
848
819
|
group.push(para);
|
|
849
820
|
i++;
|
|
850
821
|
}
|
|
851
|
-
content.push(
|
|
822
|
+
content.push(...rule.rule.build(group, ctx));
|
|
852
823
|
continue;
|
|
853
824
|
}
|
|
854
|
-
const node = this.resolveSectionChild(child);
|
|
855
|
-
if (node) content.push(node);
|
|
856
|
-
i++;
|
|
857
|
-
continue;
|
|
858
|
-
}
|
|
859
|
-
const group = [];
|
|
860
|
-
while (i < children.length) {
|
|
861
|
-
const member = children[i];
|
|
862
|
-
if (!("paragraph" in member)) break;
|
|
863
|
-
const para = member.paragraph;
|
|
864
|
-
if (typeof para === "string") break;
|
|
865
|
-
const info = this.detectList(para, numberingLookup);
|
|
866
|
-
if (!info) break;
|
|
867
|
-
group.push({
|
|
868
|
-
para,
|
|
869
|
-
info
|
|
870
|
-
});
|
|
871
|
-
i++;
|
|
872
825
|
}
|
|
873
|
-
|
|
826
|
+
const node = this.resolveSectionChild(child);
|
|
827
|
+
if (node) content.push(node);
|
|
828
|
+
i++;
|
|
874
829
|
}
|
|
875
830
|
return content;
|
|
876
831
|
}
|
|
877
|
-
/** Classify a paragraph as a list item, or null if it isn't one. */
|
|
878
|
-
detectList(para, lookup) {
|
|
879
|
-
const p = para;
|
|
880
|
-
const numbering = p.numbering;
|
|
881
|
-
const bullet = p.bullet;
|
|
882
|
-
let kind;
|
|
883
|
-
let level;
|
|
884
|
-
let reference;
|
|
885
|
-
let start;
|
|
886
|
-
if (numbering) {
|
|
887
|
-
reference = numbering.reference;
|
|
888
|
-
level = numbering.level ?? 0;
|
|
889
|
-
const cfg = reference ? lookup.get(reference) : void 0;
|
|
890
|
-
if (cfg && cfg.format && cfg.format !== "bullet") {
|
|
891
|
-
kind = "ordered";
|
|
892
|
-
start = cfg.start;
|
|
893
|
-
} else kind = "bullet";
|
|
894
|
-
} else if (bullet) {
|
|
895
|
-
kind = "bullet";
|
|
896
|
-
level = bullet.level ?? 0;
|
|
897
|
-
} else return null;
|
|
898
|
-
const first = p.children?.[0];
|
|
899
|
-
return {
|
|
900
|
-
kind: isTaskCheckbox(first) ? "task" : kind,
|
|
901
|
-
level,
|
|
902
|
-
reference,
|
|
903
|
-
start,
|
|
904
|
-
checked: readCheckboxState(first)
|
|
905
|
-
};
|
|
906
|
-
}
|
|
907
|
-
/**
|
|
908
|
-
* Rebuild nested Tiptap lists from a flat run of list paragraphs. Stack-based:
|
|
909
|
-
* each frame is an active list at a given depth; the `key` (level:type:
|
|
910
|
-
* reference) decides whether a paragraph continues the top list, starts a
|
|
911
|
-
* nested list, or splits off a new sibling list.
|
|
912
|
-
*/
|
|
913
|
-
buildListTree(group) {
|
|
914
|
-
const topLevel = [];
|
|
915
|
-
const stack = [];
|
|
916
|
-
for (const { para, info } of group) {
|
|
917
|
-
const listType = info.kind === "ordered" ? "orderedList" : info.kind === "task" ? "taskList" : "bulletList";
|
|
918
|
-
const itemType = info.kind === "task" ? "taskItem" : "listItem";
|
|
919
|
-
const key = `${info.level}:${listType}:${info.reference ?? ""}`;
|
|
920
|
-
while (stack.length > 0) {
|
|
921
|
-
const top = stack[stack.length - 1];
|
|
922
|
-
if (top.level > info.level || top.level === info.level && top.key !== key) {
|
|
923
|
-
stack.pop();
|
|
924
|
-
continue;
|
|
925
|
-
}
|
|
926
|
-
break;
|
|
927
|
-
}
|
|
928
|
-
const newItem = {
|
|
929
|
-
type: itemType,
|
|
930
|
-
content: [this.resolveListItemParagraph(para, info)]
|
|
931
|
-
};
|
|
932
|
-
if (itemType === "taskItem") newItem.attrs = { checked: info.checked };
|
|
933
|
-
const top = stack[stack.length - 1];
|
|
934
|
-
if (top && top.level === info.level && top.key === key) {
|
|
935
|
-
top.listNode.content.push(newItem);
|
|
936
|
-
top.currentItem = newItem;
|
|
937
|
-
} else {
|
|
938
|
-
const newList = {
|
|
939
|
-
type: listType,
|
|
940
|
-
content: [newItem]
|
|
941
|
-
};
|
|
942
|
-
const listAttrs = {};
|
|
943
|
-
if (listType === "orderedList" && info.level === 0 && typeof info.start === "number" && info.start !== 1) listAttrs.start = info.start;
|
|
944
|
-
if (info.reference) listAttrs.numbering = info.reference;
|
|
945
|
-
if (Object.keys(listAttrs).length > 0) newList.attrs = listAttrs;
|
|
946
|
-
if (top) top.currentItem.content.push(newList);
|
|
947
|
-
else topLevel.push(newList);
|
|
948
|
-
stack.push({
|
|
949
|
-
level: info.level,
|
|
950
|
-
key,
|
|
951
|
-
listNode: newList,
|
|
952
|
-
currentItem: newItem
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
return topLevel;
|
|
957
|
-
}
|
|
958
|
-
/** Classify a paragraph as a blockquote member by its signature. */
|
|
959
|
-
detectBlockquote(para) {
|
|
960
|
-
const p = para;
|
|
961
|
-
const indent = p.indent;
|
|
962
|
-
const border = p.border;
|
|
963
|
-
if (!indent || indent.left !== 720) return false;
|
|
964
|
-
const bl = border?.left;
|
|
965
|
-
if (!bl) return false;
|
|
966
|
-
const sig = BLOCKQUOTE_BORDER;
|
|
967
|
-
return bl.style === sig.style && bl.size === sig.size && bl.space === sig.space && bl.color === sig.color;
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Rebuild a blockquote node from a run of signature-carrying paragraphs,
|
|
971
|
-
* stripping the indent/border signature so child paragraphs render clean.
|
|
972
|
-
*/
|
|
973
|
-
buildBlockquote(group) {
|
|
974
|
-
const content = [];
|
|
975
|
-
for (const para of group) {
|
|
976
|
-
const node = this.resolveParagraph(para);
|
|
977
|
-
const attrs = node.attrs;
|
|
978
|
-
if (attrs) {
|
|
979
|
-
if (attrs.indent) {
|
|
980
|
-
const indent = { ...attrs.indent };
|
|
981
|
-
delete indent.left;
|
|
982
|
-
attrs.indent = Object.keys(indent).length > 0 ? indent : void 0;
|
|
983
|
-
}
|
|
984
|
-
if (attrs.border) {
|
|
985
|
-
const border = { ...attrs.border };
|
|
986
|
-
delete border.left;
|
|
987
|
-
attrs.border = Object.keys(border).length > 0 ? border : void 0;
|
|
988
|
-
}
|
|
989
|
-
const cleaned = cleanAttrs(attrs);
|
|
990
|
-
if (Object.keys(cleaned).length > 0) node.attrs = cleaned;
|
|
991
|
-
else delete node.attrs;
|
|
992
|
-
}
|
|
993
|
-
content.push(node);
|
|
994
|
-
}
|
|
995
|
-
return {
|
|
996
|
-
type: "blockquote",
|
|
997
|
-
content
|
|
998
|
-
};
|
|
999
|
-
}
|
|
1000
|
-
/**
|
|
1001
|
-
* Resolve a list-item paragraph to a Tiptap paragraph/heading node, stripping
|
|
1002
|
-
* the list marker (bullet/numbering) and the leading task checkbox — those
|
|
1003
|
-
* are expressed at the list/item level, not inside the paragraph.
|
|
1004
|
-
*/
|
|
1005
|
-
resolveListItemParagraph(para, info) {
|
|
1006
|
-
const resolved = typeof para === "string" ? { text: para } : para;
|
|
1007
|
-
const headingLevel = this.detectHeadingLevel(resolved);
|
|
1008
|
-
const nodeType = headingLevel ? "heading" : "paragraph";
|
|
1009
|
-
const attrs = headingLevel ? parseDocx(resolved) : parseDocx$2(resolved);
|
|
1010
|
-
if (headingLevel && attrs.level == null) attrs.level = headingLevel;
|
|
1011
|
-
const stripped = info.kind === "task" ? this.stripTaskCheckbox(resolved) : resolved;
|
|
1012
|
-
const content = this.resolveInlineContent(stripped);
|
|
1013
|
-
const node = { type: nodeType };
|
|
1014
|
-
const cleanAttrsObj = cleanAttrs(attrs);
|
|
1015
|
-
if (Object.keys(cleanAttrsObj).length > 0) node.attrs = cleanAttrsObj;
|
|
1016
|
-
if (content.length > 0) node.content = content;
|
|
1017
|
-
return node;
|
|
1018
|
-
}
|
|
1019
|
-
/** Return a copy of `para` with its leading docen-task checkbox SDT removed. */
|
|
1020
|
-
stripTaskCheckbox(para) {
|
|
1021
|
-
const children = para.children;
|
|
1022
|
-
if (Array.isArray(children) && children.length > 0 && isTaskCheckbox(children[0])) return {
|
|
1023
|
-
...para,
|
|
1024
|
-
children: children.slice(1)
|
|
1025
|
-
};
|
|
1026
|
-
return para;
|
|
1027
|
-
}
|
|
1028
|
-
resolveCodeBlock(opts) {
|
|
1029
|
-
const children = opts.children;
|
|
1030
|
-
const content = [];
|
|
1031
|
-
if (children) {
|
|
1032
|
-
for (const child of children) if (typeof child === "string") {
|
|
1033
|
-
if (child) content.push({
|
|
1034
|
-
type: "text",
|
|
1035
|
-
text: child
|
|
1036
|
-
});
|
|
1037
|
-
} else if (typeof child === "object" && child !== null) {
|
|
1038
|
-
if ("break" in child) {
|
|
1039
|
-
const prev = content[content.length - 1];
|
|
1040
|
-
if (prev && prev.type === "text") prev.text = (prev.text ?? "") + "\n";
|
|
1041
|
-
else content.push({
|
|
1042
|
-
type: "text",
|
|
1043
|
-
text: "\n"
|
|
1044
|
-
});
|
|
1045
|
-
} else if ("text" in child) {
|
|
1046
|
-
const marks = this.resolveMarks(child);
|
|
1047
|
-
const textNode = {
|
|
1048
|
-
type: "text",
|
|
1049
|
-
text: child.text
|
|
1050
|
-
};
|
|
1051
|
-
if (marks) textNode.marks = marks;
|
|
1052
|
-
content.push(textNode);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
} else if (opts.text) content.push({
|
|
1056
|
-
type: "text",
|
|
1057
|
-
text: opts.text
|
|
1058
|
-
});
|
|
1059
|
-
const node = { type: "codeBlock" };
|
|
1060
|
-
if (content.length > 0) node.content = content;
|
|
1061
|
-
return node;
|
|
1062
|
-
}
|
|
1063
|
-
resolveTable(tableOpts) {
|
|
1064
|
-
const attrs = parseDocx$4(tableOpts);
|
|
1065
|
-
const rows = tableOpts.rows ?? [];
|
|
1066
|
-
const content = [];
|
|
1067
|
-
const tableCellMargins = tableOpts.cellMargin ?? tableOpts.margins ?? null;
|
|
1068
|
-
let activeSpans = /* @__PURE__ */ new Map();
|
|
1069
|
-
for (const row of rows) {
|
|
1070
|
-
const rowAttrs = parseDocx$7(row);
|
|
1071
|
-
const cells = row.cells ?? [];
|
|
1072
|
-
const cellNodes = [];
|
|
1073
|
-
const nextActiveSpans = /* @__PURE__ */ new Map();
|
|
1074
|
-
let colIdx = 0;
|
|
1075
|
-
for (const cell of cells) {
|
|
1076
|
-
const cellColspan = cell.columnSpan ?? 1;
|
|
1077
|
-
const vMerge = cell.verticalMerge;
|
|
1078
|
-
if (vMerge === "continue") {
|
|
1079
|
-
const owner = activeSpans.get(colIdx);
|
|
1080
|
-
if (owner) {
|
|
1081
|
-
const ownerAttrs = owner.attrs ??= {};
|
|
1082
|
-
ownerAttrs.rowspan = (ownerAttrs.rowspan ?? 1) + 1;
|
|
1083
|
-
for (let c = colIdx; c < colIdx + cellColspan; c++) nextActiveSpans.set(c, owner);
|
|
1084
|
-
}
|
|
1085
|
-
colIdx += cellColspan;
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
const isHeader = row.tableHeader;
|
|
1089
|
-
const cellAttrs = isHeader ? parseDocx$6(cell) : parseDocx$5(cell);
|
|
1090
|
-
delete cellAttrs.verticalMerge;
|
|
1091
|
-
if (!cellAttrs.margins && tableCellMargins) cellAttrs.margins = tableCellMargins;
|
|
1092
|
-
const cellChildren = cell.children ?? [];
|
|
1093
|
-
const cellContent = [];
|
|
1094
|
-
for (const cc of cellChildren) {
|
|
1095
|
-
const resolved = this.resolveSectionChild(cc);
|
|
1096
|
-
if (resolved) cellContent.push(resolved);
|
|
1097
|
-
}
|
|
1098
|
-
const cellNode = { type: isHeader ? "tableHeader" : "tableCell" };
|
|
1099
|
-
if (Object.keys(cellAttrs).length > 0) cellNode.attrs = cleanAttrs(cellAttrs);
|
|
1100
|
-
if (cellContent.length > 0) cellNode.content = cellContent;
|
|
1101
|
-
else cellNode.content = [{ type: "paragraph" }];
|
|
1102
|
-
if (vMerge === "restart") for (let c = colIdx; c < colIdx + cellColspan; c++) nextActiveSpans.set(c, cellNode);
|
|
1103
|
-
cellNodes.push(cellNode);
|
|
1104
|
-
colIdx += cellColspan;
|
|
1105
|
-
}
|
|
1106
|
-
const gridAfter = row.gridAfter ?? 0;
|
|
1107
|
-
if (gridAfter > 0) {
|
|
1108
|
-
const trailingType = row.tableHeader ? "tableHeader" : "tableCell";
|
|
1109
|
-
const nilBorders = {
|
|
1110
|
-
top: { style: "nil" },
|
|
1111
|
-
right: { style: "nil" },
|
|
1112
|
-
bottom: { style: "nil" },
|
|
1113
|
-
left: { style: "nil" }
|
|
1114
|
-
};
|
|
1115
|
-
for (let c = 0; c < gridAfter; c++) cellNodes.push({
|
|
1116
|
-
type: trailingType,
|
|
1117
|
-
attrs: { borders: nilBorders },
|
|
1118
|
-
content: [{ type: "paragraph" }]
|
|
1119
|
-
});
|
|
1120
|
-
colIdx += gridAfter;
|
|
1121
|
-
}
|
|
1122
|
-
activeSpans = nextActiveSpans;
|
|
1123
|
-
const rowNode = { type: "tableRow" };
|
|
1124
|
-
if (Object.keys(rowAttrs).length > 0) rowNode.attrs = cleanAttrs(rowAttrs);
|
|
1125
|
-
if (cellNodes.length > 0) rowNode.content = cellNodes;
|
|
1126
|
-
content.push(rowNode);
|
|
1127
|
-
}
|
|
1128
|
-
const node = { type: "table" };
|
|
1129
|
-
if (Object.keys(attrs).length > 0) node.attrs = cleanAttrs(attrs);
|
|
1130
|
-
if (content.length > 0) node.content = content;
|
|
1131
|
-
return node;
|
|
1132
|
-
}
|
|
1133
832
|
/**
|
|
1134
833
|
* Resolve a paragraph's inline content. @office-open collapses a plain-text
|
|
1135
834
|
* paragraph (a single run with no properties) to a bare string or a `{ text }`
|
|
@@ -1168,70 +867,17 @@ var DocxManager = class {
|
|
|
1168
867
|
return nodes;
|
|
1169
868
|
}
|
|
1170
869
|
resolveParagraphChild(child) {
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
type: "wpgGroup",
|
|
1176
|
-
attrs: { wpgGroup: child.wpgGroup }
|
|
1177
|
-
};
|
|
1178
|
-
if ("wpsShape" in child) {
|
|
1179
|
-
const ws = child.wpsShape;
|
|
1180
|
-
const content = [];
|
|
1181
|
-
if (ws?.children) for (const para of ws.children) {
|
|
1182
|
-
if (typeof para !== "object" || para === null) {
|
|
1183
|
-
const node = this.resolveParagraph(para);
|
|
1184
|
-
if (node) content.push(node);
|
|
1185
|
-
continue;
|
|
1186
|
-
}
|
|
1187
|
-
const defRPr = para.run ?? {};
|
|
1188
|
-
const children = Array.isArray(para.children) ? para.children.map((c) => typeof c !== "object" || c === null ? {
|
|
1189
|
-
...defRPr,
|
|
1190
|
-
text: c
|
|
1191
|
-
} : {
|
|
1192
|
-
...defRPr,
|
|
1193
|
-
...c
|
|
1194
|
-
}) : void 0;
|
|
1195
|
-
const node = this.resolveParagraph({
|
|
1196
|
-
...para,
|
|
1197
|
-
run: void 0,
|
|
1198
|
-
...children ? { children } : {}
|
|
1199
|
-
});
|
|
1200
|
-
if (node) content.push(node);
|
|
1201
|
-
}
|
|
1202
|
-
if (content.length === 0) content.push({ type: "paragraph" });
|
|
1203
|
-
const { children: _omit, ...geometry } = ws ?? {};
|
|
1204
|
-
const node = {
|
|
1205
|
-
type: "wpsShape",
|
|
1206
|
-
content
|
|
1207
|
-
};
|
|
1208
|
-
const cleanGeometry = cleanAttrs(geometry);
|
|
1209
|
-
if (Object.keys(cleanGeometry).length > 0) node.attrs = { wpsShape: cleanGeometry };
|
|
1210
|
-
return node;
|
|
870
|
+
const ctx = this.resolveCtx;
|
|
871
|
+
for (const { rule } of this.inlineRules) if (rule.match(child, ctx)) {
|
|
872
|
+
const node = rule.convert(child, ctx);
|
|
873
|
+
if (node) return node;
|
|
1211
874
|
}
|
|
1212
|
-
if ("
|
|
1213
|
-
if ("hyperlink" in child) return this.resolveHyperlink(child.hyperlink);
|
|
1214
|
-
if ("pageBreak" in child) return { type: "pageBreak" };
|
|
1215
|
-
if ("columnBreak" in child) return { type: "columnBreak" };
|
|
875
|
+
if ("text" in child || "children" in child || "break" in child) return this.resolveRun(child);
|
|
1216
876
|
return {
|
|
1217
877
|
type: "inlinePassthrough",
|
|
1218
878
|
attrs: { data: JSON.stringify(child) }
|
|
1219
879
|
};
|
|
1220
880
|
}
|
|
1221
|
-
/** Resolve an inline SDT (mention carrier; other inline SDTs unsupported). */
|
|
1222
|
-
resolveInlineSdt(child) {
|
|
1223
|
-
if (isMention(child)) {
|
|
1224
|
-
const { id, label } = readMention(child);
|
|
1225
|
-
return {
|
|
1226
|
-
type: "mention",
|
|
1227
|
-
attrs: {
|
|
1228
|
-
id,
|
|
1229
|
-
label
|
|
1230
|
-
}
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
return null;
|
|
1234
|
-
}
|
|
1235
881
|
resolveRun(opts) {
|
|
1236
882
|
if (opts.break && opts.text === void 0 && !opts.children) return { type: "hardBreak" };
|
|
1237
883
|
const text = opts.text;
|
|
@@ -1253,18 +899,21 @@ var DocxManager = class {
|
|
|
1253
899
|
};
|
|
1254
900
|
for (const c of opts.children) if (typeof c === "string") parts.push(c);
|
|
1255
901
|
else if (c && typeof c === "object") {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
902
|
+
const ctx = this.resolveCtx;
|
|
903
|
+
let handled = false;
|
|
904
|
+
for (const { rule } of this.inlineRules) if (rule.match(c, ctx)) {
|
|
905
|
+
const node = rule.convert(c, ctx);
|
|
906
|
+
if (node) {
|
|
907
|
+
flushText();
|
|
908
|
+
nodes.push(...Array.isArray(node) ? node : [node]);
|
|
909
|
+
handled = true;
|
|
910
|
+
break;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
if (handled) continue;
|
|
914
|
+
if ("break" in c) {
|
|
1263
915
|
flushText();
|
|
1264
916
|
nodes.push({ type: "hardBreak" });
|
|
1265
|
-
} else if ("tab" in c) {
|
|
1266
|
-
flushText();
|
|
1267
|
-
nodes.push({ type: "tab" });
|
|
1268
917
|
}
|
|
1269
918
|
}
|
|
1270
919
|
flushText();
|
|
@@ -1287,98 +936,32 @@ var DocxManager = class {
|
|
|
1287
936
|
}
|
|
1288
937
|
resolveMarks(opts) {
|
|
1289
938
|
const marks = [];
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
attrs: { doubleStrike: strikeAttrs.doubleStrike ?? null }
|
|
1298
|
-
});
|
|
1299
|
-
}
|
|
1300
|
-
if (opts.subScript) marks.push({ type: "subscript" });
|
|
1301
|
-
if (opts.superScript) marks.push({ type: "superscript" });
|
|
1302
|
-
if (opts.highlight) marks.push({
|
|
1303
|
-
type: "highlight",
|
|
1304
|
-
attrs: { color: opts.highlight }
|
|
1305
|
-
});
|
|
1306
|
-
if (opts.style === "CodeChar") marks.push({ type: "code" });
|
|
1307
|
-
const textStyleAttrs = parseDocx$8(opts);
|
|
1308
|
-
if (opts.style === "CodeChar") {
|
|
1309
|
-
delete textStyleAttrs.font;
|
|
1310
|
-
delete textStyleAttrs.styleId;
|
|
939
|
+
for (const { name, parse } of this.markParse) {
|
|
940
|
+
const attrs = parse(opts);
|
|
941
|
+
if (attrs === null) continue;
|
|
942
|
+
marks.push(Object.keys(attrs).length ? {
|
|
943
|
+
type: name,
|
|
944
|
+
attrs
|
|
945
|
+
} : { type: name });
|
|
1311
946
|
}
|
|
1312
|
-
if (Object.keys(textStyleAttrs).length > 0) marks.push({
|
|
1313
|
-
type: "textStyle",
|
|
1314
|
-
attrs: textStyleAttrs
|
|
1315
|
-
});
|
|
1316
947
|
return marks.length > 0 ? marks : void 0;
|
|
1317
948
|
}
|
|
1318
|
-
resolveImage(imageOpts) {
|
|
1319
|
-
const attrs = parseDocx$1(imageOpts);
|
|
1320
|
-
const data = imageOpts.data;
|
|
1321
|
-
const type = imageOpts.type;
|
|
1322
|
-
if (data && type) attrs.src = `data:image/${type};base64,${encodeBase64(data instanceof ArrayBuffer ? new Uint8Array(data) : data)}`;
|
|
1323
|
-
return {
|
|
1324
|
-
type: "image",
|
|
1325
|
-
attrs
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
resolveHyperlink(hyperlink) {
|
|
1329
|
-
const href = hyperlink.link ?? (hyperlink.anchor ? `#${hyperlink.anchor}` : "");
|
|
1330
|
-
if (!href) return null;
|
|
1331
|
-
const content = this.resolveParagraphChildren((hyperlink.children ?? []).map((c) => c));
|
|
1332
|
-
if (content.length > 0) {
|
|
1333
|
-
const merged = mergeTextNodes(content);
|
|
1334
|
-
for (const node of merged) if (node.type === "text") node.marks = [...node.marks ?? [], {
|
|
1335
|
-
type: "link",
|
|
1336
|
-
attrs: {
|
|
1337
|
-
href,
|
|
1338
|
-
target: href.startsWith("#") ? null : "_blank",
|
|
1339
|
-
rel: "noopener noreferrer nofollow",
|
|
1340
|
-
class: null,
|
|
1341
|
-
title: hyperlink.tooltip ?? null
|
|
1342
|
-
}
|
|
1343
|
-
}];
|
|
1344
|
-
return merged;
|
|
1345
|
-
}
|
|
1346
|
-
return null;
|
|
1347
|
-
}
|
|
1348
949
|
};
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
Heading6: 6,
|
|
1356
|
-
Heading7: 7,
|
|
1357
|
-
Heading8: 8,
|
|
1358
|
-
Heading9: 9,
|
|
1359
|
-
Title: 1
|
|
1360
|
-
};
|
|
1361
|
-
/** Heading level (1-9) from a localized style NAME: "heading 1"/"标题 1" → 1,
|
|
1362
|
-
* "title" → 1. office-open's built-in names are English ("heading 1"), but
|
|
1363
|
-
* zh-CN Word labels the same styles "标题 1"; both map to the same level. */
|
|
1364
|
-
function headingLevelFromName(name) {
|
|
1365
|
-
if (!name) return void 0;
|
|
1366
|
-
const m = /^heading\s+(\d)$/i.exec(name) ?? /^标题\s*(\d)$/.exec(name);
|
|
1367
|
-
if (m) {
|
|
1368
|
-
const lvl = Number(m[1]);
|
|
1369
|
-
if (lvl >= 1 && lvl <= 9) return lvl;
|
|
1370
|
-
}
|
|
1371
|
-
return /^title$/i.test(name) ? 1 : void 0;
|
|
950
|
+
const defaultManager = new DocxManager(docxExtensions);
|
|
951
|
+
/** Resolve a DocxManager for a conversion call: the shared default singleton
|
|
952
|
+
* when no extensions are given, or a fresh instance bound to custom extensions
|
|
953
|
+
* so user-supplied marks/nodes plug into compile/resolve without a fork. */
|
|
954
|
+
function getDocxManager(extensions) {
|
|
955
|
+
return extensions ? new DocxManager(extensions) : defaultManager;
|
|
1372
956
|
}
|
|
1373
|
-
const defaultManager = new DocxManager();
|
|
1374
957
|
/**
|
|
1375
958
|
* Parse a DOCX file into Tiptap JSON (runtime model).
|
|
1376
959
|
*
|
|
1377
960
|
* Combines @office-open/docx's `parseDocument` (DOCX binary → DocumentOptions)
|
|
1378
961
|
* with `DocxManager.resolve` (DocumentOptions → Tiptap JSON).
|
|
1379
962
|
*/
|
|
1380
|
-
function parseDOCX(data) {
|
|
1381
|
-
return
|
|
963
|
+
function parseDOCX(data, extensions) {
|
|
964
|
+
return getDocxManager(extensions).resolve(parseDocument(data));
|
|
1382
965
|
}
|
|
1383
966
|
/**
|
|
1384
967
|
* Merge {@link DocxGenerateOptions.document} into the `DocumentOptions`
|
|
@@ -1409,9 +992,9 @@ function applyDocumentOptions(base, document) {
|
|
|
1409
992
|
* in place (http image URLs become embedded data URLs).
|
|
1410
993
|
*/
|
|
1411
994
|
async function generateDOCX(json, options) {
|
|
1412
|
-
const { prepare = true, packer, document } = options ?? {};
|
|
995
|
+
const { prepare = true, packer, document, extensions } = options ?? {};
|
|
1413
996
|
if (prepare !== false) await prepareDocument(json, prepare === true ? void 0 : prepare);
|
|
1414
|
-
return generateDocument(applyDocumentOptions(compileDocument(json), document), packer);
|
|
997
|
+
return generateDocument(applyDocumentOptions(compileDocument(json, extensions), document), packer);
|
|
1415
998
|
}
|
|
1416
999
|
/**
|
|
1417
1000
|
* Generate a DOCX file synchronously — fastest throughput, blocks the event loop.
|
|
@@ -1421,8 +1004,8 @@ async function generateDOCX(json, options) {
|
|
|
1421
1004
|
* when http images need embedding. `options.document` is still applied.
|
|
1422
1005
|
*/
|
|
1423
1006
|
function generateDOCXSync(json, options) {
|
|
1424
|
-
const { packer, document } = options ?? {};
|
|
1425
|
-
return generateDocumentSync(applyDocumentOptions(compileDocument(json), document), packer);
|
|
1007
|
+
const { packer, document, extensions } = options ?? {};
|
|
1008
|
+
return generateDocumentSync(applyDocumentOptions(compileDocument(json, extensions), document), packer);
|
|
1426
1009
|
}
|
|
1427
1010
|
/**
|
|
1428
1011
|
* Generate a DOCX file as a `ReadableStream<Uint8Array>` — for large documents
|
|
@@ -1432,21 +1015,21 @@ function generateDOCXSync(json, options) {
|
|
|
1432
1015
|
* `DocxManager.compile` → `generateDocumentStream`. Async due to preparation.
|
|
1433
1016
|
*/
|
|
1434
1017
|
async function generateDOCXStream(json, options) {
|
|
1435
|
-
const { prepare = true, packer, document } = options ?? {};
|
|
1018
|
+
const { prepare = true, packer, document, extensions } = options ?? {};
|
|
1436
1019
|
if (prepare !== false) await prepareDocument(json, prepare === true ? void 0 : prepare);
|
|
1437
|
-
return generateDocumentStream(applyDocumentOptions(compileDocument(json), document), packer);
|
|
1020
|
+
return generateDocumentStream(applyDocumentOptions(compileDocument(json, extensions), document), packer);
|
|
1438
1021
|
}
|
|
1439
1022
|
/**
|
|
1440
1023
|
* Convert DocumentOptions (persistence model) to Tiptap JSON (runtime model).
|
|
1441
1024
|
*/
|
|
1442
|
-
function resolveDocument(docOpts) {
|
|
1443
|
-
return
|
|
1025
|
+
function resolveDocument(docOpts, extensions) {
|
|
1026
|
+
return getDocxManager(extensions).resolve(docOpts);
|
|
1444
1027
|
}
|
|
1445
1028
|
/**
|
|
1446
1029
|
* Convert Tiptap JSON (runtime model) to DocumentOptions (persistence model).
|
|
1447
1030
|
*/
|
|
1448
|
-
function compileDocument(json) {
|
|
1449
|
-
return
|
|
1031
|
+
function compileDocument(json, extensions) {
|
|
1032
|
+
return getDocxManager(extensions).compile(json);
|
|
1450
1033
|
}
|
|
1451
1034
|
//#endregion
|
|
1452
1035
|
export { DocxManager, compileDocument, generateDOCX, generateDOCXStream, generateDOCXSync, parseDOCX, resolveDocument };
|