@json-to-office/core-docx 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/heading.d.ts.map +1 -1
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/paragraph.d.ts.map +1 -1
- package/dist/components/section.d.ts.map +1 -1
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/toc/index.d.ts.map +1 -1
- package/dist/core/cached-render.d.ts +9 -1
- package/dist/core/cached-render.d.ts.map +1 -1
- package/dist/core/collectTocHeadings.d.ts +60 -0
- package/dist/core/collectTocHeadings.d.ts.map +1 -0
- package/dist/core/content.d.ts +17 -1
- package/dist/core/content.d.ts.map +1 -1
- package/dist/core/layout.d.ts +5 -0
- package/dist/core/layout.d.ts.map +1 -1
- package/dist/core/render.d.ts.map +1 -1
- package/dist/core/sectionBookmarks.d.ts +53 -0
- package/dist/core/sectionBookmarks.d.ts.map +1 -0
- package/dist/core/sectionOrdinals.d.ts +32 -0
- package/dist/core/sectionOrdinals.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +816 -169
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +815 -169
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/styles/index.d.ts +2 -2
- package/dist/styles/index.d.ts.map +1 -1
- package/dist/styles/themeToDocxAdapter.d.ts.map +1 -1
- package/dist/styles/utils/layoutUtils.d.ts +48 -0
- package/dist/styles/utils/layoutUtils.d.ts.map +1 -1
- package/dist/templates/themes/index.d.ts +400 -8
- package/dist/templates/themes/index.d.ts.map +1 -1
- package/dist/themes/defaults.d.ts +96 -0
- package/dist/themes/defaults.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/commentAnchors.d.ts +39 -0
- package/dist/utils/commentAnchors.d.ts.map +1 -0
- package/dist/utils/commentRegistry.d.ts +49 -0
- package/dist/utils/commentRegistry.d.ts.map +1 -0
- package/dist/utils/componentAnnotations.d.ts +23 -0
- package/dist/utils/componentAnnotations.d.ts.map +1 -0
- package/dist/utils/fixFloatingImageIds.d.ts +1 -1
- package/dist/utils/fixFloatingImageIds.d.ts.map +1 -1
- package/dist/utils/noteRegistry.d.ts +43 -0
- package/dist/utils/noteRegistry.d.ts.map +1 -0
- package/dist/utils/noteResolver.d.ts +31 -0
- package/dist/utils/noteResolver.d.ts.map +1 -0
- package/dist/utils/numberingConfig.d.ts +15 -0
- package/dist/utils/numberingConfig.d.ts.map +1 -1
- package/dist/utils/placeholderProcessor.d.ts +2 -2
- package/dist/utils/placeholderProcessor.d.ts.map +1 -1
- package/dist/utils/revisionUtils.d.ts +32 -9
- package/dist/utils/revisionUtils.d.ts.map +1 -1
- package/dist/utils/textParser.d.ts +12 -0
- package/dist/utils/textParser.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1134,7 +1134,7 @@ function getPageDimensions(size) {
|
|
|
1134
1134
|
if (typeof size === "string") {
|
|
1135
1135
|
return PAGE_SIZES[size];
|
|
1136
1136
|
}
|
|
1137
|
-
return size;
|
|
1137
|
+
return { width: size.width, height: size.height };
|
|
1138
1138
|
}
|
|
1139
1139
|
var resolveTableParagraphSpacing, PAGE_SIZES, getTableStyle, getDocumentMargins, getPageSetup;
|
|
1140
1140
|
var init_layoutUtils = __esm({
|
|
@@ -1151,10 +1151,10 @@ var init_layoutUtils = __esm({
|
|
|
1151
1151
|
};
|
|
1152
1152
|
};
|
|
1153
1153
|
PAGE_SIZES = {
|
|
1154
|
-
A4: { width: 11906, height: 16838 },
|
|
1155
|
-
A3: { width: 16838, height: 23811 },
|
|
1156
|
-
LETTER: { width: 12240, height: 15840 },
|
|
1157
|
-
LEGAL: { width: 12240, height: 20160 }
|
|
1154
|
+
A4: { width: 11906, height: 16838, code: 9 },
|
|
1155
|
+
A3: { width: 16838, height: 23811, code: 8 },
|
|
1156
|
+
LETTER: { width: 12240, height: 15840, code: 1 },
|
|
1157
|
+
LEGAL: { width: 12240, height: 20160, code: 5 }
|
|
1158
1158
|
};
|
|
1159
1159
|
getTableStyle = (theme, themeName) => {
|
|
1160
1160
|
const themeConfig = resolveTheme(theme, themeName);
|
|
@@ -1291,7 +1291,8 @@ var init_layoutUtils = __esm({
|
|
|
1291
1291
|
return {
|
|
1292
1292
|
size: {
|
|
1293
1293
|
width: dimensions.width,
|
|
1294
|
-
height: dimensions.height
|
|
1294
|
+
height: dimensions.height,
|
|
1295
|
+
...dimensions.code !== void 0 && { code: dimensions.code }
|
|
1295
1296
|
},
|
|
1296
1297
|
margin: {
|
|
1297
1298
|
top: margins.top ?? defaultMargins.top ?? 1440,
|
|
@@ -1303,10 +1304,11 @@ var init_layoutUtils = __esm({
|
|
|
1303
1304
|
}
|
|
1304
1305
|
return {
|
|
1305
1306
|
size: {
|
|
1306
|
-
width:
|
|
1307
|
-
//
|
|
1308
|
-
height:
|
|
1309
|
-
//
|
|
1307
|
+
width: PAGE_SIZES.A4.width,
|
|
1308
|
+
// 210mm in twips (A4)
|
|
1309
|
+
height: PAGE_SIZES.A4.height,
|
|
1310
|
+
// 297mm in twips (A4)
|
|
1311
|
+
code: PAGE_SIZES.A4.code
|
|
1310
1312
|
},
|
|
1311
1313
|
margin: {
|
|
1312
1314
|
top: defaultMargins.top ?? 1440,
|
|
@@ -2528,18 +2530,7 @@ function getColumnSettings(layout) {
|
|
|
2528
2530
|
function createSectionProperties(columnSettings, theme, themeName, sectionType, pageOverride) {
|
|
2529
2531
|
const basePageSetup = getPageSetup(theme, themeName);
|
|
2530
2532
|
const pageSetup = pageOverride ? {
|
|
2531
|
-
size:
|
|
2532
|
-
...basePageSetup.size,
|
|
2533
|
-
...pageOverride.size && typeof pageOverride.size === "object" ? pageOverride.size : pageOverride.size ? (() => {
|
|
2534
|
-
const sizes = {
|
|
2535
|
-
A4: { width: 11906, height: 16838 },
|
|
2536
|
-
A3: { width: 16838, height: 23811 },
|
|
2537
|
-
LETTER: { width: 12240, height: 15840 },
|
|
2538
|
-
LEGAL: { width: 12240, height: 20160 }
|
|
2539
|
-
};
|
|
2540
|
-
return sizes[pageOverride.size];
|
|
2541
|
-
})() : {}
|
|
2542
|
-
},
|
|
2533
|
+
size: pageOverride.size ? getPageDimensions(pageOverride.size) : basePageSetup.size,
|
|
2543
2534
|
margin: {
|
|
2544
2535
|
...basePageSetup.margin,
|
|
2545
2536
|
...pageOverride.margins || {}
|
|
@@ -2641,8 +2632,8 @@ Suggestion: ${suggestion}`
|
|
|
2641
2632
|
// src/core/render.ts
|
|
2642
2633
|
import {
|
|
2643
2634
|
Document,
|
|
2644
|
-
Paragraph as
|
|
2645
|
-
TextRun as
|
|
2635
|
+
Paragraph as Paragraph9,
|
|
2636
|
+
TextRun as TextRun9,
|
|
2646
2637
|
AlignmentType as AlignmentType5,
|
|
2647
2638
|
BookmarkStart as BookmarkStart2,
|
|
2648
2639
|
BookmarkEnd as BookmarkEnd2
|
|
@@ -3061,17 +3052,19 @@ function convertBorders(borders, theme) {
|
|
|
3061
3052
|
color: resolveColor(side.color, theme),
|
|
3062
3053
|
...side.space !== void 0 ? { space: side.space } : {}
|
|
3063
3054
|
} : void 0;
|
|
3064
|
-
const
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3055
|
+
const sides = [
|
|
3056
|
+
"top",
|
|
3057
|
+
"bottom",
|
|
3058
|
+
"left",
|
|
3059
|
+
"right",
|
|
3060
|
+
"between"
|
|
3061
|
+
];
|
|
3062
|
+
const converted = {};
|
|
3063
|
+
for (const side of sides) {
|
|
3064
|
+
const value = mapSide(borders[side]);
|
|
3065
|
+
if (value) converted[side] = value;
|
|
3066
|
+
}
|
|
3067
|
+
return Object.keys(converted).length > 0 ? converted : void 0;
|
|
3075
3068
|
}
|
|
3076
3069
|
function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
3077
3070
|
const theme = typeof themeNameOrObject === "string" ? getTheme(themeNameOrObject) || getTheme("minimal") : themeNameOrObject;
|
|
@@ -3440,7 +3433,7 @@ function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
|
3440
3433
|
}
|
|
3441
3434
|
const tocMatch = /^TOC([1-9])$/.exec(styleKey);
|
|
3442
3435
|
const customStyle = tocMatch ? styleValue : resolveStyleWithBaseStyle(theme, styleKey) || styleValue;
|
|
3443
|
-
const styleId = tocMatch ? `
|
|
3436
|
+
const styleId = tocMatch ? `TOC${tocMatch[1]}` : styleKey;
|
|
3444
3437
|
const styleName = tocMatch ? `TOC ${tocMatch[1]}` : styleKey.replace(/([A-Z])/g, " $1").trim();
|
|
3445
3438
|
const mapBaseStyleId = (base) => {
|
|
3446
3439
|
if (!base) return "Normal";
|
|
@@ -3512,8 +3505,8 @@ function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
|
3512
3505
|
continue;
|
|
3513
3506
|
}
|
|
3514
3507
|
paragraphStyles.push({
|
|
3515
|
-
//
|
|
3516
|
-
id: `
|
|
3508
|
+
// Canonical id and display name — see the styleId note above.
|
|
3509
|
+
id: `TOC${i}`,
|
|
3517
3510
|
name: `TOC ${i}`,
|
|
3518
3511
|
basedOn: "Normal",
|
|
3519
3512
|
next: "Normal",
|
|
@@ -3536,20 +3529,43 @@ function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
|
3536
3529
|
}
|
|
3537
3530
|
});
|
|
3538
3531
|
}
|
|
3532
|
+
const noteStyle = resolveStyleWithBaseStyle(theme, "normal") || theme.styles?.normal;
|
|
3533
|
+
const bodyRun = convertRunProperties(
|
|
3534
|
+
mergeFontAndStyleProperties(resolveFontProperties(theme, noteStyle?.font), {
|
|
3535
|
+
size: noteStyle?.size,
|
|
3536
|
+
color: noteStyle?.color
|
|
3537
|
+
}),
|
|
3538
|
+
theme,
|
|
3539
|
+
theme.colors.text
|
|
3540
|
+
);
|
|
3541
|
+
const noteRun = {
|
|
3542
|
+
...bodyRun,
|
|
3543
|
+
...typeof bodyRun.size === "number" && {
|
|
3544
|
+
size: Math.max(12, bodyRun.size - 4)
|
|
3545
|
+
}
|
|
3546
|
+
};
|
|
3539
3547
|
return {
|
|
3540
3548
|
paragraphStyles,
|
|
3541
3549
|
// Cast needed due to docx typing
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3550
|
+
default: {
|
|
3551
|
+
// Document-default proofing language (w:docDefaults/w:rPrDefault). Runs
|
|
3552
|
+
// that don't set their own w:lang inherit this, so Word spell-checks the
|
|
3553
|
+
// whole document in the requested language unless a component overrides
|
|
3554
|
+
// it.
|
|
3555
|
+
...language && {
|
|
3547
3556
|
document: {
|
|
3548
3557
|
run: {
|
|
3549
3558
|
language: { value: language }
|
|
3550
3559
|
}
|
|
3551
3560
|
}
|
|
3552
|
-
}
|
|
3561
|
+
},
|
|
3562
|
+
// Run properties only: docx's own note paragraph defaults (single line
|
|
3563
|
+
// spacing, no space after) are already what a note wants, and an empty
|
|
3564
|
+
// spacing override would drop its line rule.
|
|
3565
|
+
footnoteText: { run: noteRun },
|
|
3566
|
+
footnoteReference: { run: { ...noteRun, superScript: true } },
|
|
3567
|
+
endnoteText: { run: noteRun },
|
|
3568
|
+
endnoteReference: { run: { ...noteRun, superScript: true } }
|
|
3553
3569
|
}
|
|
3554
3570
|
};
|
|
3555
3571
|
}
|
|
@@ -3671,7 +3687,15 @@ import {
|
|
|
3671
3687
|
} from "docx";
|
|
3672
3688
|
|
|
3673
3689
|
// src/utils/textParser.ts
|
|
3674
|
-
import {
|
|
3690
|
+
import {
|
|
3691
|
+
TextRun,
|
|
3692
|
+
ExternalHyperlink,
|
|
3693
|
+
InternalHyperlink,
|
|
3694
|
+
FootnoteReferenceRun,
|
|
3695
|
+
EndnoteReferenceRun,
|
|
3696
|
+
Tab
|
|
3697
|
+
} from "docx";
|
|
3698
|
+
var FOOTNOTE_MARKER_REGEX = /\[\^([^\]\s]+)\]/;
|
|
3675
3699
|
function escapeRegExp(s) {
|
|
3676
3700
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3677
3701
|
}
|
|
@@ -3848,8 +3872,8 @@ function buildTextRuns(text, commonProps, opts = {}) {
|
|
|
3848
3872
|
return runs;
|
|
3849
3873
|
}
|
|
3850
3874
|
function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
|
|
3851
|
-
|
|
3852
|
-
|
|
3875
|
+
const runs = (segment) => buildTextRuns(
|
|
3876
|
+
segment,
|
|
3853
3877
|
buildRunCommonProps(baseStyle, {
|
|
3854
3878
|
bold: overrideStyle?.bold,
|
|
3855
3879
|
italics: overrideStyle?.italics,
|
|
@@ -3857,6 +3881,34 @@ function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
|
|
|
3857
3881
|
}),
|
|
3858
3882
|
{ noProof: baseStyle.noProof, noProofWords: options.noProofWords }
|
|
3859
3883
|
);
|
|
3884
|
+
if (!options.noteRef) return runs(text);
|
|
3885
|
+
return splitNoteMarkers(text, options.noteRef, runs);
|
|
3886
|
+
}
|
|
3887
|
+
function splitNoteMarkers(text, noteRef, runs) {
|
|
3888
|
+
const regex = new RegExp(FOOTNOTE_MARKER_REGEX.source, "g");
|
|
3889
|
+
const out = [];
|
|
3890
|
+
let lastIndex = 0;
|
|
3891
|
+
let pending = "";
|
|
3892
|
+
let match;
|
|
3893
|
+
while ((match = regex.exec(text)) !== null) {
|
|
3894
|
+
const note = noteRef(match[1]);
|
|
3895
|
+
if (note === void 0) {
|
|
3896
|
+
pending += text.slice(lastIndex, regex.lastIndex);
|
|
3897
|
+
lastIndex = regex.lastIndex;
|
|
3898
|
+
continue;
|
|
3899
|
+
}
|
|
3900
|
+
const before = pending + text.slice(lastIndex, match.index);
|
|
3901
|
+
pending = "";
|
|
3902
|
+
if (before) out.push(...runs(before));
|
|
3903
|
+
out.push(
|
|
3904
|
+
note.endnote ? new EndnoteReferenceRun(note.id) : new FootnoteReferenceRun(note.id)
|
|
3905
|
+
);
|
|
3906
|
+
lastIndex = regex.lastIndex;
|
|
3907
|
+
}
|
|
3908
|
+
if (out.length === 0) return runs(text);
|
|
3909
|
+
const trailing = pending + text.slice(lastIndex);
|
|
3910
|
+
if (trailing) out.push(...runs(trailing));
|
|
3911
|
+
return out;
|
|
3860
3912
|
}
|
|
3861
3913
|
function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
3862
3914
|
const normalizedText = normalizeUnicodeText(text);
|
|
@@ -4112,6 +4164,52 @@ initializeBuiltinPlaceholders();
|
|
|
4112
4164
|
|
|
4113
4165
|
// src/utils/revisionUtils.ts
|
|
4114
4166
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
4167
|
+
|
|
4168
|
+
// src/utils/componentAnnotations.ts
|
|
4169
|
+
function isRecord(value) {
|
|
4170
|
+
return typeof value === "object" && value !== null;
|
|
4171
|
+
}
|
|
4172
|
+
function hasKey(value, key) {
|
|
4173
|
+
return isRecord(value) && Boolean(value[key]);
|
|
4174
|
+
}
|
|
4175
|
+
function cellHasAnnotation(cell, key) {
|
|
4176
|
+
if (!isRecord(cell)) return false;
|
|
4177
|
+
if (hasKey(cell, key)) return true;
|
|
4178
|
+
const content = cell.content;
|
|
4179
|
+
return isRecord(content) && componentHasAnnotation(content, key);
|
|
4180
|
+
}
|
|
4181
|
+
function componentHasAnnotation(component, key) {
|
|
4182
|
+
const props = component.props;
|
|
4183
|
+
if (props) {
|
|
4184
|
+
if (props[key]) return true;
|
|
4185
|
+
const items = props.items;
|
|
4186
|
+
if (Array.isArray(items) && items.some((item) => hasKey(item, key))) {
|
|
4187
|
+
return true;
|
|
4188
|
+
}
|
|
4189
|
+
const rows = props.rows;
|
|
4190
|
+
if (Array.isArray(rows) && rows.some((row) => hasKey(row, key))) {
|
|
4191
|
+
return true;
|
|
4192
|
+
}
|
|
4193
|
+
const columns = props.columns;
|
|
4194
|
+
if (Array.isArray(columns) && columns.some((column) => {
|
|
4195
|
+
if (!isRecord(column)) return false;
|
|
4196
|
+
if (cellHasAnnotation(column.header, key)) return true;
|
|
4197
|
+
const cells = column.cells;
|
|
4198
|
+
return Array.isArray(cells) && cells.some((cell) => cellHasAnnotation(cell, key));
|
|
4199
|
+
})) {
|
|
4200
|
+
return true;
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
const children = component.children;
|
|
4204
|
+
if (Array.isArray(children)) {
|
|
4205
|
+
return children.some(
|
|
4206
|
+
(child) => isRecord(child) && componentHasAnnotation(child, key)
|
|
4207
|
+
);
|
|
4208
|
+
}
|
|
4209
|
+
return false;
|
|
4210
|
+
}
|
|
4211
|
+
|
|
4212
|
+
// src/utils/revisionUtils.ts
|
|
4115
4213
|
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
4116
4214
|
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
4117
4215
|
var RevisionIdRegistry = class {
|
|
@@ -4196,25 +4294,25 @@ function createRevisionRuns(revision, baseStyle) {
|
|
|
4196
4294
|
return runs;
|
|
4197
4295
|
}
|
|
4198
4296
|
function componentHasRevision(component) {
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4297
|
+
return componentHasAnnotation(component, "revision");
|
|
4298
|
+
}
|
|
4299
|
+
function createRevisionMark(mark) {
|
|
4300
|
+
const attributes = {
|
|
4301
|
+
id: globalRevisionIdRegistry.next(),
|
|
4302
|
+
author: mark.author || DEFAULT_REVISION_AUTHOR,
|
|
4303
|
+
date: mark.date || DEFAULT_REVISION_DATE
|
|
4304
|
+
};
|
|
4305
|
+
return mark.type === "insert" ? { insertion: attributes } : { deletion: attributes };
|
|
4306
|
+
}
|
|
4307
|
+
function createMarkedTextRuns(text, mark, baseStyle) {
|
|
4308
|
+
return createRevisionRuns(
|
|
4309
|
+
{
|
|
4310
|
+
author: mark.author,
|
|
4311
|
+
date: mark.date,
|
|
4312
|
+
segments: [{ type: mark.type, text }]
|
|
4313
|
+
},
|
|
4314
|
+
baseStyle
|
|
4315
|
+
);
|
|
4218
4316
|
}
|
|
4219
4317
|
|
|
4220
4318
|
// src/core/cached-render.ts
|
|
@@ -4291,14 +4389,23 @@ async function clearComponentCache() {
|
|
|
4291
4389
|
}
|
|
4292
4390
|
bypassStats.clear();
|
|
4293
4391
|
}
|
|
4392
|
+
var DYNAMIC_CONTEXT_COMPONENTS = /* @__PURE__ */ new Set([
|
|
4393
|
+
"toc",
|
|
4394
|
+
"section",
|
|
4395
|
+
"visual",
|
|
4396
|
+
"heading",
|
|
4397
|
+
"list",
|
|
4398
|
+
"paragraph"
|
|
4399
|
+
]);
|
|
4400
|
+
function componentBypassReason(component) {
|
|
4401
|
+
if (componentHasRevision(component)) return "revision-ids";
|
|
4402
|
+
if (componentHasAnnotation(component, "comment")) return "comment-ids";
|
|
4403
|
+
if ("id" in component) return "bookmark-id";
|
|
4404
|
+
if (DYNAMIC_CONTEXT_COMPONENTS.has(component.name)) return "dynamic-context";
|
|
4405
|
+
return null;
|
|
4406
|
+
}
|
|
4294
4407
|
async function renderComponentWithCache(component, theme, themeName, context, bypassCache = false) {
|
|
4295
|
-
const bypassReason =
|
|
4296
|
-
component
|
|
4297
|
-
) ? "revision-ids" : "id" in component ? "bookmark-id" : component.name === "toc" || component.name === "section" || component.name === "visual" || component.name === "heading" || // Both explicit lists and markdown-list paragraphs register
|
|
4298
|
-
// numbering in the current document scope. Cached paragraphs can
|
|
4299
|
-
// otherwise reference definitions that only existed in a previous
|
|
4300
|
-
// render.
|
|
4301
|
-
component.name === "list" || component.name === "paragraph" ? "dynamic-context" : null;
|
|
4408
|
+
const bypassReason = componentBypassReason(component);
|
|
4302
4409
|
if (!componentCache) {
|
|
4303
4410
|
initializeComponentCache();
|
|
4304
4411
|
}
|
|
@@ -4368,8 +4475,8 @@ function getComponentCacheStats() {
|
|
|
4368
4475
|
|
|
4369
4476
|
// src/core/content.ts
|
|
4370
4477
|
import {
|
|
4371
|
-
Paragraph,
|
|
4372
|
-
TextRun as
|
|
4478
|
+
Paragraph as Paragraph3,
|
|
4479
|
+
TextRun as TextRun7,
|
|
4373
4480
|
Table,
|
|
4374
4481
|
TableRow,
|
|
4375
4482
|
TableCell,
|
|
@@ -4464,6 +4571,252 @@ var BookmarkRegistry = class {
|
|
|
4464
4571
|
};
|
|
4465
4572
|
var globalBookmarkRegistry = new BookmarkRegistry();
|
|
4466
4573
|
|
|
4574
|
+
// src/utils/commentAnchors.ts
|
|
4575
|
+
import {
|
|
4576
|
+
CommentRangeEnd,
|
|
4577
|
+
CommentRangeStart,
|
|
4578
|
+
CommentReference,
|
|
4579
|
+
TextRun as TextRun5
|
|
4580
|
+
} from "docx";
|
|
4581
|
+
|
|
4582
|
+
// src/utils/commentRegistry.ts
|
|
4583
|
+
import { Paragraph, TextRun as TextRun4 } from "docx";
|
|
4584
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
|
|
4585
|
+
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
4586
|
+
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
4587
|
+
function createState() {
|
|
4588
|
+
return { counter: 0, comments: [], hasResolved: false };
|
|
4589
|
+
}
|
|
4590
|
+
function deriveInitials(author) {
|
|
4591
|
+
const initials = author.split(/[\s._-]+/).filter(Boolean).map((word) => word[0]).join("").toUpperCase().slice(0, 3);
|
|
4592
|
+
return initials || author.slice(0, 2).toUpperCase();
|
|
4593
|
+
}
|
|
4594
|
+
function bodyParagraphs(text) {
|
|
4595
|
+
return normalizeUnicodeText(text).split("\n").map((line) => new Paragraph({ children: [new TextRun4({ text: line })] }));
|
|
4596
|
+
}
|
|
4597
|
+
var CommentRegistry = class {
|
|
4598
|
+
fallback = createState();
|
|
4599
|
+
scopes = new AsyncLocalStorage4();
|
|
4600
|
+
get state() {
|
|
4601
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
4602
|
+
}
|
|
4603
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
4604
|
+
runScoped(callback) {
|
|
4605
|
+
return this.scopes.run(createState(), callback);
|
|
4606
|
+
}
|
|
4607
|
+
/**
|
|
4608
|
+
* Register a comment thread and return every id its anchors must carry — the
|
|
4609
|
+
* root first, then each reply in order. Word anchors every comment in a
|
|
4610
|
+
* thread over the same range, so all of them need a range and a reference.
|
|
4611
|
+
*
|
|
4612
|
+
* Ids are unique and monotonic within a render. `parentId` is derived here
|
|
4613
|
+
* rather than authored; docx turns it into the `w15:paraIdParent` links in
|
|
4614
|
+
* `word/commentsExtended.xml`.
|
|
4615
|
+
*/
|
|
4616
|
+
register(comment) {
|
|
4617
|
+
const state = this.state;
|
|
4618
|
+
const resolved = comment.resolved;
|
|
4619
|
+
const rootId = ++state.counter;
|
|
4620
|
+
state.comments.push({
|
|
4621
|
+
...this.toOptions(comment, rootId),
|
|
4622
|
+
...resolved !== void 0 && { resolved }
|
|
4623
|
+
});
|
|
4624
|
+
const ids = [rootId];
|
|
4625
|
+
for (const reply of comment.replies ?? []) {
|
|
4626
|
+
const replyId = ++state.counter;
|
|
4627
|
+
state.comments.push({
|
|
4628
|
+
...this.toOptions(reply, replyId),
|
|
4629
|
+
parentId: rootId,
|
|
4630
|
+
// Word resolves a thread as a whole, so the flag rides every member.
|
|
4631
|
+
...resolved !== void 0 && { resolved }
|
|
4632
|
+
});
|
|
4633
|
+
ids.push(replyId);
|
|
4634
|
+
}
|
|
4635
|
+
if (resolved !== void 0) state.hasResolved = true;
|
|
4636
|
+
return ids;
|
|
4637
|
+
}
|
|
4638
|
+
toOptions(comment, id) {
|
|
4639
|
+
const author = comment.author || DEFAULT_COMMENT_AUTHOR;
|
|
4640
|
+
return {
|
|
4641
|
+
id,
|
|
4642
|
+
author,
|
|
4643
|
+
initials: comment.initials || deriveInitials(author),
|
|
4644
|
+
date: new Date(comment.date || DEFAULT_COMMENT_DATE),
|
|
4645
|
+
children: bodyParagraphs(comment.text)
|
|
4646
|
+
};
|
|
4647
|
+
}
|
|
4648
|
+
/**
|
|
4649
|
+
* Every comment registered in this scope, in id order.
|
|
4650
|
+
*
|
|
4651
|
+
* docx writes `word/commentsExtended.xml` — and therefore any `w15:done` —
|
|
4652
|
+
* only when at least one comment in the document carries a `parentId`. A
|
|
4653
|
+
* document whose only resolved comment has no replies would silently lose
|
|
4654
|
+
* that state, so say so rather than dropping it quietly.
|
|
4655
|
+
*/
|
|
4656
|
+
getAll() {
|
|
4657
|
+
const state = this.state;
|
|
4658
|
+
if (state.hasResolved && !state.comments.some((comment) => comment.parentId !== void 0)) {
|
|
4659
|
+
console.warn(
|
|
4660
|
+
"A comment sets `resolved` but the document has no replies. Word stores the resolved flag in commentsExtended.xml, which is written only for threaded comments, so the flag will not survive."
|
|
4661
|
+
);
|
|
4662
|
+
}
|
|
4663
|
+
return [...state.comments];
|
|
4664
|
+
}
|
|
4665
|
+
/** Test-only: reset the current scope's counter and bodies. */
|
|
4666
|
+
clear() {
|
|
4667
|
+
const state = this.scopes.getStore();
|
|
4668
|
+
if (state) {
|
|
4669
|
+
state.counter = 0;
|
|
4670
|
+
state.comments.length = 0;
|
|
4671
|
+
state.hasResolved = false;
|
|
4672
|
+
} else {
|
|
4673
|
+
this.fallback = createState();
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
};
|
|
4677
|
+
var globalCommentRegistry = new CommentRegistry();
|
|
4678
|
+
|
|
4679
|
+
// src/utils/commentAnchors.ts
|
|
4680
|
+
function openCommentRange(comment) {
|
|
4681
|
+
if (!comment) return void 0;
|
|
4682
|
+
const ids = globalCommentRegistry.register(comment);
|
|
4683
|
+
return { ids, start: ids.map((id) => new CommentRangeStart(id)) };
|
|
4684
|
+
}
|
|
4685
|
+
function closeCommentRange(ids) {
|
|
4686
|
+
return ids.flatMap((id) => [
|
|
4687
|
+
new CommentRangeEnd(id),
|
|
4688
|
+
new TextRun5({ children: [new CommentReference(id)] })
|
|
4689
|
+
]);
|
|
4690
|
+
}
|
|
4691
|
+
|
|
4692
|
+
// src/utils/noteRegistry.ts
|
|
4693
|
+
import { Paragraph as Paragraph2, TextRun as TextRun6 } from "docx";
|
|
4694
|
+
import { AsyncLocalStorage as AsyncLocalStorage5 } from "async_hooks";
|
|
4695
|
+
function createState2() {
|
|
4696
|
+
return {
|
|
4697
|
+
footnoteCounter: 0,
|
|
4698
|
+
endnoteCounter: 0,
|
|
4699
|
+
footnotes: {},
|
|
4700
|
+
endnotes: {}
|
|
4701
|
+
};
|
|
4702
|
+
}
|
|
4703
|
+
function bodyParagraphs2(text, style) {
|
|
4704
|
+
return normalizeUnicodeText(text).split("\n").map(
|
|
4705
|
+
(line) => new Paragraph2({
|
|
4706
|
+
style,
|
|
4707
|
+
children: [new TextRun6({ text: line })]
|
|
4708
|
+
})
|
|
4709
|
+
);
|
|
4710
|
+
}
|
|
4711
|
+
var NoteRegistry = class {
|
|
4712
|
+
fallback = createState2();
|
|
4713
|
+
scopes = new AsyncLocalStorage5();
|
|
4714
|
+
get state() {
|
|
4715
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
4716
|
+
}
|
|
4717
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
4718
|
+
runScoped(callback) {
|
|
4719
|
+
return this.scopes.run(createState2(), callback);
|
|
4720
|
+
}
|
|
4721
|
+
/**
|
|
4722
|
+
* Register a footnote body and return the id its reference must use. Ids are
|
|
4723
|
+
* unique and monotonic within a render.
|
|
4724
|
+
*/
|
|
4725
|
+
registerFootnote(text) {
|
|
4726
|
+
const state = this.state;
|
|
4727
|
+
const id = ++state.footnoteCounter;
|
|
4728
|
+
state.footnotes[String(id)] = {
|
|
4729
|
+
children: bodyParagraphs2(text, "FootnoteText")
|
|
4730
|
+
};
|
|
4731
|
+
return id;
|
|
4732
|
+
}
|
|
4733
|
+
/** Register an endnote body and return the id its reference must use. */
|
|
4734
|
+
registerEndnote(text) {
|
|
4735
|
+
const state = this.state;
|
|
4736
|
+
const id = ++state.endnoteCounter;
|
|
4737
|
+
state.endnotes[String(id)] = {
|
|
4738
|
+
children: bodyParagraphs2(text, "EndnoteText")
|
|
4739
|
+
};
|
|
4740
|
+
return id;
|
|
4741
|
+
}
|
|
4742
|
+
/** Every footnote registered in this scope, keyed by id. */
|
|
4743
|
+
getFootnotes() {
|
|
4744
|
+
return { ...this.state.footnotes };
|
|
4745
|
+
}
|
|
4746
|
+
/** Every endnote registered in this scope, keyed by id. */
|
|
4747
|
+
getEndnotes() {
|
|
4748
|
+
return { ...this.state.endnotes };
|
|
4749
|
+
}
|
|
4750
|
+
/** Test-only: reset the current scope's counters and bodies. */
|
|
4751
|
+
clear() {
|
|
4752
|
+
const state = this.scopes.getStore();
|
|
4753
|
+
if (state) {
|
|
4754
|
+
state.footnoteCounter = 0;
|
|
4755
|
+
state.endnoteCounter = 0;
|
|
4756
|
+
for (const key of Object.keys(state.footnotes)) {
|
|
4757
|
+
delete state.footnotes[key];
|
|
4758
|
+
}
|
|
4759
|
+
for (const key of Object.keys(state.endnotes)) {
|
|
4760
|
+
delete state.endnotes[key];
|
|
4761
|
+
}
|
|
4762
|
+
} else {
|
|
4763
|
+
this.fallback = createState2();
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
};
|
|
4767
|
+
var globalNoteRegistry = new NoteRegistry();
|
|
4768
|
+
|
|
4769
|
+
// src/utils/noteResolver.ts
|
|
4770
|
+
function collectDeclared(footnotes, endnotes) {
|
|
4771
|
+
const declared = /* @__PURE__ */ new Map();
|
|
4772
|
+
const declare = (note, endnote) => {
|
|
4773
|
+
const existing = declared.get(note.id);
|
|
4774
|
+
if (existing) {
|
|
4775
|
+
console.warn(
|
|
4776
|
+
existing.endnote === endnote ? `Note id "${note.id}" is declared twice in the same ${endnote ? "endnotes" : "footnotes"} array. Using the first declaration and ignoring the rest.` : `Note id "${note.id}" is declared as both a footnote and an endnote in the same paragraph. Using the footnote and ignoring the endnote.`
|
|
4777
|
+
);
|
|
4778
|
+
return;
|
|
4779
|
+
}
|
|
4780
|
+
declared.set(note.id, { text: note.text, endnote });
|
|
4781
|
+
};
|
|
4782
|
+
for (const note of footnotes ?? []) declare(note, false);
|
|
4783
|
+
for (const note of endnotes ?? []) declare(note, true);
|
|
4784
|
+
return declared;
|
|
4785
|
+
}
|
|
4786
|
+
function createNoteResolver(footnotes, endnotes) {
|
|
4787
|
+
const declared = collectDeclared(footnotes, endnotes);
|
|
4788
|
+
if (declared.size === 0) return void 0;
|
|
4789
|
+
const registered = /* @__PURE__ */ new Map();
|
|
4790
|
+
return {
|
|
4791
|
+
resolve(id) {
|
|
4792
|
+
const existing = registered.get(id);
|
|
4793
|
+
if (existing !== void 0) return existing;
|
|
4794
|
+
const note = declared.get(id);
|
|
4795
|
+
if (note === void 0) {
|
|
4796
|
+
console.warn(
|
|
4797
|
+
`Note marker "[^${id}]" has no matching entry in this paragraph's footnotes or endnotes (declared: ${[...declared.keys()].join(", ")}). Rendering the marker as literal text.`
|
|
4798
|
+
);
|
|
4799
|
+
return void 0;
|
|
4800
|
+
}
|
|
4801
|
+
const resolved = {
|
|
4802
|
+
id: note.endnote ? globalNoteRegistry.registerEndnote(note.text) : globalNoteRegistry.registerFootnote(note.text),
|
|
4803
|
+
endnote: note.endnote
|
|
4804
|
+
};
|
|
4805
|
+
registered.set(id, resolved);
|
|
4806
|
+
return resolved;
|
|
4807
|
+
},
|
|
4808
|
+
reportUnemitted(text) {
|
|
4809
|
+
for (const [id, note] of declared) {
|
|
4810
|
+
if (registered.has(id)) continue;
|
|
4811
|
+
const kind = note.endnote ? "Endnote" : "Footnote";
|
|
4812
|
+
console.warn(
|
|
4813
|
+
text.includes(`[^${id}]`) ? `${kind} "${id}" is declared and its marker appears in the text, but the marker was not resolved \u2014 markers are not recognised in text that also contains {PLACEHOLDER} substitutions. The note will not appear in the document.` : `${kind} "${id}" is declared but never referenced as [^${id}] in this paragraph. It will not appear in the document.`
|
|
4814
|
+
);
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4817
|
+
};
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4467
4820
|
// src/core/content.ts
|
|
4468
4821
|
init_styleHelpers();
|
|
4469
4822
|
import { synthesizeFamilyName } from "@json-to-office/shared";
|
|
@@ -4487,6 +4840,20 @@ function resolveNoProofWords(theme, optionWords) {
|
|
|
4487
4840
|
const merged = [...themeWords || [], ...optionWords || []];
|
|
4488
4841
|
return merged.length > 0 ? Array.from(new Set(merged)) : void 0;
|
|
4489
4842
|
}
|
|
4843
|
+
function reportNotesUnsupportedInRevision(footnotes, endnotes, revision) {
|
|
4844
|
+
const declared = [...footnotes ?? [], ...endnotes ?? []];
|
|
4845
|
+
if (declared.length === 0) return;
|
|
4846
|
+
const text = revision.segments.map((segment) => segment.text).join("");
|
|
4847
|
+
const referenced = declared.filter((note) => text.includes(`[^${note.id}]`));
|
|
4848
|
+
console.warn(
|
|
4849
|
+
`Paragraph declares ${declared.length} note(s) (${declared.map((note) => note.id).join(", ")}) alongside a \`revision\`. Tracked-change text renders literally, so note markers are not resolved there` + (referenced.length > 0 ? ` \u2014 the marker(s) ${referenced.map((note) => `[^${note.id}]`).join(", ")} will render as literal text` : "") + ". The notes will not appear in the document."
|
|
4850
|
+
);
|
|
4851
|
+
}
|
|
4852
|
+
function wrapInComment(children, comment) {
|
|
4853
|
+
const anchor = openCommentRange(comment);
|
|
4854
|
+
if (!anchor) return children;
|
|
4855
|
+
return [...anchor.start, ...children, ...closeCommentRange(anchor.ids)];
|
|
4856
|
+
}
|
|
4490
4857
|
function createText(content, theme, themeName, options = {}) {
|
|
4491
4858
|
const normalizedContent = normalizeUnicodeText(content);
|
|
4492
4859
|
const style = options.style || "Normal";
|
|
@@ -4506,6 +4873,10 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4506
4873
|
if (options.columnBreak) {
|
|
4507
4874
|
children.push(new ColumnBreak());
|
|
4508
4875
|
}
|
|
4876
|
+
const commentAnchor = openCommentRange(options.comment);
|
|
4877
|
+
if (commentAnchor) {
|
|
4878
|
+
children.push(...commentAnchor.start);
|
|
4879
|
+
}
|
|
4509
4880
|
const hasWeightRequest = options.fontWeight != null || options.bold === true;
|
|
4510
4881
|
const effectiveFamily = options.fontFamily ?? (hasWeightRequest ? resolveFontFamily(theme, "body") : void 0);
|
|
4511
4882
|
const weighted = applyFontWeightAlias({
|
|
@@ -4542,6 +4913,11 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4542
4913
|
...options.noProof !== void 0 && { noProof: options.noProof }
|
|
4543
4914
|
};
|
|
4544
4915
|
if (options.revision) {
|
|
4916
|
+
reportNotesUnsupportedInRevision(
|
|
4917
|
+
options.footnotes,
|
|
4918
|
+
options.endnotes,
|
|
4919
|
+
options.revision
|
|
4920
|
+
);
|
|
4545
4921
|
const revisionRuns = createRevisionRuns(options.revision, baseTextStyle);
|
|
4546
4922
|
if (options.bookmarkId) {
|
|
4547
4923
|
globalBookmarkRegistry.register(
|
|
@@ -4559,11 +4935,17 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4559
4935
|
children.push(...revisionRuns);
|
|
4560
4936
|
}
|
|
4561
4937
|
} else {
|
|
4938
|
+
const noteResolver = createNoteResolver(
|
|
4939
|
+
options.footnotes,
|
|
4940
|
+
options.endnotes
|
|
4941
|
+
);
|
|
4562
4942
|
const textRuns = parseTextWithDecorators(normalizedContent, baseTextStyle, {
|
|
4563
4943
|
boldColor: options.boldColor ? resolveColor(options.boldColor, theme) : void 0,
|
|
4564
4944
|
enableHyperlinks: true,
|
|
4565
|
-
noProofWords: resolveNoProofWords(theme, options.noProofWords)
|
|
4945
|
+
noProofWords: resolveNoProofWords(theme, options.noProofWords),
|
|
4946
|
+
noteRef: noteResolver?.resolve
|
|
4566
4947
|
});
|
|
4948
|
+
noteResolver?.reportUnemitted(normalizedContent);
|
|
4567
4949
|
if (options.bookmarkId) {
|
|
4568
4950
|
globalBookmarkRegistry.register(
|
|
4569
4951
|
options.bookmarkId,
|
|
@@ -4580,9 +4962,12 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4580
4962
|
children.push(...textRuns);
|
|
4581
4963
|
}
|
|
4582
4964
|
}
|
|
4965
|
+
if (commentAnchor) {
|
|
4966
|
+
children.push(...closeCommentRange(commentAnchor.ids));
|
|
4967
|
+
}
|
|
4583
4968
|
const isFloating = !!options.floating;
|
|
4584
4969
|
const frameOptions = isFloating && options.floating ? mapFrameOptions(options.floating, theme, themeName) : void 0;
|
|
4585
|
-
return new
|
|
4970
|
+
return new Paragraph3({
|
|
4586
4971
|
children,
|
|
4587
4972
|
style,
|
|
4588
4973
|
alignment: options.alignment ? getAlignment(options.alignment) : void 0,
|
|
@@ -4677,6 +5062,10 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4677
5062
|
if (options.columnBreak) {
|
|
4678
5063
|
children.push(new ColumnBreak());
|
|
4679
5064
|
}
|
|
5065
|
+
const commentAnchor = openCommentRange(options.comment);
|
|
5066
|
+
if (commentAnchor) {
|
|
5067
|
+
children.push(...commentAnchor.start);
|
|
5068
|
+
}
|
|
4680
5069
|
const hasDecorators = /(\*\*\*|___|(\*\*|__)|(\*|_))/.test(normalizedText);
|
|
4681
5070
|
const headingHasWeightRequest = options.fontWeight != null || options.bold === true;
|
|
4682
5071
|
const headingEffectiveFamily = options.fontFamily ?? (headingHasWeightRequest ? resolveFontFamily(theme, "heading") : void 0);
|
|
@@ -4713,7 +5102,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4713
5102
|
const headingNoProofWords = resolveNoProofWords(theme, options.noProofWords);
|
|
4714
5103
|
const makeHeadingRuns = (value) => splitByNoProofWords(
|
|
4715
5104
|
value,
|
|
4716
|
-
(segment, matched) => new
|
|
5105
|
+
(segment, matched) => new TextRun7({
|
|
4717
5106
|
text: segment,
|
|
4718
5107
|
...baseTextStyle,
|
|
4719
5108
|
...matched && { noProof: true }
|
|
@@ -4772,7 +5161,10 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4772
5161
|
children.push(...makeHeadingRuns(normalizedText));
|
|
4773
5162
|
}
|
|
4774
5163
|
}
|
|
4775
|
-
|
|
5164
|
+
if (commentAnchor) {
|
|
5165
|
+
children.push(...closeCommentRange(commentAnchor.ids));
|
|
5166
|
+
}
|
|
5167
|
+
return new Paragraph3({
|
|
4776
5168
|
children,
|
|
4777
5169
|
style: styleId,
|
|
4778
5170
|
alignment: getAlignment(options.alignment || "left"),
|
|
@@ -4839,7 +5231,7 @@ async function createImage(path4, theme, themeName, options = {}) {
|
|
|
4839
5231
|
spacing.after = pointsToTwips(options.spacing.after);
|
|
4840
5232
|
}
|
|
4841
5233
|
elements.push(
|
|
4842
|
-
new
|
|
5234
|
+
new Paragraph3({
|
|
4843
5235
|
children: [imageRun],
|
|
4844
5236
|
alignment,
|
|
4845
5237
|
...Object.keys(spacing).length > 0 && { spacing },
|
|
@@ -4856,7 +5248,7 @@ async function createImage(path4, theme, themeName, options = {}) {
|
|
|
4856
5248
|
const hasDecorators = /(\*\*\*|___|(\*\*|__)|(\*|_))/.test(options.caption);
|
|
4857
5249
|
if (!hasDecorators) {
|
|
4858
5250
|
elements.push(
|
|
4859
|
-
new
|
|
5251
|
+
new Paragraph3({
|
|
4860
5252
|
text: normalizeUnicodeText(options.caption),
|
|
4861
5253
|
style: "Normal",
|
|
4862
5254
|
alignment: AlignmentType2.LEFT
|
|
@@ -4872,7 +5264,7 @@ async function createImage(path4, theme, themeName, options = {}) {
|
|
|
4872
5264
|
}
|
|
4873
5265
|
);
|
|
4874
5266
|
elements.push(
|
|
4875
|
-
new
|
|
5267
|
+
new Paragraph3({
|
|
4876
5268
|
children: textRuns,
|
|
4877
5269
|
style: "Normal",
|
|
4878
5270
|
// Use Normal style for consistent font inheritance
|
|
@@ -4889,13 +5281,13 @@ function createStatistic(data, options = {}) {
|
|
|
4889
5281
|
const normalizedNumber = normalizeUnicodeText(data.number);
|
|
4890
5282
|
const normalizedDescription = normalizeUnicodeText(data.description);
|
|
4891
5283
|
return [
|
|
4892
|
-
new
|
|
5284
|
+
new Paragraph3({
|
|
4893
5285
|
text: normalizedNumber,
|
|
4894
5286
|
style: "StatisticNumber",
|
|
4895
5287
|
alignment,
|
|
4896
5288
|
spacing: options.spacing
|
|
4897
5289
|
}),
|
|
4898
|
-
new
|
|
5290
|
+
new Paragraph3({
|
|
4899
5291
|
text: normalizedDescription,
|
|
4900
5292
|
style: "StatisticDescription",
|
|
4901
5293
|
alignment
|
|
@@ -4907,6 +5299,15 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
4907
5299
|
return [];
|
|
4908
5300
|
}
|
|
4909
5301
|
const paragraphs = [];
|
|
5302
|
+
const noteResolver = createNoteResolver(options.footnotes, options.endnotes);
|
|
5303
|
+
const rendersAt = items.map((item) => {
|
|
5304
|
+
const text = typeof item === "string" ? item : item.text;
|
|
5305
|
+
const revision = typeof item === "object" ? item.revision : void 0;
|
|
5306
|
+
return Boolean(text.trim()) || Boolean(revision);
|
|
5307
|
+
});
|
|
5308
|
+
const firstRendered = rendersAt.indexOf(true);
|
|
5309
|
+
const lastRendered = rendersAt.lastIndexOf(true);
|
|
5310
|
+
const commentAnchor = firstRendered === -1 ? void 0 : openCommentRange(options.comment);
|
|
4910
5311
|
items.forEach((item, index) => {
|
|
4911
5312
|
const itemText = typeof item === "string" ? item : item.text;
|
|
4912
5313
|
const itemLevel = typeof item === "object" ? item.level || 0 : 0;
|
|
@@ -4918,7 +5319,8 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
4918
5319
|
itemText,
|
|
4919
5320
|
{},
|
|
4920
5321
|
{
|
|
4921
|
-
enableHyperlinks: true
|
|
5322
|
+
enableHyperlinks: true,
|
|
5323
|
+
noteRef: noteResolver?.resolve
|
|
4922
5324
|
}
|
|
4923
5325
|
);
|
|
4924
5326
|
const spacing = {};
|
|
@@ -4930,10 +5332,15 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
4930
5332
|
} else if (options.spacing?.item) {
|
|
4931
5333
|
spacing.after = pointsToTwips(options.spacing.item);
|
|
4932
5334
|
}
|
|
4933
|
-
const
|
|
5335
|
+
const paragraphChildren = [
|
|
5336
|
+
...commentAnchor && index === firstRendered ? commentAnchor.start : [],
|
|
5337
|
+
...textRuns,
|
|
5338
|
+
...commentAnchor && index === lastRendered ? closeCommentRange(commentAnchor.ids) : []
|
|
5339
|
+
];
|
|
5340
|
+
const paragraph = new Paragraph3({
|
|
4934
5341
|
style: "Normal",
|
|
4935
5342
|
// Apply Normal style for font inheritance
|
|
4936
|
-
children:
|
|
5343
|
+
children: paragraphChildren,
|
|
4937
5344
|
alignment: options.alignment ? getAlignment(options.alignment) : AlignmentType2.LEFT,
|
|
4938
5345
|
spacing,
|
|
4939
5346
|
// Use proper docx numbering instead of prepending text
|
|
@@ -4946,6 +5353,9 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
4946
5353
|
});
|
|
4947
5354
|
paragraphs.push(paragraph);
|
|
4948
5355
|
});
|
|
5356
|
+
noteResolver?.reportUnemitted(
|
|
5357
|
+
items.map((item) => typeof item === "string" ? item : item.text).join("\n")
|
|
5358
|
+
);
|
|
4949
5359
|
return paragraphs;
|
|
4950
5360
|
}
|
|
4951
5361
|
async function createTable(columns, tableConfig, theme, themeName, _options = {}) {
|
|
@@ -5279,10 +5689,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5279
5689
|
return false;
|
|
5280
5690
|
}
|
|
5281
5691
|
};
|
|
5282
|
-
const processCellContent = async (cell, cellDefaults, baseCellStyle) => {
|
|
5692
|
+
const processCellContent = async (cell, cellDefaults, baseCellStyle, comment, revision, rowMark) => {
|
|
5283
5693
|
let cellChildren = [];
|
|
5284
5694
|
if (!cell) {
|
|
5285
|
-
return cellChildren;
|
|
5695
|
+
return wrapInComment(cellChildren, comment);
|
|
5286
5696
|
}
|
|
5287
5697
|
const cellWeighted = applyFontWeightAlias({
|
|
5288
5698
|
fontFamily: cellDefaults.font?.family || baseCellStyle.font,
|
|
@@ -5326,11 +5736,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5326
5736
|
color: resolveColor(paragraphFont.color, theme)
|
|
5327
5737
|
}
|
|
5328
5738
|
};
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
);
|
|
5739
|
+
const paragraphRevision = revision ?? textComp.props.revision;
|
|
5740
|
+
cellChildren = paragraphRevision ? createRevisionRuns(paragraphRevision, paragraphStyle) : rowMark ? createMarkedTextRuns(textComp.props.text, rowMark, paragraphStyle) : parseTextWithDecorators(textComp.props.text, paragraphStyle, {
|
|
5741
|
+
enableHyperlinks: true
|
|
5742
|
+
});
|
|
5334
5743
|
} else if (isImageComponent(cell)) {
|
|
5335
5744
|
const imageComp = cell;
|
|
5336
5745
|
try {
|
|
@@ -5365,7 +5774,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5365
5774
|
} catch (error) {
|
|
5366
5775
|
const imageSource = imageComp.props.svg?.trim() ? "inline-svg" : imageComp.props.base64 || imageComp.props.path || "unknown";
|
|
5367
5776
|
cellChildren = [
|
|
5368
|
-
new
|
|
5777
|
+
new TextRun7({
|
|
5369
5778
|
text: `[IMAGE: ${imageSource.substring(0, 50)}${imageSource.length > 50 ? "..." : ""}]`,
|
|
5370
5779
|
font: mergedStyle.font,
|
|
5371
5780
|
size: mergedStyle.size,
|
|
@@ -5375,7 +5784,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5375
5784
|
}
|
|
5376
5785
|
} else {
|
|
5377
5786
|
cellChildren = [
|
|
5378
|
-
new
|
|
5787
|
+
new TextRun7({
|
|
5379
5788
|
text: `[Unsupported component type: ${cell.name}]`,
|
|
5380
5789
|
font: mergedStyle.font,
|
|
5381
5790
|
size: mergedStyle.size,
|
|
@@ -5384,11 +5793,11 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5384
5793
|
];
|
|
5385
5794
|
}
|
|
5386
5795
|
} else {
|
|
5387
|
-
cellChildren = parseTextWithDecorators(cell, mergedStyle, {
|
|
5796
|
+
cellChildren = revision ? createRevisionRuns(revision, mergedStyle) : rowMark ? createMarkedTextRuns(cell, rowMark, mergedStyle) : parseTextWithDecorators(cell, mergedStyle, {
|
|
5388
5797
|
enableHyperlinks: true
|
|
5389
5798
|
});
|
|
5390
5799
|
}
|
|
5391
|
-
return cellChildren;
|
|
5800
|
+
return wrapInComment(cellChildren, comment);
|
|
5392
5801
|
};
|
|
5393
5802
|
const numColumns = columns.length;
|
|
5394
5803
|
const headerHeight = columns.reduce(
|
|
@@ -5445,7 +5854,9 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5445
5854
|
const cellChildren = await processCellContent(
|
|
5446
5855
|
headerCell?.content,
|
|
5447
5856
|
mergedDefaults,
|
|
5448
|
-
tableStyle.tableHeader
|
|
5857
|
+
tableStyle.tableHeader,
|
|
5858
|
+
headerCell?.comment,
|
|
5859
|
+
headerCell?.revision
|
|
5449
5860
|
);
|
|
5450
5861
|
const horizontalAlignment = mergedDefaults.horizontalAlignment;
|
|
5451
5862
|
const verticalAlignment = getVerticalAlignment(
|
|
@@ -5453,7 +5864,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5453
5864
|
);
|
|
5454
5865
|
return new TableCell({
|
|
5455
5866
|
children: [
|
|
5456
|
-
new
|
|
5867
|
+
new Paragraph3({
|
|
5457
5868
|
...tableConfig.keepInOnePage && { keepNext: true },
|
|
5458
5869
|
spacing: tableStyle.headerParagraph,
|
|
5459
5870
|
alignment: getAlignment(horizontalAlignment),
|
|
@@ -5496,6 +5907,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5496
5907
|
const dataRows = await Promise.all(
|
|
5497
5908
|
Array.from({ length: numRows }, async (_, rowIndex) => {
|
|
5498
5909
|
const isLastRow = rowIndex === numRows - 1;
|
|
5910
|
+
const rowProps = tableConfig.rows?.[rowIndex];
|
|
5911
|
+
const rowRevision = rowProps?.revision;
|
|
5912
|
+
const rowRevisionAttributes = rowRevision ? createRevisionMark(rowRevision) : void 0;
|
|
5913
|
+
const paragraphMarks = rowRevision ? columns.map(() => ({ run: createRevisionMark(rowRevision) })) : void 0;
|
|
5499
5914
|
const rowHeight = columns.reduce(
|
|
5500
5915
|
(maxHeight, column, colIndex) => {
|
|
5501
5916
|
const cell = column.cells?.[rowIndex];
|
|
@@ -5525,6 +5940,14 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5525
5940
|
);
|
|
5526
5941
|
return new TableRow({
|
|
5527
5942
|
height: rowHeight !== void 0 ? { value: rowHeight * 20, rule: "atLeast" } : void 0,
|
|
5943
|
+
...rowProps?.cantSplit !== void 0 && {
|
|
5944
|
+
cantSplit: rowProps.cantSplit
|
|
5945
|
+
},
|
|
5946
|
+
...rowProps?.tableHeader !== void 0 && {
|
|
5947
|
+
tableHeader: rowProps.tableHeader
|
|
5948
|
+
},
|
|
5949
|
+
// w:trPr/w:ins | w:del — the row itself was inserted or deleted.
|
|
5950
|
+
...rowRevisionAttributes,
|
|
5528
5951
|
children: await Promise.all(
|
|
5529
5952
|
columns.map(async (column, colIndex) => {
|
|
5530
5953
|
const cell = column.cells?.[rowIndex];
|
|
@@ -5548,10 +5971,11 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5548
5971
|
);
|
|
5549
5972
|
return new TableCell({
|
|
5550
5973
|
children: [
|
|
5551
|
-
new
|
|
5974
|
+
new Paragraph3({
|
|
5552
5975
|
...tableConfig.keepInOnePage && !isLastRow || isLastRow && tableConfig.keepNext ? { keepNext: true } : {},
|
|
5553
5976
|
spacing: tableStyle.cellParagraph,
|
|
5554
5977
|
alignment: AlignmentType2.LEFT,
|
|
5978
|
+
...paragraphMarks?.[colIndex],
|
|
5555
5979
|
children: []
|
|
5556
5980
|
})
|
|
5557
5981
|
],
|
|
@@ -5616,7 +6040,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5616
6040
|
const cellChildren = await processCellContent(
|
|
5617
6041
|
cell.content,
|
|
5618
6042
|
mergedDefaults,
|
|
5619
|
-
tableStyle.tableCell
|
|
6043
|
+
tableStyle.tableCell,
|
|
6044
|
+
cell.comment,
|
|
6045
|
+
cell.revision,
|
|
6046
|
+
rowRevision
|
|
5620
6047
|
);
|
|
5621
6048
|
const horizontalAlignment = mergedDefaults.horizontalAlignment;
|
|
5622
6049
|
const verticalAlignment = getVerticalAlignment(
|
|
@@ -5624,10 +6051,11 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5624
6051
|
);
|
|
5625
6052
|
return new TableCell({
|
|
5626
6053
|
children: [
|
|
5627
|
-
new
|
|
6054
|
+
new Paragraph3({
|
|
5628
6055
|
...tableConfig.keepInOnePage && !isLastRow || isLastRow && tableConfig.keepNext ? { keepNext: true } : {},
|
|
5629
6056
|
spacing: tableStyle.cellParagraph,
|
|
5630
6057
|
alignment: getAlignment(horizontalAlignment),
|
|
6058
|
+
...paragraphMarks?.[colIndex],
|
|
5631
6059
|
children: cellChildren
|
|
5632
6060
|
})
|
|
5633
6061
|
],
|
|
@@ -5786,7 +6214,9 @@ function renderHeadingComponent(component, theme, themeName) {
|
|
|
5786
6214
|
// Bookmark ID for internal linking
|
|
5787
6215
|
bookmarkId,
|
|
5788
6216
|
// Tracked-change segments (rendered as native Word revisions)
|
|
5789
|
-
revision: config.revision
|
|
6217
|
+
revision: config.revision,
|
|
6218
|
+
// Review comment anchored to this heading's text
|
|
6219
|
+
comment: config.comment
|
|
5790
6220
|
}
|
|
5791
6221
|
);
|
|
5792
6222
|
return [header];
|
|
@@ -5794,7 +6224,7 @@ function renderHeadingComponent(component, theme, themeName) {
|
|
|
5794
6224
|
|
|
5795
6225
|
// src/utils/numberingConfig.ts
|
|
5796
6226
|
import { AlignmentType as AlignmentType3, convertInchesToTwip, LevelFormat } from "docx";
|
|
5797
|
-
import { AsyncLocalStorage as
|
|
6227
|
+
import { AsyncLocalStorage as AsyncLocalStorage6 } from "async_hooks";
|
|
5798
6228
|
var LEVEL_FORMAT_MAP = {
|
|
5799
6229
|
decimal: LevelFormat.DECIMAL,
|
|
5800
6230
|
upperRoman: LevelFormat.UPPER_ROMAN,
|
|
@@ -5872,6 +6302,21 @@ function getAlignment2(alignment) {
|
|
|
5872
6302
|
if (!alignment) return AlignmentType3.LEFT;
|
|
5873
6303
|
return ALIGNMENT_MAP[alignment] || AlignmentType3.LEFT;
|
|
5874
6304
|
}
|
|
6305
|
+
function createMarkerRunStyle(font) {
|
|
6306
|
+
if (!font) return void 0;
|
|
6307
|
+
const run = {
|
|
6308
|
+
...font.family && { font: font.family },
|
|
6309
|
+
// docx run sizes are half-points.
|
|
6310
|
+
...font.size !== void 0 && { size: font.size * 2 },
|
|
6311
|
+
...font.color && { color: font.color },
|
|
6312
|
+
...font.bold !== void 0 && { bold: font.bold },
|
|
6313
|
+
...font.italic !== void 0 && { italics: font.italic },
|
|
6314
|
+
...font.underline !== void 0 && {
|
|
6315
|
+
underline: font.underline ? { type: "single" } : void 0
|
|
6316
|
+
}
|
|
6317
|
+
};
|
|
6318
|
+
return Object.keys(run).length > 0 ? run : void 0;
|
|
6319
|
+
}
|
|
5875
6320
|
function createNumberingConfig(config) {
|
|
5876
6321
|
const levels = [];
|
|
5877
6322
|
for (const levelConfig of config.levels) {
|
|
@@ -5880,6 +6325,7 @@ function createNumberingConfig(config) {
|
|
|
5880
6325
|
const text = levelConfig.text || (format2 === LevelFormat.BULLET ? "\u2022" : `%${levelConfig.level + 1}.`);
|
|
5881
6326
|
const baseIndent = levelConfig.indent?.left !== void 0 ? levelConfig.indent.left / 72 : 0.5 * (levelConfig.level + 1);
|
|
5882
6327
|
const hangingIndent = levelConfig.indent?.hanging !== void 0 ? levelConfig.indent.hanging / 72 : 0.25;
|
|
6328
|
+
const markerRun = createMarkerRunStyle(levelConfig.font);
|
|
5883
6329
|
const level = {
|
|
5884
6330
|
level: levelConfig.level,
|
|
5885
6331
|
format: format2,
|
|
@@ -5891,7 +6337,10 @@ function createNumberingConfig(config) {
|
|
|
5891
6337
|
left: convertInchesToTwip(baseIndent),
|
|
5892
6338
|
hanging: convertInchesToTwip(hangingIndent)
|
|
5893
6339
|
}
|
|
5894
|
-
}
|
|
6340
|
+
},
|
|
6341
|
+
// The marker glyph carries its own run properties; without this it
|
|
6342
|
+
// inherits whatever the list paragraph resolves to.
|
|
6343
|
+
...markerRun && { run: markerRun }
|
|
5895
6344
|
},
|
|
5896
6345
|
// Add start number if specified
|
|
5897
6346
|
...levelConfig.start !== void 0 && { start: levelConfig.start }
|
|
@@ -5908,7 +6357,7 @@ var NumberingRegistry = class {
|
|
|
5908
6357
|
configs: /* @__PURE__ */ new Map(),
|
|
5909
6358
|
counter: 0
|
|
5910
6359
|
};
|
|
5911
|
-
scopes = new
|
|
6360
|
+
scopes = new AsyncLocalStorage6();
|
|
5912
6361
|
get state() {
|
|
5913
6362
|
return this.scopes.getStore() ?? this.fallback;
|
|
5914
6363
|
}
|
|
@@ -6020,7 +6469,10 @@ function renderParagraphComponent(component, theme, themeName) {
|
|
|
6020
6469
|
return createList(listData.items, theme, themeName, {
|
|
6021
6470
|
numberingReference: reference,
|
|
6022
6471
|
spacing: resolvedConfig.spacing,
|
|
6023
|
-
alignment: resolvedConfig.alignment
|
|
6472
|
+
alignment: resolvedConfig.alignment,
|
|
6473
|
+
comment: resolvedConfig.comment,
|
|
6474
|
+
footnotes: resolvedConfig.footnotes,
|
|
6475
|
+
endnotes: resolvedConfig.endnotes
|
|
6024
6476
|
});
|
|
6025
6477
|
}
|
|
6026
6478
|
const styleFromTheme = (() => {
|
|
@@ -6084,12 +6536,18 @@ function renderParagraphComponent(component, theme, themeName) {
|
|
|
6084
6536
|
// Pass bookmark ID for internal linking
|
|
6085
6537
|
bookmarkId: resolvedConfig.id,
|
|
6086
6538
|
// Tracked-change segments (rendered as native Word revisions)
|
|
6087
|
-
revision: resolvedConfig.revision
|
|
6539
|
+
revision: resolvedConfig.revision,
|
|
6540
|
+
// Review comment anchored to this paragraph's text
|
|
6541
|
+
comment: resolvedConfig.comment,
|
|
6542
|
+
// Note bodies for the `[^id]` markers in this paragraph
|
|
6543
|
+
footnotes: resolvedConfig.footnotes,
|
|
6544
|
+
endnotes: resolvedConfig.endnotes
|
|
6088
6545
|
});
|
|
6089
6546
|
return [text];
|
|
6090
6547
|
}
|
|
6091
6548
|
|
|
6092
6549
|
// src/components/list.ts
|
|
6550
|
+
init_colorUtils();
|
|
6093
6551
|
function createLevelsFromSimplifiedProps(props) {
|
|
6094
6552
|
const levels = [];
|
|
6095
6553
|
let format2;
|
|
@@ -6136,6 +6594,22 @@ function createLevelsFromSimplifiedProps(props) {
|
|
|
6136
6594
|
}
|
|
6137
6595
|
return levels;
|
|
6138
6596
|
}
|
|
6597
|
+
function resolveMarkerFonts(levels, theme) {
|
|
6598
|
+
return levels.map((level) => {
|
|
6599
|
+
const font = level.font;
|
|
6600
|
+
if (!font?.color) return level;
|
|
6601
|
+
return {
|
|
6602
|
+
...level,
|
|
6603
|
+
font: { ...font, color: resolveColor(font.color, theme) }
|
|
6604
|
+
};
|
|
6605
|
+
});
|
|
6606
|
+
}
|
|
6607
|
+
function applyListStart(levels, start) {
|
|
6608
|
+
if (start === void 0) return levels;
|
|
6609
|
+
return levels.map(
|
|
6610
|
+
(level) => level.level === 0 && level.start === void 0 ? { ...level, start } : level
|
|
6611
|
+
);
|
|
6612
|
+
}
|
|
6139
6613
|
function getMaxLevelFromItems(items) {
|
|
6140
6614
|
if (!items || !Array.isArray(items)) {
|
|
6141
6615
|
return 0;
|
|
@@ -6198,7 +6672,10 @@ function renderListComponent(component, theme, themeName) {
|
|
|
6198
6672
|
let levels;
|
|
6199
6673
|
if (resolvedConfig.levels && resolvedConfig.levels.length > 0) {
|
|
6200
6674
|
levels = fillMissingLevels(
|
|
6201
|
-
|
|
6675
|
+
applyListStart(
|
|
6676
|
+
resolvedConfig.levels,
|
|
6677
|
+
resolvedConfig.start
|
|
6678
|
+
),
|
|
6202
6679
|
maxLevel
|
|
6203
6680
|
);
|
|
6204
6681
|
} else {
|
|
@@ -6207,7 +6684,7 @@ function renderListComponent(component, theme, themeName) {
|
|
|
6207
6684
|
}
|
|
6208
6685
|
const config = {
|
|
6209
6686
|
reference,
|
|
6210
|
-
levels
|
|
6687
|
+
levels: resolveMarkerFonts(levels, theme)
|
|
6211
6688
|
};
|
|
6212
6689
|
const numberingConfig = createNumberingConfig(config);
|
|
6213
6690
|
globalNumberingRegistry.register(numberingConfig);
|
|
@@ -6215,7 +6692,9 @@ function renderListComponent(component, theme, themeName) {
|
|
|
6215
6692
|
return createList(resolvedConfig.items, theme, themeName, {
|
|
6216
6693
|
numberingReference: reference,
|
|
6217
6694
|
spacing: resolvedConfig.spacing,
|
|
6218
|
-
alignment: resolvedConfig.alignment
|
|
6695
|
+
alignment: resolvedConfig.alignment,
|
|
6696
|
+
// Review comment spanning the whole list
|
|
6697
|
+
comment: resolvedConfig.comment
|
|
6219
6698
|
});
|
|
6220
6699
|
}
|
|
6221
6700
|
|
|
@@ -6306,10 +6785,10 @@ function convertBorders2(bordersConfig, theme) {
|
|
|
6306
6785
|
// src/styles/utils/cellUtils.ts
|
|
6307
6786
|
init_styleHelpers();
|
|
6308
6787
|
init_colorUtils();
|
|
6309
|
-
import { Paragraph as
|
|
6788
|
+
import { Paragraph as Paragraph4 } from "docx";
|
|
6310
6789
|
function buildCellOptions(children, styleCfg, theme) {
|
|
6311
6790
|
const cellOpts = {
|
|
6312
|
-
children: children.length ? children : [new
|
|
6791
|
+
children: children.length ? children : [new Paragraph4({})],
|
|
6313
6792
|
margins: {
|
|
6314
6793
|
top: styleCfg?.padding?.top ? pointsToTwips(styleCfg.padding.top) : 0,
|
|
6315
6794
|
right: styleCfg?.padding?.right ? pointsToTwips(styleCfg.padding.right) : 0,
|
|
@@ -6512,25 +6991,66 @@ async function renderTableComponent(component, theme, themeName) {
|
|
|
6512
6991
|
}
|
|
6513
6992
|
|
|
6514
6993
|
// src/components/section.ts
|
|
6515
|
-
import { Paragraph as
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6994
|
+
import { Paragraph as Paragraph6, BookmarkStart, BookmarkEnd } from "docx";
|
|
6995
|
+
|
|
6996
|
+
// src/core/sectionBookmarks.ts
|
|
6997
|
+
import { AsyncLocalStorage as AsyncLocalStorage7 } from "async_hooks";
|
|
6998
|
+
var NESTED_LINK_ID_BASE = 1e6;
|
|
6999
|
+
function createState3() {
|
|
7000
|
+
return { nextNested: 1, resolved: /* @__PURE__ */ new WeakMap() };
|
|
7001
|
+
}
|
|
7002
|
+
var SectionBookmarkRegistry = class {
|
|
7003
|
+
fallback = createState3();
|
|
7004
|
+
scopes = new AsyncLocalStorage7();
|
|
7005
|
+
get state() {
|
|
7006
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
7007
|
+
}
|
|
7008
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
7009
|
+
runScoped(callback) {
|
|
7010
|
+
return this.scopes.run(createState3(), callback);
|
|
7011
|
+
}
|
|
7012
|
+
/**
|
|
7013
|
+
* The bookmark for a layout section, derived from its ordinal.
|
|
7014
|
+
*
|
|
7015
|
+
* Every layout chunk of one user-defined section shares an ordinal (see
|
|
7016
|
+
* `computeSectionOrdinals`), so they all resolve to the same bookmark — which
|
|
7017
|
+
* is the point: the start lands in the first chunk and the end in the last.
|
|
7018
|
+
*/
|
|
7019
|
+
forLayoutSection(ordinal) {
|
|
7020
|
+
return { id: `_Section_${ordinal}`, linkId: ordinal };
|
|
7021
|
+
}
|
|
7022
|
+
/**
|
|
7023
|
+
* The bookmark for a `section` component, allocated on first sight and
|
|
7024
|
+
* remembered so re-resolving the same component never allocates twice.
|
|
7025
|
+
*/
|
|
7026
|
+
forSectionComponent(component) {
|
|
7027
|
+
const state = this.state;
|
|
7028
|
+
const existing = state.resolved.get(component);
|
|
7029
|
+
if (existing) return existing;
|
|
7030
|
+
const ordinal = state.nextNested++;
|
|
7031
|
+
const bookmark = {
|
|
7032
|
+
id: `_NestedSection_${ordinal}`,
|
|
7033
|
+
linkId: NESTED_LINK_ID_BASE + ordinal
|
|
7034
|
+
};
|
|
7035
|
+
state.resolved.set(component, bookmark);
|
|
7036
|
+
return bookmark;
|
|
7037
|
+
}
|
|
7038
|
+
/** Test-only: reset the unscoped fallback counters. */
|
|
7039
|
+
clear() {
|
|
7040
|
+
if (!this.scopes.getStore()) {
|
|
7041
|
+
this.fallback = createState3();
|
|
7042
|
+
}
|
|
7043
|
+
}
|
|
7044
|
+
};
|
|
7045
|
+
var globalSectionBookmarkRegistry = new SectionBookmarkRegistry();
|
|
7046
|
+
|
|
7047
|
+
// src/components/section.ts
|
|
6528
7048
|
async function renderSectionComponent(component, theme, themeName, context) {
|
|
6529
7049
|
if (!isSectionComponent(component)) return [];
|
|
6530
7050
|
const elements = [];
|
|
6531
|
-
const { id: sectionBookmarkId, linkId: bookmarkLinkId } =
|
|
7051
|
+
const { id: sectionBookmarkId, linkId: bookmarkLinkId } = globalSectionBookmarkRegistry.forSectionComponent(component);
|
|
6532
7052
|
elements.push(
|
|
6533
|
-
new
|
|
7053
|
+
new Paragraph6({
|
|
6534
7054
|
children: [new BookmarkStart(sectionBookmarkId, bookmarkLinkId)],
|
|
6535
7055
|
spacing: {
|
|
6536
7056
|
before: 0,
|
|
@@ -6558,7 +7078,7 @@ async function renderSectionComponent(component, theme, themeName, context) {
|
|
|
6558
7078
|
}
|
|
6559
7079
|
}
|
|
6560
7080
|
elements.push(
|
|
6561
|
-
new
|
|
7081
|
+
new Paragraph6({
|
|
6562
7082
|
children: [new BookmarkEnd(bookmarkLinkId)],
|
|
6563
7083
|
spacing: {
|
|
6564
7084
|
before: 0,
|
|
@@ -6572,7 +7092,7 @@ async function renderSectionComponent(component, theme, themeName, context) {
|
|
|
6572
7092
|
|
|
6573
7093
|
// src/components/columns.ts
|
|
6574
7094
|
import {
|
|
6575
|
-
Paragraph as
|
|
7095
|
+
Paragraph as Paragraph7,
|
|
6576
7096
|
Table as Table5,
|
|
6577
7097
|
TableRow as TableRow3,
|
|
6578
7098
|
TableCell as TableCell3,
|
|
@@ -6664,7 +7184,7 @@ async function renderColumnsAsTable(component, theme, themeName, context) {
|
|
|
6664
7184
|
columnElements.push(...rendered);
|
|
6665
7185
|
}
|
|
6666
7186
|
if (columnElements.length === 0) {
|
|
6667
|
-
columnElements.push(new
|
|
7187
|
+
columnElements.push(new Paragraph7({}));
|
|
6668
7188
|
}
|
|
6669
7189
|
cells.push(
|
|
6670
7190
|
new TableCell3({
|
|
@@ -6715,12 +7235,34 @@ function renderStatisticComponent(component, _theme) {
|
|
|
6715
7235
|
|
|
6716
7236
|
// src/components/toc/index.ts
|
|
6717
7237
|
import {
|
|
6718
|
-
Paragraph as
|
|
7238
|
+
Paragraph as Paragraph8,
|
|
6719
7239
|
TableOfContents,
|
|
6720
7240
|
AlignmentType as AlignmentType4,
|
|
6721
|
-
TextRun as
|
|
7241
|
+
TextRun as TextRun8,
|
|
6722
7242
|
StyleLevel
|
|
6723
7243
|
} from "docx";
|
|
7244
|
+
function toStyleDisplayName(styleId) {
|
|
7245
|
+
return styleId.replace(/([A-Z])/g, " $1").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
|
|
7246
|
+
}
|
|
7247
|
+
function selectCachedEntries(collected, options) {
|
|
7248
|
+
if (!collected || collected.length === 0) return [];
|
|
7249
|
+
const { depthStart, depthEnd, sectionBookmarkId, styleLevels } = options;
|
|
7250
|
+
const entries = [];
|
|
7251
|
+
for (const entry of collected) {
|
|
7252
|
+
if (sectionBookmarkId && entry.sectionBookmarkId !== sectionBookmarkId) {
|
|
7253
|
+
continue;
|
|
7254
|
+
}
|
|
7255
|
+
if (entry.styleId !== void 0) {
|
|
7256
|
+
const level = styleLevels.get(entry.styleId) ?? styleLevels.get(toStyleDisplayName(entry.styleId));
|
|
7257
|
+
if (level === void 0) continue;
|
|
7258
|
+
entries.push({ title: entry.title, level });
|
|
7259
|
+
continue;
|
|
7260
|
+
}
|
|
7261
|
+
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
7262
|
+
entries.push({ title: entry.title, level: entry.level });
|
|
7263
|
+
}
|
|
7264
|
+
return entries;
|
|
7265
|
+
}
|
|
6724
7266
|
function parseDepthRange(rawDepth, fieldName, defaultFrom = 1, defaultTo = 3) {
|
|
6725
7267
|
if (typeof rawDepth !== "object" || rawDepth === null) {
|
|
6726
7268
|
throw new Error(
|
|
@@ -6776,9 +7318,9 @@ function renderTocComponent(component, theme, context) {
|
|
|
6776
7318
|
const paragraphs = [];
|
|
6777
7319
|
if (componentProps.title) {
|
|
6778
7320
|
paragraphs.push(
|
|
6779
|
-
new
|
|
7321
|
+
new Paragraph8({
|
|
6780
7322
|
children: [
|
|
6781
|
-
new
|
|
7323
|
+
new TextRun8({
|
|
6782
7324
|
text: componentProps.title,
|
|
6783
7325
|
bold: true,
|
|
6784
7326
|
size: 28
|
|
@@ -6796,11 +7338,14 @@ function renderTocComponent(component, theme, context) {
|
|
|
6796
7338
|
);
|
|
6797
7339
|
}
|
|
6798
7340
|
const stylesWithLevels = [];
|
|
7341
|
+
const styleLevels = /* @__PURE__ */ new Map();
|
|
6799
7342
|
if (componentProps.styles && componentProps.styles.length > 0) {
|
|
6800
7343
|
for (const styleMapping of componentProps.styles) {
|
|
6801
7344
|
const styleId = styleMapping.styleId;
|
|
6802
7345
|
const isCustomStyle = !!theme.styles && Object.prototype.hasOwnProperty.call(theme.styles, styleId);
|
|
6803
|
-
const styleDisplayName = isCustomStyle ? styleId
|
|
7346
|
+
const styleDisplayName = isCustomStyle ? toStyleDisplayName(styleId) : styleId;
|
|
7347
|
+
styleLevels.set(styleId, styleMapping.level);
|
|
7348
|
+
styleLevels.set(styleDisplayName, styleMapping.level);
|
|
6804
7349
|
stylesWithLevels.push(
|
|
6805
7350
|
new StyleLevel(styleDisplayName, styleMapping.level)
|
|
6806
7351
|
);
|
|
@@ -6808,6 +7353,12 @@ function renderTocComponent(component, theme, context) {
|
|
|
6808
7353
|
}
|
|
6809
7354
|
const effectiveDepthStart = depthStart;
|
|
6810
7355
|
const effectiveDepthEnd = depthEnd;
|
|
7356
|
+
const cachedEntries = selectCachedEntries(context?.tocHeadings, {
|
|
7357
|
+
depthStart,
|
|
7358
|
+
depthEnd,
|
|
7359
|
+
sectionBookmarkId,
|
|
7360
|
+
styleLevels
|
|
7361
|
+
});
|
|
6811
7362
|
const tocOptions = {
|
|
6812
7363
|
hyperlink: true,
|
|
6813
7364
|
// Enable clickable hyperlinks (\h switch)
|
|
@@ -6846,7 +7397,10 @@ function renderTocComponent(component, theme, context) {
|
|
|
6846
7397
|
// default to tab
|
|
6847
7398
|
};
|
|
6848
7399
|
paragraphs.push(
|
|
6849
|
-
new TableOfContents(componentProps.title ?? "Table of Contents",
|
|
7400
|
+
new TableOfContents(componentProps.title ?? "Table of Contents", {
|
|
7401
|
+
...tocOptions,
|
|
7402
|
+
...cachedEntries.length > 0 && { cachedEntries }
|
|
7403
|
+
})
|
|
6850
7404
|
);
|
|
6851
7405
|
return paragraphs;
|
|
6852
7406
|
}
|
|
@@ -7395,6 +7949,78 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
7395
7949
|
return map;
|
|
7396
7950
|
}
|
|
7397
7951
|
|
|
7952
|
+
// src/core/sectionOrdinals.ts
|
|
7953
|
+
function computeSectionOrdinals(sections) {
|
|
7954
|
+
let counter = 0;
|
|
7955
|
+
return sections.map((section, index) => {
|
|
7956
|
+
if (!section.belongsToUserSection) {
|
|
7957
|
+
if (section.isUserSection) counter++;
|
|
7958
|
+
return { closeBookmark: false };
|
|
7959
|
+
}
|
|
7960
|
+
const ordinal = section.isUserSection ? counter + 1 : counter;
|
|
7961
|
+
if (section.isUserSection) counter++;
|
|
7962
|
+
const next = sections[index + 1];
|
|
7963
|
+
const closeBookmark = !next || !next.belongsToUserSection || next.isUserSection;
|
|
7964
|
+
return { ordinal, closeBookmark };
|
|
7965
|
+
});
|
|
7966
|
+
}
|
|
7967
|
+
|
|
7968
|
+
// src/core/collectTocHeadings.ts
|
|
7969
|
+
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
7970
|
+
function normalizeEntryTitle(text) {
|
|
7971
|
+
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
7972
|
+
}
|
|
7973
|
+
function isContainer(name) {
|
|
7974
|
+
return getStandardComponent(name)?.hasChildren === true;
|
|
7975
|
+
}
|
|
7976
|
+
function isEnabled(component) {
|
|
7977
|
+
return !("enabled" in component && component.enabled === false);
|
|
7978
|
+
}
|
|
7979
|
+
function styleEntryKey(props) {
|
|
7980
|
+
const themeStyle = props.themeStyle;
|
|
7981
|
+
if (typeof themeStyle !== "string" || !themeStyle) return void 0;
|
|
7982
|
+
if (/^heading[1-6]$/i.test(themeStyle)) return void 0;
|
|
7983
|
+
if (["normal", "title", "subtitle"].includes(themeStyle.toLowerCase())) {
|
|
7984
|
+
return void 0;
|
|
7985
|
+
}
|
|
7986
|
+
return themeStyle;
|
|
7987
|
+
}
|
|
7988
|
+
function collectTocHeadings(sections) {
|
|
7989
|
+
const entries = [];
|
|
7990
|
+
const ordinals = computeSectionOrdinals(sections);
|
|
7991
|
+
sections.forEach((section, index) => {
|
|
7992
|
+
const ordinal = ordinals[index]?.ordinal;
|
|
7993
|
+
const sectionBookmarkId = ordinal ? globalSectionBookmarkRegistry.forLayoutSection(ordinal).id : void 0;
|
|
7994
|
+
const visit = (component) => {
|
|
7995
|
+
if (!isEnabled(component)) return;
|
|
7996
|
+
const props = component.props ?? {};
|
|
7997
|
+
if (component.name === "heading") {
|
|
7998
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
7999
|
+
const title = normalizeEntryTitle(text);
|
|
8000
|
+
if (title) {
|
|
8001
|
+
const level = typeof props.level === "number" ? props.level : 1;
|
|
8002
|
+
entries.push({ title, level, sectionBookmarkId });
|
|
8003
|
+
}
|
|
8004
|
+
return;
|
|
8005
|
+
}
|
|
8006
|
+
if (component.name === "paragraph") {
|
|
8007
|
+
const styleId = styleEntryKey(props);
|
|
8008
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
8009
|
+
const title = normalizeEntryTitle(text);
|
|
8010
|
+
if (styleId && title) {
|
|
8011
|
+
entries.push({ title, level: 1, styleId, sectionBookmarkId });
|
|
8012
|
+
}
|
|
8013
|
+
return;
|
|
8014
|
+
}
|
|
8015
|
+
if (!isContainer(component.name)) return;
|
|
8016
|
+
const children = component.children;
|
|
8017
|
+
if (Array.isArray(children)) children.forEach(visit);
|
|
8018
|
+
};
|
|
8019
|
+
section.components.forEach(visit);
|
|
8020
|
+
});
|
|
8021
|
+
return entries;
|
|
8022
|
+
}
|
|
8023
|
+
|
|
7398
8024
|
// src/core/render.ts
|
|
7399
8025
|
function getAlignment3(alignment) {
|
|
7400
8026
|
switch (alignment) {
|
|
@@ -7432,7 +8058,23 @@ async function renderDocument(structure, layout, options) {
|
|
|
7432
8058
|
() => globalBookmarkRegistry.runScoped(
|
|
7433
8059
|
() => globalRevisionIdRegistry.runScoped(
|
|
7434
8060
|
() => globalNumberingRegistry.runScoped(
|
|
7435
|
-
() =>
|
|
8061
|
+
() => globalSectionBookmarkRegistry.runScoped(
|
|
8062
|
+
() => (
|
|
8063
|
+
// Comment ids are a separate OOXML namespace from w:ins/w:del,
|
|
8064
|
+
// but they need the same per-render isolation: outside this nest
|
|
8065
|
+
// concurrent generations would interleave counters and an anchor
|
|
8066
|
+
// would point at another document's comment body.
|
|
8067
|
+
globalCommentRegistry.runScoped(
|
|
8068
|
+
() => (
|
|
8069
|
+
// Footnote ids are document-scoped too: a reference resolved
|
|
8070
|
+
// against another render's counter points at the wrong body.
|
|
8071
|
+
globalNoteRegistry.runScoped(
|
|
8072
|
+
() => renderDocumentScoped(structure, layout, options)
|
|
8073
|
+
)
|
|
8074
|
+
)
|
|
8075
|
+
)
|
|
8076
|
+
)
|
|
8077
|
+
)
|
|
7436
8078
|
)
|
|
7437
8079
|
)
|
|
7438
8080
|
)
|
|
@@ -7467,19 +8109,23 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7467
8109
|
error instanceof Error ? error.message : error
|
|
7468
8110
|
);
|
|
7469
8111
|
}
|
|
7470
|
-
|
|
8112
|
+
try {
|
|
8113
|
+
const tocHeadings = collectTocHeadings(layout.sections);
|
|
8114
|
+
if (tocHeadings.length > 0) {
|
|
8115
|
+
context.tocHeadings = tocHeadings;
|
|
8116
|
+
}
|
|
8117
|
+
} catch (error) {
|
|
8118
|
+
console.warn(
|
|
8119
|
+
"[core-docx] TOC entry collection failed; the TOC field will rely on the reader refreshing it:",
|
|
8120
|
+
error instanceof Error ? error.message : error
|
|
8121
|
+
);
|
|
8122
|
+
}
|
|
8123
|
+
const sectionOrdinals = computeSectionOrdinals(layout.sections);
|
|
7471
8124
|
let previousHeader = void 0;
|
|
7472
8125
|
let previousFooter = void 0;
|
|
7473
8126
|
for (let idx = 0; idx < layout.sections.length; idx++) {
|
|
7474
8127
|
const layoutSection = layout.sections[idx];
|
|
7475
|
-
|
|
7476
|
-
if (layoutSection.belongsToUserSection) {
|
|
7477
|
-
if (layoutSection.isUserSection) {
|
|
7478
|
-
sectionOrdinal = sectionBookmarkCounter + 1;
|
|
7479
|
-
} else {
|
|
7480
|
-
sectionOrdinal = sectionBookmarkCounter;
|
|
7481
|
-
}
|
|
7482
|
-
}
|
|
8128
|
+
const { ordinal: sectionOrdinal, closeBookmark } = sectionOrdinals[idx];
|
|
7483
8129
|
let headerToUse;
|
|
7484
8130
|
if (layoutSection.header === "linkToPrevious") {
|
|
7485
8131
|
headerToUse = previousHeader;
|
|
@@ -7503,13 +8149,6 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7503
8149
|
header: headerToUse,
|
|
7504
8150
|
footer: footerToUse
|
|
7505
8151
|
};
|
|
7506
|
-
let closeBookmark = false;
|
|
7507
|
-
if (layoutSection.belongsToUserSection && sectionOrdinal !== void 0) {
|
|
7508
|
-
const next = layout.sections[idx + 1];
|
|
7509
|
-
if (!next || !next.belongsToUserSection || next.isUserSection) {
|
|
7510
|
-
closeBookmark = true;
|
|
7511
|
-
}
|
|
7512
|
-
}
|
|
7513
8152
|
const rendered = await renderSection(
|
|
7514
8153
|
sectionToRender,
|
|
7515
8154
|
structure.theme,
|
|
@@ -7519,14 +8158,14 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7519
8158
|
closeBookmark,
|
|
7520
8159
|
options?.bypassCache === true
|
|
7521
8160
|
);
|
|
7522
|
-
if (layoutSection.isUserSection) {
|
|
7523
|
-
sectionBookmarkCounter++;
|
|
7524
|
-
}
|
|
7525
8161
|
if (rendered.children.length > 0) {
|
|
7526
8162
|
sections.push(rendered);
|
|
7527
8163
|
}
|
|
7528
8164
|
}
|
|
7529
8165
|
const numberingConfigs = globalNumberingRegistry.getAll();
|
|
8166
|
+
const comments = globalCommentRegistry.getAll();
|
|
8167
|
+
const footnotes = globalNoteRegistry.getFootnotes();
|
|
8168
|
+
const endnotes = globalNoteRegistry.getEndnotes();
|
|
7530
8169
|
return new Document({
|
|
7531
8170
|
styles: createWordStyles(structure.theme, structure.language),
|
|
7532
8171
|
sections,
|
|
@@ -7537,6 +8176,12 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7537
8176
|
// Word opens the document in review mode (further edits are tracked)
|
|
7538
8177
|
...structure.trackRevisions && { trackRevisions: true }
|
|
7539
8178
|
},
|
|
8179
|
+
// word/comments.xml, emitted only when something was actually commented
|
|
8180
|
+
...comments.length > 0 && { comments: { children: comments } },
|
|
8181
|
+
// word/footnotes.xml and word/endnotes.xml bodies, keyed by the id their
|
|
8182
|
+
// references carry
|
|
8183
|
+
...Object.keys(footnotes).length > 0 && { footnotes },
|
|
8184
|
+
...Object.keys(endnotes).length > 0 && { endnotes },
|
|
7540
8185
|
// Add numbering configurations if any lists were rendered
|
|
7541
8186
|
...numberingConfigs.length > 0 && {
|
|
7542
8187
|
numbering: {
|
|
@@ -7583,9 +8228,9 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7583
8228
|
let imageSource = resolveImageSource(imageComp.props);
|
|
7584
8229
|
if (!imageSource) {
|
|
7585
8230
|
elements.push(
|
|
7586
|
-
new
|
|
8231
|
+
new Paragraph9({
|
|
7587
8232
|
children: [
|
|
7588
|
-
new
|
|
8233
|
+
new TextRun9({
|
|
7589
8234
|
text: "[IMAGE: Missing path, base64, or svg property]",
|
|
7590
8235
|
font: getThemeFonts(theme).body.family,
|
|
7591
8236
|
size: 20,
|
|
@@ -7653,7 +8298,7 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7653
8298
|
...floatingOptions && { floating: floatingOptions }
|
|
7654
8299
|
});
|
|
7655
8300
|
elements.push(
|
|
7656
|
-
new
|
|
8301
|
+
new Paragraph9({
|
|
7657
8302
|
children: [imageRun],
|
|
7658
8303
|
alignment: imageComp.props.alignment ? getAlignment3(imageComp.props.alignment) : void 0,
|
|
7659
8304
|
style: "Normal"
|
|
@@ -7666,9 +8311,9 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7666
8311
|
error instanceof Error ? error.message : error
|
|
7667
8312
|
);
|
|
7668
8313
|
elements.push(
|
|
7669
|
-
new
|
|
8314
|
+
new Paragraph9({
|
|
7670
8315
|
children: [
|
|
7671
|
-
new
|
|
8316
|
+
new TextRun9({
|
|
7672
8317
|
text: `[IMAGE: ${sourcePreview}]`,
|
|
7673
8318
|
font: getThemeFonts(theme).body.family,
|
|
7674
8319
|
size: 20,
|
|
@@ -7698,8 +8343,9 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7698
8343
|
async function renderSection(section, theme, themeName, context, sectionOrdinal, closeBookmark, bypassCache = false) {
|
|
7699
8344
|
const elements = [];
|
|
7700
8345
|
const isFirstLayoutOfUserSection = section.isUserSection;
|
|
7701
|
-
const
|
|
7702
|
-
const
|
|
8346
|
+
const bookmark = section.belongsToUserSection && sectionOrdinal ? globalSectionBookmarkRegistry.forLayoutSection(sectionOrdinal) : void 0;
|
|
8347
|
+
const sharedLinkId = bookmark?.linkId;
|
|
8348
|
+
const sectionBookmarkId = bookmark?.id;
|
|
7703
8349
|
const sectionContext = {
|
|
7704
8350
|
...context,
|
|
7705
8351
|
section: {
|
|
@@ -7712,7 +8358,7 @@ async function renderSection(section, theme, themeName, context, sectionOrdinal,
|
|
|
7712
8358
|
};
|
|
7713
8359
|
if (sectionBookmarkId && isFirstLayoutOfUserSection && sharedLinkId !== void 0) {
|
|
7714
8360
|
elements.push(
|
|
7715
|
-
new
|
|
8361
|
+
new Paragraph9({
|
|
7716
8362
|
children: [new BookmarkStart2(sectionBookmarkId, sharedLinkId)],
|
|
7717
8363
|
spacing: {
|
|
7718
8364
|
before: 0,
|
|
@@ -7737,7 +8383,7 @@ async function renderSection(section, theme, themeName, context, sectionOrdinal,
|
|
|
7737
8383
|
}
|
|
7738
8384
|
if (closeBookmark && sharedLinkId !== void 0) {
|
|
7739
8385
|
elements.push(
|
|
7740
|
-
new
|
|
8386
|
+
new Paragraph9({
|
|
7741
8387
|
children: [new BookmarkEnd2(sharedLinkId)]
|
|
7742
8388
|
})
|
|
7743
8389
|
);
|
|
@@ -7891,9 +8537,9 @@ function fixFloatingImageIdsInBuffer(buffer) {
|
|
|
7891
8537
|
throw new Error("document.xml not found in DOCX");
|
|
7892
8538
|
}
|
|
7893
8539
|
let idCounter = 1;
|
|
7894
|
-
const documentXml = documentEntry.getData().toString("utf8").replace(
|
|
8540
|
+
const documentXml = documentEntry.getData().toString("utf8").replace(/(<wp:docPr\b[^>]*?\s)id="\d+"/g, (_match, prefix) => {
|
|
7895
8541
|
const newId = idCounter++;
|
|
7896
|
-
return
|
|
8542
|
+
return `${prefix}id="${newId}"`;
|
|
7897
8543
|
});
|
|
7898
8544
|
zip.updateFile(documentEntry, Buffer.from(documentXml, "utf8"));
|
|
7899
8545
|
return zip.toBuffer();
|
|
@@ -9273,6 +9919,7 @@ export {
|
|
|
9273
9919
|
UnknownPreservedComponentError,
|
|
9274
9920
|
cleanComponentProps,
|
|
9275
9921
|
clearComponentCache,
|
|
9922
|
+
componentBypassReason,
|
|
9276
9923
|
corporateTheme,
|
|
9277
9924
|
createComponent,
|
|
9278
9925
|
createDocumentGenerator,
|