@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
|
@@ -1128,7 +1128,7 @@ function getPageDimensions(size) {
|
|
|
1128
1128
|
if (typeof size === "string") {
|
|
1129
1129
|
return PAGE_SIZES[size];
|
|
1130
1130
|
}
|
|
1131
|
-
return size;
|
|
1131
|
+
return { width: size.width, height: size.height };
|
|
1132
1132
|
}
|
|
1133
1133
|
var resolveTableParagraphSpacing, PAGE_SIZES, getTableStyle, getDocumentMargins, getPageSetup;
|
|
1134
1134
|
var init_layoutUtils = __esm({
|
|
@@ -1145,10 +1145,10 @@ var init_layoutUtils = __esm({
|
|
|
1145
1145
|
};
|
|
1146
1146
|
};
|
|
1147
1147
|
PAGE_SIZES = {
|
|
1148
|
-
A4: { width: 11906, height: 16838 },
|
|
1149
|
-
A3: { width: 16838, height: 23811 },
|
|
1150
|
-
LETTER: { width: 12240, height: 15840 },
|
|
1151
|
-
LEGAL: { width: 12240, height: 20160 }
|
|
1148
|
+
A4: { width: 11906, height: 16838, code: 9 },
|
|
1149
|
+
A3: { width: 16838, height: 23811, code: 8 },
|
|
1150
|
+
LETTER: { width: 12240, height: 15840, code: 1 },
|
|
1151
|
+
LEGAL: { width: 12240, height: 20160, code: 5 }
|
|
1152
1152
|
};
|
|
1153
1153
|
getTableStyle = (theme, themeName) => {
|
|
1154
1154
|
const themeConfig = resolveTheme(theme, themeName);
|
|
@@ -1285,7 +1285,8 @@ var init_layoutUtils = __esm({
|
|
|
1285
1285
|
return {
|
|
1286
1286
|
size: {
|
|
1287
1287
|
width: dimensions.width,
|
|
1288
|
-
height: dimensions.height
|
|
1288
|
+
height: dimensions.height,
|
|
1289
|
+
...dimensions.code !== void 0 && { code: dimensions.code }
|
|
1289
1290
|
},
|
|
1290
1291
|
margin: {
|
|
1291
1292
|
top: margins.top ?? defaultMargins.top ?? 1440,
|
|
@@ -1297,10 +1298,11 @@ var init_layoutUtils = __esm({
|
|
|
1297
1298
|
}
|
|
1298
1299
|
return {
|
|
1299
1300
|
size: {
|
|
1300
|
-
width:
|
|
1301
|
-
//
|
|
1302
|
-
height:
|
|
1303
|
-
//
|
|
1301
|
+
width: PAGE_SIZES.A4.width,
|
|
1302
|
+
// 210mm in twips (A4)
|
|
1303
|
+
height: PAGE_SIZES.A4.height,
|
|
1304
|
+
// 297mm in twips (A4)
|
|
1305
|
+
code: PAGE_SIZES.A4.code
|
|
1304
1306
|
},
|
|
1305
1307
|
margin: {
|
|
1306
1308
|
top: defaultMargins.top ?? 1440,
|
|
@@ -2699,18 +2701,7 @@ function getColumnSettings(layout) {
|
|
|
2699
2701
|
function createSectionProperties(columnSettings, theme, themeName, sectionType, pageOverride) {
|
|
2700
2702
|
const basePageSetup = getPageSetup(theme, themeName);
|
|
2701
2703
|
const pageSetup = pageOverride ? {
|
|
2702
|
-
size:
|
|
2703
|
-
...basePageSetup.size,
|
|
2704
|
-
...pageOverride.size && typeof pageOverride.size === "object" ? pageOverride.size : pageOverride.size ? (() => {
|
|
2705
|
-
const sizes = {
|
|
2706
|
-
A4: { width: 11906, height: 16838 },
|
|
2707
|
-
A3: { width: 16838, height: 23811 },
|
|
2708
|
-
LETTER: { width: 12240, height: 15840 },
|
|
2709
|
-
LEGAL: { width: 12240, height: 20160 }
|
|
2710
|
-
};
|
|
2711
|
-
return sizes[pageOverride.size];
|
|
2712
|
-
})() : {}
|
|
2713
|
-
},
|
|
2704
|
+
size: pageOverride.size ? getPageDimensions(pageOverride.size) : basePageSetup.size,
|
|
2714
2705
|
margin: {
|
|
2715
2706
|
...basePageSetup.margin,
|
|
2716
2707
|
...pageOverride.margins || {}
|
|
@@ -2812,8 +2803,8 @@ Suggestion: ${suggestion}`
|
|
|
2812
2803
|
// src/core/render.ts
|
|
2813
2804
|
import {
|
|
2814
2805
|
Document,
|
|
2815
|
-
Paragraph as
|
|
2816
|
-
TextRun as
|
|
2806
|
+
Paragraph as Paragraph9,
|
|
2807
|
+
TextRun as TextRun9,
|
|
2817
2808
|
AlignmentType as AlignmentType5,
|
|
2818
2809
|
BookmarkStart as BookmarkStart2,
|
|
2819
2810
|
BookmarkEnd as BookmarkEnd2
|
|
@@ -3232,17 +3223,19 @@ function convertBorders(borders, theme) {
|
|
|
3232
3223
|
color: resolveColor(side.color, theme),
|
|
3233
3224
|
...side.space !== void 0 ? { space: side.space } : {}
|
|
3234
3225
|
} : void 0;
|
|
3235
|
-
const
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3226
|
+
const sides = [
|
|
3227
|
+
"top",
|
|
3228
|
+
"bottom",
|
|
3229
|
+
"left",
|
|
3230
|
+
"right",
|
|
3231
|
+
"between"
|
|
3232
|
+
];
|
|
3233
|
+
const converted = {};
|
|
3234
|
+
for (const side of sides) {
|
|
3235
|
+
const value = mapSide(borders[side]);
|
|
3236
|
+
if (value) converted[side] = value;
|
|
3237
|
+
}
|
|
3238
|
+
return Object.keys(converted).length > 0 ? converted : void 0;
|
|
3246
3239
|
}
|
|
3247
3240
|
function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
3248
3241
|
const theme = typeof themeNameOrObject === "string" ? getTheme(themeNameOrObject) || getTheme("minimal") : themeNameOrObject;
|
|
@@ -3611,7 +3604,7 @@ function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
|
3611
3604
|
}
|
|
3612
3605
|
const tocMatch = /^TOC([1-9])$/.exec(styleKey);
|
|
3613
3606
|
const customStyle = tocMatch ? styleValue : resolveStyleWithBaseStyle(theme, styleKey) || styleValue;
|
|
3614
|
-
const styleId = tocMatch ? `
|
|
3607
|
+
const styleId = tocMatch ? `TOC${tocMatch[1]}` : styleKey;
|
|
3615
3608
|
const styleName = tocMatch ? `TOC ${tocMatch[1]}` : styleKey.replace(/([A-Z])/g, " $1").trim();
|
|
3616
3609
|
const mapBaseStyleId = (base) => {
|
|
3617
3610
|
if (!base) return "Normal";
|
|
@@ -3683,8 +3676,8 @@ function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
|
3683
3676
|
continue;
|
|
3684
3677
|
}
|
|
3685
3678
|
paragraphStyles.push({
|
|
3686
|
-
//
|
|
3687
|
-
id: `
|
|
3679
|
+
// Canonical id and display name — see the styleId note above.
|
|
3680
|
+
id: `TOC${i}`,
|
|
3688
3681
|
name: `TOC ${i}`,
|
|
3689
3682
|
basedOn: "Normal",
|
|
3690
3683
|
next: "Normal",
|
|
@@ -3707,20 +3700,43 @@ function createWordStyles(themeNameOrObject = "minimal", language) {
|
|
|
3707
3700
|
}
|
|
3708
3701
|
});
|
|
3709
3702
|
}
|
|
3703
|
+
const noteStyle = resolveStyleWithBaseStyle(theme, "normal") || theme.styles?.normal;
|
|
3704
|
+
const bodyRun = convertRunProperties(
|
|
3705
|
+
mergeFontAndStyleProperties(resolveFontProperties(theme, noteStyle?.font), {
|
|
3706
|
+
size: noteStyle?.size,
|
|
3707
|
+
color: noteStyle?.color
|
|
3708
|
+
}),
|
|
3709
|
+
theme,
|
|
3710
|
+
theme.colors.text
|
|
3711
|
+
);
|
|
3712
|
+
const noteRun = {
|
|
3713
|
+
...bodyRun,
|
|
3714
|
+
...typeof bodyRun.size === "number" && {
|
|
3715
|
+
size: Math.max(12, bodyRun.size - 4)
|
|
3716
|
+
}
|
|
3717
|
+
};
|
|
3710
3718
|
return {
|
|
3711
3719
|
paragraphStyles,
|
|
3712
3720
|
// Cast needed due to docx typing
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3721
|
+
default: {
|
|
3722
|
+
// Document-default proofing language (w:docDefaults/w:rPrDefault). Runs
|
|
3723
|
+
// that don't set their own w:lang inherit this, so Word spell-checks the
|
|
3724
|
+
// whole document in the requested language unless a component overrides
|
|
3725
|
+
// it.
|
|
3726
|
+
...language && {
|
|
3718
3727
|
document: {
|
|
3719
3728
|
run: {
|
|
3720
3729
|
language: { value: language }
|
|
3721
3730
|
}
|
|
3722
3731
|
}
|
|
3723
|
-
}
|
|
3732
|
+
},
|
|
3733
|
+
// Run properties only: docx's own note paragraph defaults (single line
|
|
3734
|
+
// spacing, no space after) are already what a note wants, and an empty
|
|
3735
|
+
// spacing override would drop its line rule.
|
|
3736
|
+
footnoteText: { run: noteRun },
|
|
3737
|
+
footnoteReference: { run: { ...noteRun, superScript: true } },
|
|
3738
|
+
endnoteText: { run: noteRun },
|
|
3739
|
+
endnoteReference: { run: { ...noteRun, superScript: true } }
|
|
3724
3740
|
}
|
|
3725
3741
|
};
|
|
3726
3742
|
}
|
|
@@ -3842,7 +3858,15 @@ import {
|
|
|
3842
3858
|
} from "docx";
|
|
3843
3859
|
|
|
3844
3860
|
// src/utils/textParser.ts
|
|
3845
|
-
import {
|
|
3861
|
+
import {
|
|
3862
|
+
TextRun,
|
|
3863
|
+
ExternalHyperlink,
|
|
3864
|
+
InternalHyperlink,
|
|
3865
|
+
FootnoteReferenceRun,
|
|
3866
|
+
EndnoteReferenceRun,
|
|
3867
|
+
Tab
|
|
3868
|
+
} from "docx";
|
|
3869
|
+
var FOOTNOTE_MARKER_REGEX = /\[\^([^\]\s]+)\]/;
|
|
3846
3870
|
function escapeRegExp(s) {
|
|
3847
3871
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3848
3872
|
}
|
|
@@ -4019,8 +4043,8 @@ function buildTextRuns(text, commonProps, opts = {}) {
|
|
|
4019
4043
|
return runs;
|
|
4020
4044
|
}
|
|
4021
4045
|
function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
|
|
4022
|
-
|
|
4023
|
-
|
|
4046
|
+
const runs = (segment) => buildTextRuns(
|
|
4047
|
+
segment,
|
|
4024
4048
|
buildRunCommonProps(baseStyle, {
|
|
4025
4049
|
bold: overrideStyle?.bold,
|
|
4026
4050
|
italics: overrideStyle?.italics,
|
|
@@ -4028,6 +4052,34 @@ function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
|
|
|
4028
4052
|
}),
|
|
4029
4053
|
{ noProof: baseStyle.noProof, noProofWords: options.noProofWords }
|
|
4030
4054
|
);
|
|
4055
|
+
if (!options.noteRef) return runs(text);
|
|
4056
|
+
return splitNoteMarkers(text, options.noteRef, runs);
|
|
4057
|
+
}
|
|
4058
|
+
function splitNoteMarkers(text, noteRef, runs) {
|
|
4059
|
+
const regex = new RegExp(FOOTNOTE_MARKER_REGEX.source, "g");
|
|
4060
|
+
const out = [];
|
|
4061
|
+
let lastIndex = 0;
|
|
4062
|
+
let pending = "";
|
|
4063
|
+
let match;
|
|
4064
|
+
while ((match = regex.exec(text)) !== null) {
|
|
4065
|
+
const note = noteRef(match[1]);
|
|
4066
|
+
if (note === void 0) {
|
|
4067
|
+
pending += text.slice(lastIndex, regex.lastIndex);
|
|
4068
|
+
lastIndex = regex.lastIndex;
|
|
4069
|
+
continue;
|
|
4070
|
+
}
|
|
4071
|
+
const before = pending + text.slice(lastIndex, match.index);
|
|
4072
|
+
pending = "";
|
|
4073
|
+
if (before) out.push(...runs(before));
|
|
4074
|
+
out.push(
|
|
4075
|
+
note.endnote ? new EndnoteReferenceRun(note.id) : new FootnoteReferenceRun(note.id)
|
|
4076
|
+
);
|
|
4077
|
+
lastIndex = regex.lastIndex;
|
|
4078
|
+
}
|
|
4079
|
+
if (out.length === 0) return runs(text);
|
|
4080
|
+
const trailing = pending + text.slice(lastIndex);
|
|
4081
|
+
if (trailing) out.push(...runs(trailing));
|
|
4082
|
+
return out;
|
|
4031
4083
|
}
|
|
4032
4084
|
function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
4033
4085
|
const normalizedText = normalizeUnicodeText(text);
|
|
@@ -4283,6 +4335,52 @@ initializeBuiltinPlaceholders();
|
|
|
4283
4335
|
|
|
4284
4336
|
// src/utils/revisionUtils.ts
|
|
4285
4337
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
4338
|
+
|
|
4339
|
+
// src/utils/componentAnnotations.ts
|
|
4340
|
+
function isRecord(value) {
|
|
4341
|
+
return typeof value === "object" && value !== null;
|
|
4342
|
+
}
|
|
4343
|
+
function hasKey(value, key) {
|
|
4344
|
+
return isRecord(value) && Boolean(value[key]);
|
|
4345
|
+
}
|
|
4346
|
+
function cellHasAnnotation(cell, key) {
|
|
4347
|
+
if (!isRecord(cell)) return false;
|
|
4348
|
+
if (hasKey(cell, key)) return true;
|
|
4349
|
+
const content = cell.content;
|
|
4350
|
+
return isRecord(content) && componentHasAnnotation(content, key);
|
|
4351
|
+
}
|
|
4352
|
+
function componentHasAnnotation(component, key) {
|
|
4353
|
+
const props = component.props;
|
|
4354
|
+
if (props) {
|
|
4355
|
+
if (props[key]) return true;
|
|
4356
|
+
const items = props.items;
|
|
4357
|
+
if (Array.isArray(items) && items.some((item) => hasKey(item, key))) {
|
|
4358
|
+
return true;
|
|
4359
|
+
}
|
|
4360
|
+
const rows = props.rows;
|
|
4361
|
+
if (Array.isArray(rows) && rows.some((row) => hasKey(row, key))) {
|
|
4362
|
+
return true;
|
|
4363
|
+
}
|
|
4364
|
+
const columns = props.columns;
|
|
4365
|
+
if (Array.isArray(columns) && columns.some((column) => {
|
|
4366
|
+
if (!isRecord(column)) return false;
|
|
4367
|
+
if (cellHasAnnotation(column.header, key)) return true;
|
|
4368
|
+
const cells = column.cells;
|
|
4369
|
+
return Array.isArray(cells) && cells.some((cell) => cellHasAnnotation(cell, key));
|
|
4370
|
+
})) {
|
|
4371
|
+
return true;
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
const children = component.children;
|
|
4375
|
+
if (Array.isArray(children)) {
|
|
4376
|
+
return children.some(
|
|
4377
|
+
(child) => isRecord(child) && componentHasAnnotation(child, key)
|
|
4378
|
+
);
|
|
4379
|
+
}
|
|
4380
|
+
return false;
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
// src/utils/revisionUtils.ts
|
|
4286
4384
|
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
4287
4385
|
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
4288
4386
|
var RevisionIdRegistry = class {
|
|
@@ -4367,25 +4465,25 @@ function createRevisionRuns(revision, baseStyle) {
|
|
|
4367
4465
|
return runs;
|
|
4368
4466
|
}
|
|
4369
4467
|
function componentHasRevision(component) {
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4468
|
+
return componentHasAnnotation(component, "revision");
|
|
4469
|
+
}
|
|
4470
|
+
function createRevisionMark(mark) {
|
|
4471
|
+
const attributes = {
|
|
4472
|
+
id: globalRevisionIdRegistry.next(),
|
|
4473
|
+
author: mark.author || DEFAULT_REVISION_AUTHOR,
|
|
4474
|
+
date: mark.date || DEFAULT_REVISION_DATE
|
|
4475
|
+
};
|
|
4476
|
+
return mark.type === "insert" ? { insertion: attributes } : { deletion: attributes };
|
|
4477
|
+
}
|
|
4478
|
+
function createMarkedTextRuns(text, mark, baseStyle) {
|
|
4479
|
+
return createRevisionRuns(
|
|
4480
|
+
{
|
|
4481
|
+
author: mark.author,
|
|
4482
|
+
date: mark.date,
|
|
4483
|
+
segments: [{ type: mark.type, text }]
|
|
4484
|
+
},
|
|
4485
|
+
baseStyle
|
|
4486
|
+
);
|
|
4389
4487
|
}
|
|
4390
4488
|
|
|
4391
4489
|
// src/core/cached-render.ts
|
|
@@ -4446,14 +4544,23 @@ function initializeComponentCache(cache) {
|
|
|
4446
4544
|
cacheKeyGen = new CacheKeyGenerator();
|
|
4447
4545
|
}
|
|
4448
4546
|
}
|
|
4547
|
+
var DYNAMIC_CONTEXT_COMPONENTS = /* @__PURE__ */ new Set([
|
|
4548
|
+
"toc",
|
|
4549
|
+
"section",
|
|
4550
|
+
"visual",
|
|
4551
|
+
"heading",
|
|
4552
|
+
"list",
|
|
4553
|
+
"paragraph"
|
|
4554
|
+
]);
|
|
4555
|
+
function componentBypassReason(component) {
|
|
4556
|
+
if (componentHasRevision(component)) return "revision-ids";
|
|
4557
|
+
if (componentHasAnnotation(component, "comment")) return "comment-ids";
|
|
4558
|
+
if ("id" in component) return "bookmark-id";
|
|
4559
|
+
if (DYNAMIC_CONTEXT_COMPONENTS.has(component.name)) return "dynamic-context";
|
|
4560
|
+
return null;
|
|
4561
|
+
}
|
|
4449
4562
|
async function renderComponentWithCache(component, theme, themeName, context, bypassCache = false) {
|
|
4450
|
-
const bypassReason =
|
|
4451
|
-
component
|
|
4452
|
-
) ? "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
|
|
4453
|
-
// numbering in the current document scope. Cached paragraphs can
|
|
4454
|
-
// otherwise reference definitions that only existed in a previous
|
|
4455
|
-
// render.
|
|
4456
|
-
component.name === "list" || component.name === "paragraph" ? "dynamic-context" : null;
|
|
4563
|
+
const bypassReason = componentBypassReason(component);
|
|
4457
4564
|
if (!componentCache) {
|
|
4458
4565
|
initializeComponentCache();
|
|
4459
4566
|
}
|
|
@@ -4499,8 +4606,8 @@ async function renderComponentWithCache(component, theme, themeName, context, by
|
|
|
4499
4606
|
|
|
4500
4607
|
// src/core/content.ts
|
|
4501
4608
|
import {
|
|
4502
|
-
Paragraph,
|
|
4503
|
-
TextRun as
|
|
4609
|
+
Paragraph as Paragraph3,
|
|
4610
|
+
TextRun as TextRun7,
|
|
4504
4611
|
Table,
|
|
4505
4612
|
TableRow,
|
|
4506
4613
|
TableCell,
|
|
@@ -4595,6 +4702,252 @@ var BookmarkRegistry = class {
|
|
|
4595
4702
|
};
|
|
4596
4703
|
var globalBookmarkRegistry = new BookmarkRegistry();
|
|
4597
4704
|
|
|
4705
|
+
// src/utils/commentAnchors.ts
|
|
4706
|
+
import {
|
|
4707
|
+
CommentRangeEnd,
|
|
4708
|
+
CommentRangeStart,
|
|
4709
|
+
CommentReference,
|
|
4710
|
+
TextRun as TextRun5
|
|
4711
|
+
} from "docx";
|
|
4712
|
+
|
|
4713
|
+
// src/utils/commentRegistry.ts
|
|
4714
|
+
import { Paragraph, TextRun as TextRun4 } from "docx";
|
|
4715
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
|
|
4716
|
+
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
4717
|
+
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
4718
|
+
function createState() {
|
|
4719
|
+
return { counter: 0, comments: [], hasResolved: false };
|
|
4720
|
+
}
|
|
4721
|
+
function deriveInitials(author) {
|
|
4722
|
+
const initials = author.split(/[\s._-]+/).filter(Boolean).map((word) => word[0]).join("").toUpperCase().slice(0, 3);
|
|
4723
|
+
return initials || author.slice(0, 2).toUpperCase();
|
|
4724
|
+
}
|
|
4725
|
+
function bodyParagraphs(text) {
|
|
4726
|
+
return normalizeUnicodeText(text).split("\n").map((line) => new Paragraph({ children: [new TextRun4({ text: line })] }));
|
|
4727
|
+
}
|
|
4728
|
+
var CommentRegistry = class {
|
|
4729
|
+
fallback = createState();
|
|
4730
|
+
scopes = new AsyncLocalStorage4();
|
|
4731
|
+
get state() {
|
|
4732
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
4733
|
+
}
|
|
4734
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
4735
|
+
runScoped(callback) {
|
|
4736
|
+
return this.scopes.run(createState(), callback);
|
|
4737
|
+
}
|
|
4738
|
+
/**
|
|
4739
|
+
* Register a comment thread and return every id its anchors must carry — the
|
|
4740
|
+
* root first, then each reply in order. Word anchors every comment in a
|
|
4741
|
+
* thread over the same range, so all of them need a range and a reference.
|
|
4742
|
+
*
|
|
4743
|
+
* Ids are unique and monotonic within a render. `parentId` is derived here
|
|
4744
|
+
* rather than authored; docx turns it into the `w15:paraIdParent` links in
|
|
4745
|
+
* `word/commentsExtended.xml`.
|
|
4746
|
+
*/
|
|
4747
|
+
register(comment) {
|
|
4748
|
+
const state = this.state;
|
|
4749
|
+
const resolved = comment.resolved;
|
|
4750
|
+
const rootId = ++state.counter;
|
|
4751
|
+
state.comments.push({
|
|
4752
|
+
...this.toOptions(comment, rootId),
|
|
4753
|
+
...resolved !== void 0 && { resolved }
|
|
4754
|
+
});
|
|
4755
|
+
const ids = [rootId];
|
|
4756
|
+
for (const reply of comment.replies ?? []) {
|
|
4757
|
+
const replyId = ++state.counter;
|
|
4758
|
+
state.comments.push({
|
|
4759
|
+
...this.toOptions(reply, replyId),
|
|
4760
|
+
parentId: rootId,
|
|
4761
|
+
// Word resolves a thread as a whole, so the flag rides every member.
|
|
4762
|
+
...resolved !== void 0 && { resolved }
|
|
4763
|
+
});
|
|
4764
|
+
ids.push(replyId);
|
|
4765
|
+
}
|
|
4766
|
+
if (resolved !== void 0) state.hasResolved = true;
|
|
4767
|
+
return ids;
|
|
4768
|
+
}
|
|
4769
|
+
toOptions(comment, id) {
|
|
4770
|
+
const author = comment.author || DEFAULT_COMMENT_AUTHOR;
|
|
4771
|
+
return {
|
|
4772
|
+
id,
|
|
4773
|
+
author,
|
|
4774
|
+
initials: comment.initials || deriveInitials(author),
|
|
4775
|
+
date: new Date(comment.date || DEFAULT_COMMENT_DATE),
|
|
4776
|
+
children: bodyParagraphs(comment.text)
|
|
4777
|
+
};
|
|
4778
|
+
}
|
|
4779
|
+
/**
|
|
4780
|
+
* Every comment registered in this scope, in id order.
|
|
4781
|
+
*
|
|
4782
|
+
* docx writes `word/commentsExtended.xml` — and therefore any `w15:done` —
|
|
4783
|
+
* only when at least one comment in the document carries a `parentId`. A
|
|
4784
|
+
* document whose only resolved comment has no replies would silently lose
|
|
4785
|
+
* that state, so say so rather than dropping it quietly.
|
|
4786
|
+
*/
|
|
4787
|
+
getAll() {
|
|
4788
|
+
const state = this.state;
|
|
4789
|
+
if (state.hasResolved && !state.comments.some((comment) => comment.parentId !== void 0)) {
|
|
4790
|
+
console.warn(
|
|
4791
|
+
"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."
|
|
4792
|
+
);
|
|
4793
|
+
}
|
|
4794
|
+
return [...state.comments];
|
|
4795
|
+
}
|
|
4796
|
+
/** Test-only: reset the current scope's counter and bodies. */
|
|
4797
|
+
clear() {
|
|
4798
|
+
const state = this.scopes.getStore();
|
|
4799
|
+
if (state) {
|
|
4800
|
+
state.counter = 0;
|
|
4801
|
+
state.comments.length = 0;
|
|
4802
|
+
state.hasResolved = false;
|
|
4803
|
+
} else {
|
|
4804
|
+
this.fallback = createState();
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
};
|
|
4808
|
+
var globalCommentRegistry = new CommentRegistry();
|
|
4809
|
+
|
|
4810
|
+
// src/utils/commentAnchors.ts
|
|
4811
|
+
function openCommentRange(comment) {
|
|
4812
|
+
if (!comment) return void 0;
|
|
4813
|
+
const ids = globalCommentRegistry.register(comment);
|
|
4814
|
+
return { ids, start: ids.map((id) => new CommentRangeStart(id)) };
|
|
4815
|
+
}
|
|
4816
|
+
function closeCommentRange(ids) {
|
|
4817
|
+
return ids.flatMap((id) => [
|
|
4818
|
+
new CommentRangeEnd(id),
|
|
4819
|
+
new TextRun5({ children: [new CommentReference(id)] })
|
|
4820
|
+
]);
|
|
4821
|
+
}
|
|
4822
|
+
|
|
4823
|
+
// src/utils/noteRegistry.ts
|
|
4824
|
+
import { Paragraph as Paragraph2, TextRun as TextRun6 } from "docx";
|
|
4825
|
+
import { AsyncLocalStorage as AsyncLocalStorage5 } from "async_hooks";
|
|
4826
|
+
function createState2() {
|
|
4827
|
+
return {
|
|
4828
|
+
footnoteCounter: 0,
|
|
4829
|
+
endnoteCounter: 0,
|
|
4830
|
+
footnotes: {},
|
|
4831
|
+
endnotes: {}
|
|
4832
|
+
};
|
|
4833
|
+
}
|
|
4834
|
+
function bodyParagraphs2(text, style) {
|
|
4835
|
+
return normalizeUnicodeText(text).split("\n").map(
|
|
4836
|
+
(line) => new Paragraph2({
|
|
4837
|
+
style,
|
|
4838
|
+
children: [new TextRun6({ text: line })]
|
|
4839
|
+
})
|
|
4840
|
+
);
|
|
4841
|
+
}
|
|
4842
|
+
var NoteRegistry = class {
|
|
4843
|
+
fallback = createState2();
|
|
4844
|
+
scopes = new AsyncLocalStorage5();
|
|
4845
|
+
get state() {
|
|
4846
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
4847
|
+
}
|
|
4848
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
4849
|
+
runScoped(callback) {
|
|
4850
|
+
return this.scopes.run(createState2(), callback);
|
|
4851
|
+
}
|
|
4852
|
+
/**
|
|
4853
|
+
* Register a footnote body and return the id its reference must use. Ids are
|
|
4854
|
+
* unique and monotonic within a render.
|
|
4855
|
+
*/
|
|
4856
|
+
registerFootnote(text) {
|
|
4857
|
+
const state = this.state;
|
|
4858
|
+
const id = ++state.footnoteCounter;
|
|
4859
|
+
state.footnotes[String(id)] = {
|
|
4860
|
+
children: bodyParagraphs2(text, "FootnoteText")
|
|
4861
|
+
};
|
|
4862
|
+
return id;
|
|
4863
|
+
}
|
|
4864
|
+
/** Register an endnote body and return the id its reference must use. */
|
|
4865
|
+
registerEndnote(text) {
|
|
4866
|
+
const state = this.state;
|
|
4867
|
+
const id = ++state.endnoteCounter;
|
|
4868
|
+
state.endnotes[String(id)] = {
|
|
4869
|
+
children: bodyParagraphs2(text, "EndnoteText")
|
|
4870
|
+
};
|
|
4871
|
+
return id;
|
|
4872
|
+
}
|
|
4873
|
+
/** Every footnote registered in this scope, keyed by id. */
|
|
4874
|
+
getFootnotes() {
|
|
4875
|
+
return { ...this.state.footnotes };
|
|
4876
|
+
}
|
|
4877
|
+
/** Every endnote registered in this scope, keyed by id. */
|
|
4878
|
+
getEndnotes() {
|
|
4879
|
+
return { ...this.state.endnotes };
|
|
4880
|
+
}
|
|
4881
|
+
/** Test-only: reset the current scope's counters and bodies. */
|
|
4882
|
+
clear() {
|
|
4883
|
+
const state = this.scopes.getStore();
|
|
4884
|
+
if (state) {
|
|
4885
|
+
state.footnoteCounter = 0;
|
|
4886
|
+
state.endnoteCounter = 0;
|
|
4887
|
+
for (const key of Object.keys(state.footnotes)) {
|
|
4888
|
+
delete state.footnotes[key];
|
|
4889
|
+
}
|
|
4890
|
+
for (const key of Object.keys(state.endnotes)) {
|
|
4891
|
+
delete state.endnotes[key];
|
|
4892
|
+
}
|
|
4893
|
+
} else {
|
|
4894
|
+
this.fallback = createState2();
|
|
4895
|
+
}
|
|
4896
|
+
}
|
|
4897
|
+
};
|
|
4898
|
+
var globalNoteRegistry = new NoteRegistry();
|
|
4899
|
+
|
|
4900
|
+
// src/utils/noteResolver.ts
|
|
4901
|
+
function collectDeclared(footnotes, endnotes) {
|
|
4902
|
+
const declared = /* @__PURE__ */ new Map();
|
|
4903
|
+
const declare = (note, endnote) => {
|
|
4904
|
+
const existing = declared.get(note.id);
|
|
4905
|
+
if (existing) {
|
|
4906
|
+
console.warn(
|
|
4907
|
+
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.`
|
|
4908
|
+
);
|
|
4909
|
+
return;
|
|
4910
|
+
}
|
|
4911
|
+
declared.set(note.id, { text: note.text, endnote });
|
|
4912
|
+
};
|
|
4913
|
+
for (const note of footnotes ?? []) declare(note, false);
|
|
4914
|
+
for (const note of endnotes ?? []) declare(note, true);
|
|
4915
|
+
return declared;
|
|
4916
|
+
}
|
|
4917
|
+
function createNoteResolver(footnotes, endnotes) {
|
|
4918
|
+
const declared = collectDeclared(footnotes, endnotes);
|
|
4919
|
+
if (declared.size === 0) return void 0;
|
|
4920
|
+
const registered = /* @__PURE__ */ new Map();
|
|
4921
|
+
return {
|
|
4922
|
+
resolve(id) {
|
|
4923
|
+
const existing = registered.get(id);
|
|
4924
|
+
if (existing !== void 0) return existing;
|
|
4925
|
+
const note = declared.get(id);
|
|
4926
|
+
if (note === void 0) {
|
|
4927
|
+
console.warn(
|
|
4928
|
+
`Note marker "[^${id}]" has no matching entry in this paragraph's footnotes or endnotes (declared: ${[...declared.keys()].join(", ")}). Rendering the marker as literal text.`
|
|
4929
|
+
);
|
|
4930
|
+
return void 0;
|
|
4931
|
+
}
|
|
4932
|
+
const resolved = {
|
|
4933
|
+
id: note.endnote ? globalNoteRegistry.registerEndnote(note.text) : globalNoteRegistry.registerFootnote(note.text),
|
|
4934
|
+
endnote: note.endnote
|
|
4935
|
+
};
|
|
4936
|
+
registered.set(id, resolved);
|
|
4937
|
+
return resolved;
|
|
4938
|
+
},
|
|
4939
|
+
reportUnemitted(text) {
|
|
4940
|
+
for (const [id, note] of declared) {
|
|
4941
|
+
if (registered.has(id)) continue;
|
|
4942
|
+
const kind = note.endnote ? "Endnote" : "Footnote";
|
|
4943
|
+
console.warn(
|
|
4944
|
+
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.`
|
|
4945
|
+
);
|
|
4946
|
+
}
|
|
4947
|
+
}
|
|
4948
|
+
};
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4598
4951
|
// src/core/content.ts
|
|
4599
4952
|
init_styleHelpers();
|
|
4600
4953
|
import { synthesizeFamilyName } from "@json-to-office/shared";
|
|
@@ -4618,6 +4971,20 @@ function resolveNoProofWords(theme, optionWords) {
|
|
|
4618
4971
|
const merged = [...themeWords || [], ...optionWords || []];
|
|
4619
4972
|
return merged.length > 0 ? Array.from(new Set(merged)) : void 0;
|
|
4620
4973
|
}
|
|
4974
|
+
function reportNotesUnsupportedInRevision(footnotes, endnotes, revision) {
|
|
4975
|
+
const declared = [...footnotes ?? [], ...endnotes ?? []];
|
|
4976
|
+
if (declared.length === 0) return;
|
|
4977
|
+
const text = revision.segments.map((segment) => segment.text).join("");
|
|
4978
|
+
const referenced = declared.filter((note) => text.includes(`[^${note.id}]`));
|
|
4979
|
+
console.warn(
|
|
4980
|
+
`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."
|
|
4981
|
+
);
|
|
4982
|
+
}
|
|
4983
|
+
function wrapInComment(children, comment) {
|
|
4984
|
+
const anchor = openCommentRange(comment);
|
|
4985
|
+
if (!anchor) return children;
|
|
4986
|
+
return [...anchor.start, ...children, ...closeCommentRange(anchor.ids)];
|
|
4987
|
+
}
|
|
4621
4988
|
function createText(content, theme, themeName, options = {}) {
|
|
4622
4989
|
const normalizedContent = normalizeUnicodeText(content);
|
|
4623
4990
|
const style = options.style || "Normal";
|
|
@@ -4637,6 +5004,10 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4637
5004
|
if (options.columnBreak) {
|
|
4638
5005
|
children.push(new ColumnBreak());
|
|
4639
5006
|
}
|
|
5007
|
+
const commentAnchor = openCommentRange(options.comment);
|
|
5008
|
+
if (commentAnchor) {
|
|
5009
|
+
children.push(...commentAnchor.start);
|
|
5010
|
+
}
|
|
4640
5011
|
const hasWeightRequest = options.fontWeight != null || options.bold === true;
|
|
4641
5012
|
const effectiveFamily = options.fontFamily ?? (hasWeightRequest ? resolveFontFamily(theme, "body") : void 0);
|
|
4642
5013
|
const weighted = applyFontWeightAlias({
|
|
@@ -4673,6 +5044,11 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4673
5044
|
...options.noProof !== void 0 && { noProof: options.noProof }
|
|
4674
5045
|
};
|
|
4675
5046
|
if (options.revision) {
|
|
5047
|
+
reportNotesUnsupportedInRevision(
|
|
5048
|
+
options.footnotes,
|
|
5049
|
+
options.endnotes,
|
|
5050
|
+
options.revision
|
|
5051
|
+
);
|
|
4676
5052
|
const revisionRuns = createRevisionRuns(options.revision, baseTextStyle);
|
|
4677
5053
|
if (options.bookmarkId) {
|
|
4678
5054
|
globalBookmarkRegistry.register(
|
|
@@ -4690,11 +5066,17 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4690
5066
|
children.push(...revisionRuns);
|
|
4691
5067
|
}
|
|
4692
5068
|
} else {
|
|
5069
|
+
const noteResolver = createNoteResolver(
|
|
5070
|
+
options.footnotes,
|
|
5071
|
+
options.endnotes
|
|
5072
|
+
);
|
|
4693
5073
|
const textRuns = parseTextWithDecorators(normalizedContent, baseTextStyle, {
|
|
4694
5074
|
boldColor: options.boldColor ? resolveColor(options.boldColor, theme) : void 0,
|
|
4695
5075
|
enableHyperlinks: true,
|
|
4696
|
-
noProofWords: resolveNoProofWords(theme, options.noProofWords)
|
|
5076
|
+
noProofWords: resolveNoProofWords(theme, options.noProofWords),
|
|
5077
|
+
noteRef: noteResolver?.resolve
|
|
4697
5078
|
});
|
|
5079
|
+
noteResolver?.reportUnemitted(normalizedContent);
|
|
4698
5080
|
if (options.bookmarkId) {
|
|
4699
5081
|
globalBookmarkRegistry.register(
|
|
4700
5082
|
options.bookmarkId,
|
|
@@ -4711,9 +5093,12 @@ function createText(content, theme, themeName, options = {}) {
|
|
|
4711
5093
|
children.push(...textRuns);
|
|
4712
5094
|
}
|
|
4713
5095
|
}
|
|
5096
|
+
if (commentAnchor) {
|
|
5097
|
+
children.push(...closeCommentRange(commentAnchor.ids));
|
|
5098
|
+
}
|
|
4714
5099
|
const isFloating = !!options.floating;
|
|
4715
5100
|
const frameOptions = isFloating && options.floating ? mapFrameOptions(options.floating, theme, themeName) : void 0;
|
|
4716
|
-
return new
|
|
5101
|
+
return new Paragraph3({
|
|
4717
5102
|
children,
|
|
4718
5103
|
style,
|
|
4719
5104
|
alignment: options.alignment ? getAlignment(options.alignment) : void 0,
|
|
@@ -4808,6 +5193,10 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4808
5193
|
if (options.columnBreak) {
|
|
4809
5194
|
children.push(new ColumnBreak());
|
|
4810
5195
|
}
|
|
5196
|
+
const commentAnchor = openCommentRange(options.comment);
|
|
5197
|
+
if (commentAnchor) {
|
|
5198
|
+
children.push(...commentAnchor.start);
|
|
5199
|
+
}
|
|
4811
5200
|
const hasDecorators = /(\*\*\*|___|(\*\*|__)|(\*|_))/.test(normalizedText);
|
|
4812
5201
|
const headingHasWeightRequest = options.fontWeight != null || options.bold === true;
|
|
4813
5202
|
const headingEffectiveFamily = options.fontFamily ?? (headingHasWeightRequest ? resolveFontFamily(theme, "heading") : void 0);
|
|
@@ -4844,7 +5233,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4844
5233
|
const headingNoProofWords = resolveNoProofWords(theme, options.noProofWords);
|
|
4845
5234
|
const makeHeadingRuns = (value) => splitByNoProofWords(
|
|
4846
5235
|
value,
|
|
4847
|
-
(segment, matched) => new
|
|
5236
|
+
(segment, matched) => new TextRun7({
|
|
4848
5237
|
text: segment,
|
|
4849
5238
|
...baseTextStyle,
|
|
4850
5239
|
...matched && { noProof: true }
|
|
@@ -4903,7 +5292,10 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4903
5292
|
children.push(...makeHeadingRuns(normalizedText));
|
|
4904
5293
|
}
|
|
4905
5294
|
}
|
|
4906
|
-
|
|
5295
|
+
if (commentAnchor) {
|
|
5296
|
+
children.push(...closeCommentRange(commentAnchor.ids));
|
|
5297
|
+
}
|
|
5298
|
+
return new Paragraph3({
|
|
4907
5299
|
children,
|
|
4908
5300
|
style: styleId,
|
|
4909
5301
|
alignment: getAlignment(options.alignment || "left"),
|
|
@@ -4970,7 +5362,7 @@ async function createImage(path3, theme, themeName, options = {}) {
|
|
|
4970
5362
|
spacing.after = pointsToTwips(options.spacing.after);
|
|
4971
5363
|
}
|
|
4972
5364
|
elements.push(
|
|
4973
|
-
new
|
|
5365
|
+
new Paragraph3({
|
|
4974
5366
|
children: [imageRun],
|
|
4975
5367
|
alignment,
|
|
4976
5368
|
...Object.keys(spacing).length > 0 && { spacing },
|
|
@@ -4987,7 +5379,7 @@ async function createImage(path3, theme, themeName, options = {}) {
|
|
|
4987
5379
|
const hasDecorators = /(\*\*\*|___|(\*\*|__)|(\*|_))/.test(options.caption);
|
|
4988
5380
|
if (!hasDecorators) {
|
|
4989
5381
|
elements.push(
|
|
4990
|
-
new
|
|
5382
|
+
new Paragraph3({
|
|
4991
5383
|
text: normalizeUnicodeText(options.caption),
|
|
4992
5384
|
style: "Normal",
|
|
4993
5385
|
alignment: AlignmentType2.LEFT
|
|
@@ -5003,7 +5395,7 @@ async function createImage(path3, theme, themeName, options = {}) {
|
|
|
5003
5395
|
}
|
|
5004
5396
|
);
|
|
5005
5397
|
elements.push(
|
|
5006
|
-
new
|
|
5398
|
+
new Paragraph3({
|
|
5007
5399
|
children: textRuns,
|
|
5008
5400
|
style: "Normal",
|
|
5009
5401
|
// Use Normal style for consistent font inheritance
|
|
@@ -5020,13 +5412,13 @@ function createStatistic(data, options = {}) {
|
|
|
5020
5412
|
const normalizedNumber = normalizeUnicodeText(data.number);
|
|
5021
5413
|
const normalizedDescription = normalizeUnicodeText(data.description);
|
|
5022
5414
|
return [
|
|
5023
|
-
new
|
|
5415
|
+
new Paragraph3({
|
|
5024
5416
|
text: normalizedNumber,
|
|
5025
5417
|
style: "StatisticNumber",
|
|
5026
5418
|
alignment,
|
|
5027
5419
|
spacing: options.spacing
|
|
5028
5420
|
}),
|
|
5029
|
-
new
|
|
5421
|
+
new Paragraph3({
|
|
5030
5422
|
text: normalizedDescription,
|
|
5031
5423
|
style: "StatisticDescription",
|
|
5032
5424
|
alignment
|
|
@@ -5038,6 +5430,15 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
5038
5430
|
return [];
|
|
5039
5431
|
}
|
|
5040
5432
|
const paragraphs = [];
|
|
5433
|
+
const noteResolver = createNoteResolver(options.footnotes, options.endnotes);
|
|
5434
|
+
const rendersAt = items.map((item) => {
|
|
5435
|
+
const text = typeof item === "string" ? item : item.text;
|
|
5436
|
+
const revision = typeof item === "object" ? item.revision : void 0;
|
|
5437
|
+
return Boolean(text.trim()) || Boolean(revision);
|
|
5438
|
+
});
|
|
5439
|
+
const firstRendered = rendersAt.indexOf(true);
|
|
5440
|
+
const lastRendered = rendersAt.lastIndexOf(true);
|
|
5441
|
+
const commentAnchor = firstRendered === -1 ? void 0 : openCommentRange(options.comment);
|
|
5041
5442
|
items.forEach((item, index) => {
|
|
5042
5443
|
const itemText = typeof item === "string" ? item : item.text;
|
|
5043
5444
|
const itemLevel = typeof item === "object" ? item.level || 0 : 0;
|
|
@@ -5049,7 +5450,8 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
5049
5450
|
itemText,
|
|
5050
5451
|
{},
|
|
5051
5452
|
{
|
|
5052
|
-
enableHyperlinks: true
|
|
5453
|
+
enableHyperlinks: true,
|
|
5454
|
+
noteRef: noteResolver?.resolve
|
|
5053
5455
|
}
|
|
5054
5456
|
);
|
|
5055
5457
|
const spacing = {};
|
|
@@ -5061,10 +5463,15 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
5061
5463
|
} else if (options.spacing?.item) {
|
|
5062
5464
|
spacing.after = pointsToTwips(options.spacing.item);
|
|
5063
5465
|
}
|
|
5064
|
-
const
|
|
5466
|
+
const paragraphChildren = [
|
|
5467
|
+
...commentAnchor && index === firstRendered ? commentAnchor.start : [],
|
|
5468
|
+
...textRuns,
|
|
5469
|
+
...commentAnchor && index === lastRendered ? closeCommentRange(commentAnchor.ids) : []
|
|
5470
|
+
];
|
|
5471
|
+
const paragraph = new Paragraph3({
|
|
5065
5472
|
style: "Normal",
|
|
5066
5473
|
// Apply Normal style for font inheritance
|
|
5067
|
-
children:
|
|
5474
|
+
children: paragraphChildren,
|
|
5068
5475
|
alignment: options.alignment ? getAlignment(options.alignment) : AlignmentType2.LEFT,
|
|
5069
5476
|
spacing,
|
|
5070
5477
|
// Use proper docx numbering instead of prepending text
|
|
@@ -5077,6 +5484,9 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
5077
5484
|
});
|
|
5078
5485
|
paragraphs.push(paragraph);
|
|
5079
5486
|
});
|
|
5487
|
+
noteResolver?.reportUnemitted(
|
|
5488
|
+
items.map((item) => typeof item === "string" ? item : item.text).join("\n")
|
|
5489
|
+
);
|
|
5080
5490
|
return paragraphs;
|
|
5081
5491
|
}
|
|
5082
5492
|
async function createTable(columns, tableConfig, theme, themeName, _options = {}) {
|
|
@@ -5410,10 +5820,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5410
5820
|
return false;
|
|
5411
5821
|
}
|
|
5412
5822
|
};
|
|
5413
|
-
const processCellContent = async (cell, cellDefaults, baseCellStyle) => {
|
|
5823
|
+
const processCellContent = async (cell, cellDefaults, baseCellStyle, comment, revision, rowMark) => {
|
|
5414
5824
|
let cellChildren = [];
|
|
5415
5825
|
if (!cell) {
|
|
5416
|
-
return cellChildren;
|
|
5826
|
+
return wrapInComment(cellChildren, comment);
|
|
5417
5827
|
}
|
|
5418
5828
|
const cellWeighted = applyFontWeightAlias({
|
|
5419
5829
|
fontFamily: cellDefaults.font?.family || baseCellStyle.font,
|
|
@@ -5457,11 +5867,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5457
5867
|
color: resolveColor(paragraphFont.color, theme)
|
|
5458
5868
|
}
|
|
5459
5869
|
};
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
);
|
|
5870
|
+
const paragraphRevision = revision ?? textComp.props.revision;
|
|
5871
|
+
cellChildren = paragraphRevision ? createRevisionRuns(paragraphRevision, paragraphStyle) : rowMark ? createMarkedTextRuns(textComp.props.text, rowMark, paragraphStyle) : parseTextWithDecorators(textComp.props.text, paragraphStyle, {
|
|
5872
|
+
enableHyperlinks: true
|
|
5873
|
+
});
|
|
5465
5874
|
} else if (isImageComponent(cell)) {
|
|
5466
5875
|
const imageComp = cell;
|
|
5467
5876
|
try {
|
|
@@ -5496,7 +5905,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5496
5905
|
} catch (error) {
|
|
5497
5906
|
const imageSource = imageComp.props.svg?.trim() ? "inline-svg" : imageComp.props.base64 || imageComp.props.path || "unknown";
|
|
5498
5907
|
cellChildren = [
|
|
5499
|
-
new
|
|
5908
|
+
new TextRun7({
|
|
5500
5909
|
text: `[IMAGE: ${imageSource.substring(0, 50)}${imageSource.length > 50 ? "..." : ""}]`,
|
|
5501
5910
|
font: mergedStyle.font,
|
|
5502
5911
|
size: mergedStyle.size,
|
|
@@ -5506,7 +5915,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5506
5915
|
}
|
|
5507
5916
|
} else {
|
|
5508
5917
|
cellChildren = [
|
|
5509
|
-
new
|
|
5918
|
+
new TextRun7({
|
|
5510
5919
|
text: `[Unsupported component type: ${cell.name}]`,
|
|
5511
5920
|
font: mergedStyle.font,
|
|
5512
5921
|
size: mergedStyle.size,
|
|
@@ -5515,11 +5924,11 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5515
5924
|
];
|
|
5516
5925
|
}
|
|
5517
5926
|
} else {
|
|
5518
|
-
cellChildren = parseTextWithDecorators(cell, mergedStyle, {
|
|
5927
|
+
cellChildren = revision ? createRevisionRuns(revision, mergedStyle) : rowMark ? createMarkedTextRuns(cell, rowMark, mergedStyle) : parseTextWithDecorators(cell, mergedStyle, {
|
|
5519
5928
|
enableHyperlinks: true
|
|
5520
5929
|
});
|
|
5521
5930
|
}
|
|
5522
|
-
return cellChildren;
|
|
5931
|
+
return wrapInComment(cellChildren, comment);
|
|
5523
5932
|
};
|
|
5524
5933
|
const numColumns = columns.length;
|
|
5525
5934
|
const headerHeight = columns.reduce(
|
|
@@ -5576,7 +5985,9 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5576
5985
|
const cellChildren = await processCellContent(
|
|
5577
5986
|
headerCell?.content,
|
|
5578
5987
|
mergedDefaults,
|
|
5579
|
-
tableStyle.tableHeader
|
|
5988
|
+
tableStyle.tableHeader,
|
|
5989
|
+
headerCell?.comment,
|
|
5990
|
+
headerCell?.revision
|
|
5580
5991
|
);
|
|
5581
5992
|
const horizontalAlignment = mergedDefaults.horizontalAlignment;
|
|
5582
5993
|
const verticalAlignment = getVerticalAlignment(
|
|
@@ -5584,7 +5995,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5584
5995
|
);
|
|
5585
5996
|
return new TableCell({
|
|
5586
5997
|
children: [
|
|
5587
|
-
new
|
|
5998
|
+
new Paragraph3({
|
|
5588
5999
|
...tableConfig.keepInOnePage && { keepNext: true },
|
|
5589
6000
|
spacing: tableStyle.headerParagraph,
|
|
5590
6001
|
alignment: getAlignment(horizontalAlignment),
|
|
@@ -5627,6 +6038,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5627
6038
|
const dataRows = await Promise.all(
|
|
5628
6039
|
Array.from({ length: numRows }, async (_, rowIndex) => {
|
|
5629
6040
|
const isLastRow = rowIndex === numRows - 1;
|
|
6041
|
+
const rowProps = tableConfig.rows?.[rowIndex];
|
|
6042
|
+
const rowRevision = rowProps?.revision;
|
|
6043
|
+
const rowRevisionAttributes = rowRevision ? createRevisionMark(rowRevision) : void 0;
|
|
6044
|
+
const paragraphMarks = rowRevision ? columns.map(() => ({ run: createRevisionMark(rowRevision) })) : void 0;
|
|
5630
6045
|
const rowHeight = columns.reduce(
|
|
5631
6046
|
(maxHeight, column, colIndex) => {
|
|
5632
6047
|
const cell = column.cells?.[rowIndex];
|
|
@@ -5656,6 +6071,14 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5656
6071
|
);
|
|
5657
6072
|
return new TableRow({
|
|
5658
6073
|
height: rowHeight !== void 0 ? { value: rowHeight * 20, rule: "atLeast" } : void 0,
|
|
6074
|
+
...rowProps?.cantSplit !== void 0 && {
|
|
6075
|
+
cantSplit: rowProps.cantSplit
|
|
6076
|
+
},
|
|
6077
|
+
...rowProps?.tableHeader !== void 0 && {
|
|
6078
|
+
tableHeader: rowProps.tableHeader
|
|
6079
|
+
},
|
|
6080
|
+
// w:trPr/w:ins | w:del — the row itself was inserted or deleted.
|
|
6081
|
+
...rowRevisionAttributes,
|
|
5659
6082
|
children: await Promise.all(
|
|
5660
6083
|
columns.map(async (column, colIndex) => {
|
|
5661
6084
|
const cell = column.cells?.[rowIndex];
|
|
@@ -5679,10 +6102,11 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5679
6102
|
);
|
|
5680
6103
|
return new TableCell({
|
|
5681
6104
|
children: [
|
|
5682
|
-
new
|
|
6105
|
+
new Paragraph3({
|
|
5683
6106
|
...tableConfig.keepInOnePage && !isLastRow || isLastRow && tableConfig.keepNext ? { keepNext: true } : {},
|
|
5684
6107
|
spacing: tableStyle.cellParagraph,
|
|
5685
6108
|
alignment: AlignmentType2.LEFT,
|
|
6109
|
+
...paragraphMarks?.[colIndex],
|
|
5686
6110
|
children: []
|
|
5687
6111
|
})
|
|
5688
6112
|
],
|
|
@@ -5747,7 +6171,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5747
6171
|
const cellChildren = await processCellContent(
|
|
5748
6172
|
cell.content,
|
|
5749
6173
|
mergedDefaults,
|
|
5750
|
-
tableStyle.tableCell
|
|
6174
|
+
tableStyle.tableCell,
|
|
6175
|
+
cell.comment,
|
|
6176
|
+
cell.revision,
|
|
6177
|
+
rowRevision
|
|
5751
6178
|
);
|
|
5752
6179
|
const horizontalAlignment = mergedDefaults.horizontalAlignment;
|
|
5753
6180
|
const verticalAlignment = getVerticalAlignment(
|
|
@@ -5755,10 +6182,11 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5755
6182
|
);
|
|
5756
6183
|
return new TableCell({
|
|
5757
6184
|
children: [
|
|
5758
|
-
new
|
|
6185
|
+
new Paragraph3({
|
|
5759
6186
|
...tableConfig.keepInOnePage && !isLastRow || isLastRow && tableConfig.keepNext ? { keepNext: true } : {},
|
|
5760
6187
|
spacing: tableStyle.cellParagraph,
|
|
5761
6188
|
alignment: getAlignment(horizontalAlignment),
|
|
6189
|
+
...paragraphMarks?.[colIndex],
|
|
5762
6190
|
children: cellChildren
|
|
5763
6191
|
})
|
|
5764
6192
|
],
|
|
@@ -5917,7 +6345,9 @@ function renderHeadingComponent(component, theme, themeName) {
|
|
|
5917
6345
|
// Bookmark ID for internal linking
|
|
5918
6346
|
bookmarkId,
|
|
5919
6347
|
// Tracked-change segments (rendered as native Word revisions)
|
|
5920
|
-
revision: config.revision
|
|
6348
|
+
revision: config.revision,
|
|
6349
|
+
// Review comment anchored to this heading's text
|
|
6350
|
+
comment: config.comment
|
|
5921
6351
|
}
|
|
5922
6352
|
);
|
|
5923
6353
|
return [header];
|
|
@@ -5925,7 +6355,7 @@ function renderHeadingComponent(component, theme, themeName) {
|
|
|
5925
6355
|
|
|
5926
6356
|
// src/utils/numberingConfig.ts
|
|
5927
6357
|
import { AlignmentType as AlignmentType3, convertInchesToTwip, LevelFormat } from "docx";
|
|
5928
|
-
import { AsyncLocalStorage as
|
|
6358
|
+
import { AsyncLocalStorage as AsyncLocalStorage6 } from "async_hooks";
|
|
5929
6359
|
var LEVEL_FORMAT_MAP = {
|
|
5930
6360
|
decimal: LevelFormat.DECIMAL,
|
|
5931
6361
|
upperRoman: LevelFormat.UPPER_ROMAN,
|
|
@@ -6003,6 +6433,21 @@ function getAlignment2(alignment) {
|
|
|
6003
6433
|
if (!alignment) return AlignmentType3.LEFT;
|
|
6004
6434
|
return ALIGNMENT_MAP[alignment] || AlignmentType3.LEFT;
|
|
6005
6435
|
}
|
|
6436
|
+
function createMarkerRunStyle(font) {
|
|
6437
|
+
if (!font) return void 0;
|
|
6438
|
+
const run = {
|
|
6439
|
+
...font.family && { font: font.family },
|
|
6440
|
+
// docx run sizes are half-points.
|
|
6441
|
+
...font.size !== void 0 && { size: font.size * 2 },
|
|
6442
|
+
...font.color && { color: font.color },
|
|
6443
|
+
...font.bold !== void 0 && { bold: font.bold },
|
|
6444
|
+
...font.italic !== void 0 && { italics: font.italic },
|
|
6445
|
+
...font.underline !== void 0 && {
|
|
6446
|
+
underline: font.underline ? { type: "single" } : void 0
|
|
6447
|
+
}
|
|
6448
|
+
};
|
|
6449
|
+
return Object.keys(run).length > 0 ? run : void 0;
|
|
6450
|
+
}
|
|
6006
6451
|
function createNumberingConfig(config) {
|
|
6007
6452
|
const levels = [];
|
|
6008
6453
|
for (const levelConfig of config.levels) {
|
|
@@ -6011,6 +6456,7 @@ function createNumberingConfig(config) {
|
|
|
6011
6456
|
const text = levelConfig.text || (format2 === LevelFormat.BULLET ? "\u2022" : `%${levelConfig.level + 1}.`);
|
|
6012
6457
|
const baseIndent = levelConfig.indent?.left !== void 0 ? levelConfig.indent.left / 72 : 0.5 * (levelConfig.level + 1);
|
|
6013
6458
|
const hangingIndent = levelConfig.indent?.hanging !== void 0 ? levelConfig.indent.hanging / 72 : 0.25;
|
|
6459
|
+
const markerRun = createMarkerRunStyle(levelConfig.font);
|
|
6014
6460
|
const level = {
|
|
6015
6461
|
level: levelConfig.level,
|
|
6016
6462
|
format: format2,
|
|
@@ -6022,7 +6468,10 @@ function createNumberingConfig(config) {
|
|
|
6022
6468
|
left: convertInchesToTwip(baseIndent),
|
|
6023
6469
|
hanging: convertInchesToTwip(hangingIndent)
|
|
6024
6470
|
}
|
|
6025
|
-
}
|
|
6471
|
+
},
|
|
6472
|
+
// The marker glyph carries its own run properties; without this it
|
|
6473
|
+
// inherits whatever the list paragraph resolves to.
|
|
6474
|
+
...markerRun && { run: markerRun }
|
|
6026
6475
|
},
|
|
6027
6476
|
// Add start number if specified
|
|
6028
6477
|
...levelConfig.start !== void 0 && { start: levelConfig.start }
|
|
@@ -6039,7 +6488,7 @@ var NumberingRegistry = class {
|
|
|
6039
6488
|
configs: /* @__PURE__ */ new Map(),
|
|
6040
6489
|
counter: 0
|
|
6041
6490
|
};
|
|
6042
|
-
scopes = new
|
|
6491
|
+
scopes = new AsyncLocalStorage6();
|
|
6043
6492
|
get state() {
|
|
6044
6493
|
return this.scopes.getStore() ?? this.fallback;
|
|
6045
6494
|
}
|
|
@@ -6151,7 +6600,10 @@ function renderParagraphComponent(component, theme, themeName) {
|
|
|
6151
6600
|
return createList(listData.items, theme, themeName, {
|
|
6152
6601
|
numberingReference: reference,
|
|
6153
6602
|
spacing: resolvedConfig.spacing,
|
|
6154
|
-
alignment: resolvedConfig.alignment
|
|
6603
|
+
alignment: resolvedConfig.alignment,
|
|
6604
|
+
comment: resolvedConfig.comment,
|
|
6605
|
+
footnotes: resolvedConfig.footnotes,
|
|
6606
|
+
endnotes: resolvedConfig.endnotes
|
|
6155
6607
|
});
|
|
6156
6608
|
}
|
|
6157
6609
|
const styleFromTheme = (() => {
|
|
@@ -6215,12 +6667,18 @@ function renderParagraphComponent(component, theme, themeName) {
|
|
|
6215
6667
|
// Pass bookmark ID for internal linking
|
|
6216
6668
|
bookmarkId: resolvedConfig.id,
|
|
6217
6669
|
// Tracked-change segments (rendered as native Word revisions)
|
|
6218
|
-
revision: resolvedConfig.revision
|
|
6670
|
+
revision: resolvedConfig.revision,
|
|
6671
|
+
// Review comment anchored to this paragraph's text
|
|
6672
|
+
comment: resolvedConfig.comment,
|
|
6673
|
+
// Note bodies for the `[^id]` markers in this paragraph
|
|
6674
|
+
footnotes: resolvedConfig.footnotes,
|
|
6675
|
+
endnotes: resolvedConfig.endnotes
|
|
6219
6676
|
});
|
|
6220
6677
|
return [text];
|
|
6221
6678
|
}
|
|
6222
6679
|
|
|
6223
6680
|
// src/components/list.ts
|
|
6681
|
+
init_colorUtils();
|
|
6224
6682
|
function createLevelsFromSimplifiedProps(props) {
|
|
6225
6683
|
const levels = [];
|
|
6226
6684
|
let format2;
|
|
@@ -6267,6 +6725,22 @@ function createLevelsFromSimplifiedProps(props) {
|
|
|
6267
6725
|
}
|
|
6268
6726
|
return levels;
|
|
6269
6727
|
}
|
|
6728
|
+
function resolveMarkerFonts(levels, theme) {
|
|
6729
|
+
return levels.map((level) => {
|
|
6730
|
+
const font = level.font;
|
|
6731
|
+
if (!font?.color) return level;
|
|
6732
|
+
return {
|
|
6733
|
+
...level,
|
|
6734
|
+
font: { ...font, color: resolveColor(font.color, theme) }
|
|
6735
|
+
};
|
|
6736
|
+
});
|
|
6737
|
+
}
|
|
6738
|
+
function applyListStart(levels, start) {
|
|
6739
|
+
if (start === void 0) return levels;
|
|
6740
|
+
return levels.map(
|
|
6741
|
+
(level) => level.level === 0 && level.start === void 0 ? { ...level, start } : level
|
|
6742
|
+
);
|
|
6743
|
+
}
|
|
6270
6744
|
function getMaxLevelFromItems(items) {
|
|
6271
6745
|
if (!items || !Array.isArray(items)) {
|
|
6272
6746
|
return 0;
|
|
@@ -6329,7 +6803,10 @@ function renderListComponent(component, theme, themeName) {
|
|
|
6329
6803
|
let levels;
|
|
6330
6804
|
if (resolvedConfig.levels && resolvedConfig.levels.length > 0) {
|
|
6331
6805
|
levels = fillMissingLevels(
|
|
6332
|
-
|
|
6806
|
+
applyListStart(
|
|
6807
|
+
resolvedConfig.levels,
|
|
6808
|
+
resolvedConfig.start
|
|
6809
|
+
),
|
|
6333
6810
|
maxLevel
|
|
6334
6811
|
);
|
|
6335
6812
|
} else {
|
|
@@ -6338,7 +6815,7 @@ function renderListComponent(component, theme, themeName) {
|
|
|
6338
6815
|
}
|
|
6339
6816
|
const config = {
|
|
6340
6817
|
reference,
|
|
6341
|
-
levels
|
|
6818
|
+
levels: resolveMarkerFonts(levels, theme)
|
|
6342
6819
|
};
|
|
6343
6820
|
const numberingConfig = createNumberingConfig(config);
|
|
6344
6821
|
globalNumberingRegistry.register(numberingConfig);
|
|
@@ -6346,7 +6823,9 @@ function renderListComponent(component, theme, themeName) {
|
|
|
6346
6823
|
return createList(resolvedConfig.items, theme, themeName, {
|
|
6347
6824
|
numberingReference: reference,
|
|
6348
6825
|
spacing: resolvedConfig.spacing,
|
|
6349
|
-
alignment: resolvedConfig.alignment
|
|
6826
|
+
alignment: resolvedConfig.alignment,
|
|
6827
|
+
// Review comment spanning the whole list
|
|
6828
|
+
comment: resolvedConfig.comment
|
|
6350
6829
|
});
|
|
6351
6830
|
}
|
|
6352
6831
|
|
|
@@ -6437,10 +6916,10 @@ function convertBorders2(bordersConfig, theme) {
|
|
|
6437
6916
|
// src/styles/utils/cellUtils.ts
|
|
6438
6917
|
init_styleHelpers();
|
|
6439
6918
|
init_colorUtils();
|
|
6440
|
-
import { Paragraph as
|
|
6919
|
+
import { Paragraph as Paragraph4 } from "docx";
|
|
6441
6920
|
function buildCellOptions(children, styleCfg, theme) {
|
|
6442
6921
|
const cellOpts = {
|
|
6443
|
-
children: children.length ? children : [new
|
|
6922
|
+
children: children.length ? children : [new Paragraph4({})],
|
|
6444
6923
|
margins: {
|
|
6445
6924
|
top: styleCfg?.padding?.top ? pointsToTwips(styleCfg.padding.top) : 0,
|
|
6446
6925
|
right: styleCfg?.padding?.right ? pointsToTwips(styleCfg.padding.right) : 0,
|
|
@@ -6643,25 +7122,66 @@ async function renderTableComponent(component, theme, themeName) {
|
|
|
6643
7122
|
}
|
|
6644
7123
|
|
|
6645
7124
|
// src/components/section.ts
|
|
6646
|
-
import { Paragraph as
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
7125
|
+
import { Paragraph as Paragraph6, BookmarkStart, BookmarkEnd } from "docx";
|
|
7126
|
+
|
|
7127
|
+
// src/core/sectionBookmarks.ts
|
|
7128
|
+
import { AsyncLocalStorage as AsyncLocalStorage7 } from "async_hooks";
|
|
7129
|
+
var NESTED_LINK_ID_BASE = 1e6;
|
|
7130
|
+
function createState3() {
|
|
7131
|
+
return { nextNested: 1, resolved: /* @__PURE__ */ new WeakMap() };
|
|
7132
|
+
}
|
|
7133
|
+
var SectionBookmarkRegistry = class {
|
|
7134
|
+
fallback = createState3();
|
|
7135
|
+
scopes = new AsyncLocalStorage7();
|
|
7136
|
+
get state() {
|
|
7137
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
7138
|
+
}
|
|
7139
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
7140
|
+
runScoped(callback) {
|
|
7141
|
+
return this.scopes.run(createState3(), callback);
|
|
7142
|
+
}
|
|
7143
|
+
/**
|
|
7144
|
+
* The bookmark for a layout section, derived from its ordinal.
|
|
7145
|
+
*
|
|
7146
|
+
* Every layout chunk of one user-defined section shares an ordinal (see
|
|
7147
|
+
* `computeSectionOrdinals`), so they all resolve to the same bookmark — which
|
|
7148
|
+
* is the point: the start lands in the first chunk and the end in the last.
|
|
7149
|
+
*/
|
|
7150
|
+
forLayoutSection(ordinal) {
|
|
7151
|
+
return { id: `_Section_${ordinal}`, linkId: ordinal };
|
|
7152
|
+
}
|
|
7153
|
+
/**
|
|
7154
|
+
* The bookmark for a `section` component, allocated on first sight and
|
|
7155
|
+
* remembered so re-resolving the same component never allocates twice.
|
|
7156
|
+
*/
|
|
7157
|
+
forSectionComponent(component) {
|
|
7158
|
+
const state = this.state;
|
|
7159
|
+
const existing = state.resolved.get(component);
|
|
7160
|
+
if (existing) return existing;
|
|
7161
|
+
const ordinal = state.nextNested++;
|
|
7162
|
+
const bookmark = {
|
|
7163
|
+
id: `_NestedSection_${ordinal}`,
|
|
7164
|
+
linkId: NESTED_LINK_ID_BASE + ordinal
|
|
7165
|
+
};
|
|
7166
|
+
state.resolved.set(component, bookmark);
|
|
7167
|
+
return bookmark;
|
|
7168
|
+
}
|
|
7169
|
+
/** Test-only: reset the unscoped fallback counters. */
|
|
7170
|
+
clear() {
|
|
7171
|
+
if (!this.scopes.getStore()) {
|
|
7172
|
+
this.fallback = createState3();
|
|
7173
|
+
}
|
|
7174
|
+
}
|
|
7175
|
+
};
|
|
7176
|
+
var globalSectionBookmarkRegistry = new SectionBookmarkRegistry();
|
|
7177
|
+
|
|
7178
|
+
// src/components/section.ts
|
|
6659
7179
|
async function renderSectionComponent(component, theme, themeName, context) {
|
|
6660
7180
|
if (!isSectionComponent(component)) return [];
|
|
6661
7181
|
const elements = [];
|
|
6662
|
-
const { id: sectionBookmarkId, linkId: bookmarkLinkId } =
|
|
7182
|
+
const { id: sectionBookmarkId, linkId: bookmarkLinkId } = globalSectionBookmarkRegistry.forSectionComponent(component);
|
|
6663
7183
|
elements.push(
|
|
6664
|
-
new
|
|
7184
|
+
new Paragraph6({
|
|
6665
7185
|
children: [new BookmarkStart(sectionBookmarkId, bookmarkLinkId)],
|
|
6666
7186
|
spacing: {
|
|
6667
7187
|
before: 0,
|
|
@@ -6689,7 +7209,7 @@ async function renderSectionComponent(component, theme, themeName, context) {
|
|
|
6689
7209
|
}
|
|
6690
7210
|
}
|
|
6691
7211
|
elements.push(
|
|
6692
|
-
new
|
|
7212
|
+
new Paragraph6({
|
|
6693
7213
|
children: [new BookmarkEnd(bookmarkLinkId)],
|
|
6694
7214
|
spacing: {
|
|
6695
7215
|
before: 0,
|
|
@@ -6703,7 +7223,7 @@ async function renderSectionComponent(component, theme, themeName, context) {
|
|
|
6703
7223
|
|
|
6704
7224
|
// src/components/columns.ts
|
|
6705
7225
|
import {
|
|
6706
|
-
Paragraph as
|
|
7226
|
+
Paragraph as Paragraph7,
|
|
6707
7227
|
Table as Table5,
|
|
6708
7228
|
TableRow as TableRow3,
|
|
6709
7229
|
TableCell as TableCell3,
|
|
@@ -6795,7 +7315,7 @@ async function renderColumnsAsTable(component, theme, themeName, context) {
|
|
|
6795
7315
|
columnElements.push(...rendered);
|
|
6796
7316
|
}
|
|
6797
7317
|
if (columnElements.length === 0) {
|
|
6798
|
-
columnElements.push(new
|
|
7318
|
+
columnElements.push(new Paragraph7({}));
|
|
6799
7319
|
}
|
|
6800
7320
|
cells.push(
|
|
6801
7321
|
new TableCell3({
|
|
@@ -6846,12 +7366,34 @@ function renderStatisticComponent(component, _theme) {
|
|
|
6846
7366
|
|
|
6847
7367
|
// src/components/toc/index.ts
|
|
6848
7368
|
import {
|
|
6849
|
-
Paragraph as
|
|
7369
|
+
Paragraph as Paragraph8,
|
|
6850
7370
|
TableOfContents,
|
|
6851
7371
|
AlignmentType as AlignmentType4,
|
|
6852
|
-
TextRun as
|
|
7372
|
+
TextRun as TextRun8,
|
|
6853
7373
|
StyleLevel
|
|
6854
7374
|
} from "docx";
|
|
7375
|
+
function toStyleDisplayName(styleId) {
|
|
7376
|
+
return styleId.replace(/([A-Z])/g, " $1").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
|
|
7377
|
+
}
|
|
7378
|
+
function selectCachedEntries(collected, options) {
|
|
7379
|
+
if (!collected || collected.length === 0) return [];
|
|
7380
|
+
const { depthStart, depthEnd, sectionBookmarkId, styleLevels } = options;
|
|
7381
|
+
const entries = [];
|
|
7382
|
+
for (const entry of collected) {
|
|
7383
|
+
if (sectionBookmarkId && entry.sectionBookmarkId !== sectionBookmarkId) {
|
|
7384
|
+
continue;
|
|
7385
|
+
}
|
|
7386
|
+
if (entry.styleId !== void 0) {
|
|
7387
|
+
const level = styleLevels.get(entry.styleId) ?? styleLevels.get(toStyleDisplayName(entry.styleId));
|
|
7388
|
+
if (level === void 0) continue;
|
|
7389
|
+
entries.push({ title: entry.title, level });
|
|
7390
|
+
continue;
|
|
7391
|
+
}
|
|
7392
|
+
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
7393
|
+
entries.push({ title: entry.title, level: entry.level });
|
|
7394
|
+
}
|
|
7395
|
+
return entries;
|
|
7396
|
+
}
|
|
6855
7397
|
function parseDepthRange(rawDepth, fieldName, defaultFrom = 1, defaultTo = 3) {
|
|
6856
7398
|
if (typeof rawDepth !== "object" || rawDepth === null) {
|
|
6857
7399
|
throw new Error(
|
|
@@ -6907,9 +7449,9 @@ function renderTocComponent(component, theme, context) {
|
|
|
6907
7449
|
const paragraphs = [];
|
|
6908
7450
|
if (componentProps.title) {
|
|
6909
7451
|
paragraphs.push(
|
|
6910
|
-
new
|
|
7452
|
+
new Paragraph8({
|
|
6911
7453
|
children: [
|
|
6912
|
-
new
|
|
7454
|
+
new TextRun8({
|
|
6913
7455
|
text: componentProps.title,
|
|
6914
7456
|
bold: true,
|
|
6915
7457
|
size: 28
|
|
@@ -6927,11 +7469,14 @@ function renderTocComponent(component, theme, context) {
|
|
|
6927
7469
|
);
|
|
6928
7470
|
}
|
|
6929
7471
|
const stylesWithLevels = [];
|
|
7472
|
+
const styleLevels = /* @__PURE__ */ new Map();
|
|
6930
7473
|
if (componentProps.styles && componentProps.styles.length > 0) {
|
|
6931
7474
|
for (const styleMapping of componentProps.styles) {
|
|
6932
7475
|
const styleId = styleMapping.styleId;
|
|
6933
7476
|
const isCustomStyle = !!theme.styles && Object.prototype.hasOwnProperty.call(theme.styles, styleId);
|
|
6934
|
-
const styleDisplayName = isCustomStyle ? styleId
|
|
7477
|
+
const styleDisplayName = isCustomStyle ? toStyleDisplayName(styleId) : styleId;
|
|
7478
|
+
styleLevels.set(styleId, styleMapping.level);
|
|
7479
|
+
styleLevels.set(styleDisplayName, styleMapping.level);
|
|
6935
7480
|
stylesWithLevels.push(
|
|
6936
7481
|
new StyleLevel(styleDisplayName, styleMapping.level)
|
|
6937
7482
|
);
|
|
@@ -6939,6 +7484,12 @@ function renderTocComponent(component, theme, context) {
|
|
|
6939
7484
|
}
|
|
6940
7485
|
const effectiveDepthStart = depthStart;
|
|
6941
7486
|
const effectiveDepthEnd = depthEnd;
|
|
7487
|
+
const cachedEntries = selectCachedEntries(context?.tocHeadings, {
|
|
7488
|
+
depthStart,
|
|
7489
|
+
depthEnd,
|
|
7490
|
+
sectionBookmarkId,
|
|
7491
|
+
styleLevels
|
|
7492
|
+
});
|
|
6942
7493
|
const tocOptions = {
|
|
6943
7494
|
hyperlink: true,
|
|
6944
7495
|
// Enable clickable hyperlinks (\h switch)
|
|
@@ -6977,7 +7528,10 @@ function renderTocComponent(component, theme, context) {
|
|
|
6977
7528
|
// default to tab
|
|
6978
7529
|
};
|
|
6979
7530
|
paragraphs.push(
|
|
6980
|
-
new TableOfContents(componentProps.title ?? "Table of Contents",
|
|
7531
|
+
new TableOfContents(componentProps.title ?? "Table of Contents", {
|
|
7532
|
+
...tocOptions,
|
|
7533
|
+
...cachedEntries.length > 0 && { cachedEntries }
|
|
7534
|
+
})
|
|
6981
7535
|
);
|
|
6982
7536
|
return paragraphs;
|
|
6983
7537
|
}
|
|
@@ -7504,6 +8058,78 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
7504
8058
|
return map;
|
|
7505
8059
|
}
|
|
7506
8060
|
|
|
8061
|
+
// src/core/sectionOrdinals.ts
|
|
8062
|
+
function computeSectionOrdinals(sections) {
|
|
8063
|
+
let counter = 0;
|
|
8064
|
+
return sections.map((section, index) => {
|
|
8065
|
+
if (!section.belongsToUserSection) {
|
|
8066
|
+
if (section.isUserSection) counter++;
|
|
8067
|
+
return { closeBookmark: false };
|
|
8068
|
+
}
|
|
8069
|
+
const ordinal = section.isUserSection ? counter + 1 : counter;
|
|
8070
|
+
if (section.isUserSection) counter++;
|
|
8071
|
+
const next = sections[index + 1];
|
|
8072
|
+
const closeBookmark = !next || !next.belongsToUserSection || next.isUserSection;
|
|
8073
|
+
return { ordinal, closeBookmark };
|
|
8074
|
+
});
|
|
8075
|
+
}
|
|
8076
|
+
|
|
8077
|
+
// src/core/collectTocHeadings.ts
|
|
8078
|
+
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
8079
|
+
function normalizeEntryTitle(text) {
|
|
8080
|
+
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
8081
|
+
}
|
|
8082
|
+
function isContainer(name) {
|
|
8083
|
+
return getStandardComponent(name)?.hasChildren === true;
|
|
8084
|
+
}
|
|
8085
|
+
function isEnabled(component) {
|
|
8086
|
+
return !("enabled" in component && component.enabled === false);
|
|
8087
|
+
}
|
|
8088
|
+
function styleEntryKey(props) {
|
|
8089
|
+
const themeStyle = props.themeStyle;
|
|
8090
|
+
if (typeof themeStyle !== "string" || !themeStyle) return void 0;
|
|
8091
|
+
if (/^heading[1-6]$/i.test(themeStyle)) return void 0;
|
|
8092
|
+
if (["normal", "title", "subtitle"].includes(themeStyle.toLowerCase())) {
|
|
8093
|
+
return void 0;
|
|
8094
|
+
}
|
|
8095
|
+
return themeStyle;
|
|
8096
|
+
}
|
|
8097
|
+
function collectTocHeadings(sections) {
|
|
8098
|
+
const entries = [];
|
|
8099
|
+
const ordinals = computeSectionOrdinals(sections);
|
|
8100
|
+
sections.forEach((section, index) => {
|
|
8101
|
+
const ordinal = ordinals[index]?.ordinal;
|
|
8102
|
+
const sectionBookmarkId = ordinal ? globalSectionBookmarkRegistry.forLayoutSection(ordinal).id : void 0;
|
|
8103
|
+
const visit = (component) => {
|
|
8104
|
+
if (!isEnabled(component)) return;
|
|
8105
|
+
const props = component.props ?? {};
|
|
8106
|
+
if (component.name === "heading") {
|
|
8107
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
8108
|
+
const title = normalizeEntryTitle(text);
|
|
8109
|
+
if (title) {
|
|
8110
|
+
const level = typeof props.level === "number" ? props.level : 1;
|
|
8111
|
+
entries.push({ title, level, sectionBookmarkId });
|
|
8112
|
+
}
|
|
8113
|
+
return;
|
|
8114
|
+
}
|
|
8115
|
+
if (component.name === "paragraph") {
|
|
8116
|
+
const styleId = styleEntryKey(props);
|
|
8117
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
8118
|
+
const title = normalizeEntryTitle(text);
|
|
8119
|
+
if (styleId && title) {
|
|
8120
|
+
entries.push({ title, level: 1, styleId, sectionBookmarkId });
|
|
8121
|
+
}
|
|
8122
|
+
return;
|
|
8123
|
+
}
|
|
8124
|
+
if (!isContainer(component.name)) return;
|
|
8125
|
+
const children = component.children;
|
|
8126
|
+
if (Array.isArray(children)) children.forEach(visit);
|
|
8127
|
+
};
|
|
8128
|
+
section.components.forEach(visit);
|
|
8129
|
+
});
|
|
8130
|
+
return entries;
|
|
8131
|
+
}
|
|
8132
|
+
|
|
7507
8133
|
// src/core/render.ts
|
|
7508
8134
|
function getAlignment3(alignment) {
|
|
7509
8135
|
switch (alignment) {
|
|
@@ -7541,7 +8167,23 @@ async function renderDocument(structure, layout, options) {
|
|
|
7541
8167
|
() => globalBookmarkRegistry.runScoped(
|
|
7542
8168
|
() => globalRevisionIdRegistry.runScoped(
|
|
7543
8169
|
() => globalNumberingRegistry.runScoped(
|
|
7544
|
-
() =>
|
|
8170
|
+
() => globalSectionBookmarkRegistry.runScoped(
|
|
8171
|
+
() => (
|
|
8172
|
+
// Comment ids are a separate OOXML namespace from w:ins/w:del,
|
|
8173
|
+
// but they need the same per-render isolation: outside this nest
|
|
8174
|
+
// concurrent generations would interleave counters and an anchor
|
|
8175
|
+
// would point at another document's comment body.
|
|
8176
|
+
globalCommentRegistry.runScoped(
|
|
8177
|
+
() => (
|
|
8178
|
+
// Footnote ids are document-scoped too: a reference resolved
|
|
8179
|
+
// against another render's counter points at the wrong body.
|
|
8180
|
+
globalNoteRegistry.runScoped(
|
|
8181
|
+
() => renderDocumentScoped(structure, layout, options)
|
|
8182
|
+
)
|
|
8183
|
+
)
|
|
8184
|
+
)
|
|
8185
|
+
)
|
|
8186
|
+
)
|
|
7545
8187
|
)
|
|
7546
8188
|
)
|
|
7547
8189
|
)
|
|
@@ -7576,19 +8218,23 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7576
8218
|
error instanceof Error ? error.message : error
|
|
7577
8219
|
);
|
|
7578
8220
|
}
|
|
7579
|
-
|
|
8221
|
+
try {
|
|
8222
|
+
const tocHeadings = collectTocHeadings(layout.sections);
|
|
8223
|
+
if (tocHeadings.length > 0) {
|
|
8224
|
+
context.tocHeadings = tocHeadings;
|
|
8225
|
+
}
|
|
8226
|
+
} catch (error) {
|
|
8227
|
+
console.warn(
|
|
8228
|
+
"[core-docx] TOC entry collection failed; the TOC field will rely on the reader refreshing it:",
|
|
8229
|
+
error instanceof Error ? error.message : error
|
|
8230
|
+
);
|
|
8231
|
+
}
|
|
8232
|
+
const sectionOrdinals = computeSectionOrdinals(layout.sections);
|
|
7580
8233
|
let previousHeader = void 0;
|
|
7581
8234
|
let previousFooter = void 0;
|
|
7582
8235
|
for (let idx = 0; idx < layout.sections.length; idx++) {
|
|
7583
8236
|
const layoutSection = layout.sections[idx];
|
|
7584
|
-
|
|
7585
|
-
if (layoutSection.belongsToUserSection) {
|
|
7586
|
-
if (layoutSection.isUserSection) {
|
|
7587
|
-
sectionOrdinal = sectionBookmarkCounter + 1;
|
|
7588
|
-
} else {
|
|
7589
|
-
sectionOrdinal = sectionBookmarkCounter;
|
|
7590
|
-
}
|
|
7591
|
-
}
|
|
8237
|
+
const { ordinal: sectionOrdinal, closeBookmark } = sectionOrdinals[idx];
|
|
7592
8238
|
let headerToUse;
|
|
7593
8239
|
if (layoutSection.header === "linkToPrevious") {
|
|
7594
8240
|
headerToUse = previousHeader;
|
|
@@ -7612,13 +8258,6 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7612
8258
|
header: headerToUse,
|
|
7613
8259
|
footer: footerToUse
|
|
7614
8260
|
};
|
|
7615
|
-
let closeBookmark = false;
|
|
7616
|
-
if (layoutSection.belongsToUserSection && sectionOrdinal !== void 0) {
|
|
7617
|
-
const next = layout.sections[idx + 1];
|
|
7618
|
-
if (!next || !next.belongsToUserSection || next.isUserSection) {
|
|
7619
|
-
closeBookmark = true;
|
|
7620
|
-
}
|
|
7621
|
-
}
|
|
7622
8261
|
const rendered = await renderSection(
|
|
7623
8262
|
sectionToRender,
|
|
7624
8263
|
structure.theme,
|
|
@@ -7628,14 +8267,14 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7628
8267
|
closeBookmark,
|
|
7629
8268
|
options?.bypassCache === true
|
|
7630
8269
|
);
|
|
7631
|
-
if (layoutSection.isUserSection) {
|
|
7632
|
-
sectionBookmarkCounter++;
|
|
7633
|
-
}
|
|
7634
8270
|
if (rendered.children.length > 0) {
|
|
7635
8271
|
sections.push(rendered);
|
|
7636
8272
|
}
|
|
7637
8273
|
}
|
|
7638
8274
|
const numberingConfigs = globalNumberingRegistry.getAll();
|
|
8275
|
+
const comments = globalCommentRegistry.getAll();
|
|
8276
|
+
const footnotes = globalNoteRegistry.getFootnotes();
|
|
8277
|
+
const endnotes = globalNoteRegistry.getEndnotes();
|
|
7639
8278
|
return new Document({
|
|
7640
8279
|
styles: createWordStyles(structure.theme, structure.language),
|
|
7641
8280
|
sections,
|
|
@@ -7646,6 +8285,12 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7646
8285
|
// Word opens the document in review mode (further edits are tracked)
|
|
7647
8286
|
...structure.trackRevisions && { trackRevisions: true }
|
|
7648
8287
|
},
|
|
8288
|
+
// word/comments.xml, emitted only when something was actually commented
|
|
8289
|
+
...comments.length > 0 && { comments: { children: comments } },
|
|
8290
|
+
// word/footnotes.xml and word/endnotes.xml bodies, keyed by the id their
|
|
8291
|
+
// references carry
|
|
8292
|
+
...Object.keys(footnotes).length > 0 && { footnotes },
|
|
8293
|
+
...Object.keys(endnotes).length > 0 && { endnotes },
|
|
7649
8294
|
// Add numbering configurations if any lists were rendered
|
|
7650
8295
|
...numberingConfigs.length > 0 && {
|
|
7651
8296
|
numbering: {
|
|
@@ -7692,9 +8337,9 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7692
8337
|
let imageSource = resolveImageSource(imageComp.props);
|
|
7693
8338
|
if (!imageSource) {
|
|
7694
8339
|
elements.push(
|
|
7695
|
-
new
|
|
8340
|
+
new Paragraph9({
|
|
7696
8341
|
children: [
|
|
7697
|
-
new
|
|
8342
|
+
new TextRun9({
|
|
7698
8343
|
text: "[IMAGE: Missing path, base64, or svg property]",
|
|
7699
8344
|
font: getThemeFonts(theme).body.family,
|
|
7700
8345
|
size: 20,
|
|
@@ -7762,7 +8407,7 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7762
8407
|
...floatingOptions && { floating: floatingOptions }
|
|
7763
8408
|
});
|
|
7764
8409
|
elements.push(
|
|
7765
|
-
new
|
|
8410
|
+
new Paragraph9({
|
|
7766
8411
|
children: [imageRun],
|
|
7767
8412
|
alignment: imageComp.props.alignment ? getAlignment3(imageComp.props.alignment) : void 0,
|
|
7768
8413
|
style: "Normal"
|
|
@@ -7775,9 +8420,9 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7775
8420
|
error instanceof Error ? error.message : error
|
|
7776
8421
|
);
|
|
7777
8422
|
elements.push(
|
|
7778
|
-
new
|
|
8423
|
+
new Paragraph9({
|
|
7779
8424
|
children: [
|
|
7780
|
-
new
|
|
8425
|
+
new TextRun9({
|
|
7781
8426
|
text: `[IMAGE: ${sourcePreview}]`,
|
|
7782
8427
|
font: getThemeFonts(theme).body.family,
|
|
7783
8428
|
size: 20,
|
|
@@ -7807,8 +8452,9 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
7807
8452
|
async function renderSection(section, theme, themeName, context, sectionOrdinal, closeBookmark, bypassCache = false) {
|
|
7808
8453
|
const elements = [];
|
|
7809
8454
|
const isFirstLayoutOfUserSection = section.isUserSection;
|
|
7810
|
-
const
|
|
7811
|
-
const
|
|
8455
|
+
const bookmark = section.belongsToUserSection && sectionOrdinal ? globalSectionBookmarkRegistry.forLayoutSection(sectionOrdinal) : void 0;
|
|
8456
|
+
const sharedLinkId = bookmark?.linkId;
|
|
8457
|
+
const sectionBookmarkId = bookmark?.id;
|
|
7812
8458
|
const sectionContext = {
|
|
7813
8459
|
...context,
|
|
7814
8460
|
section: {
|
|
@@ -7821,7 +8467,7 @@ async function renderSection(section, theme, themeName, context, sectionOrdinal,
|
|
|
7821
8467
|
};
|
|
7822
8468
|
if (sectionBookmarkId && isFirstLayoutOfUserSection && sharedLinkId !== void 0) {
|
|
7823
8469
|
elements.push(
|
|
7824
|
-
new
|
|
8470
|
+
new Paragraph9({
|
|
7825
8471
|
children: [new BookmarkStart2(sectionBookmarkId, sharedLinkId)],
|
|
7826
8472
|
spacing: {
|
|
7827
8473
|
before: 0,
|
|
@@ -7846,7 +8492,7 @@ async function renderSection(section, theme, themeName, context, sectionOrdinal,
|
|
|
7846
8492
|
}
|
|
7847
8493
|
if (closeBookmark && sharedLinkId !== void 0) {
|
|
7848
8494
|
elements.push(
|
|
7849
|
-
new
|
|
8495
|
+
new Paragraph9({
|
|
7850
8496
|
children: [new BookmarkEnd2(sharedLinkId)]
|
|
7851
8497
|
})
|
|
7852
8498
|
);
|
|
@@ -8022,9 +8668,9 @@ function fixFloatingImageIdsInBuffer(buffer) {
|
|
|
8022
8668
|
throw new Error("document.xml not found in DOCX");
|
|
8023
8669
|
}
|
|
8024
8670
|
let idCounter = 1;
|
|
8025
|
-
const documentXml = documentEntry.getData().toString("utf8").replace(
|
|
8671
|
+
const documentXml = documentEntry.getData().toString("utf8").replace(/(<wp:docPr\b[^>]*?\s)id="\d+"/g, (_match, prefix) => {
|
|
8026
8672
|
const newId = idCounter++;
|
|
8027
|
-
return
|
|
8673
|
+
return `${prefix}id="${newId}"`;
|
|
8028
8674
|
});
|
|
8029
8675
|
zip.updateFile(documentEntry, Buffer.from(documentXml, "utf8"));
|
|
8030
8676
|
return zip.toBuffer();
|