@json-to-office/core-docx 0.36.1 → 0.37.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/text-box.d.ts +1 -1
- package/dist/components/text-box.d.ts.map +1 -1
- package/dist/components/toc/index.d.ts.map +1 -1
- package/dist/core/cached-render.d.ts +2 -2
- package/dist/core/cached-render.d.ts.map +1 -1
- package/dist/core/collectTocHeadings.d.ts +27 -1
- package/dist/core/collectTocHeadings.d.ts.map +1 -1
- package/dist/core/content.d.ts +10 -0
- package/dist/core/content.d.ts.map +1 -1
- package/dist/core/render.d.ts +2 -2
- package/dist/core/render.d.ts.map +1 -1
- package/dist/index.js +605 -160
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +603 -160
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/templates/themes/apex.docx.theme.json +0 -3
- package/dist/templates/themes/corporate.docx.theme.json +0 -3
- package/dist/templates/themes/devportal.docx.theme.json +0 -3
- package/dist/templates/themes/index.d.ts +4 -0
- package/dist/templates/themes/index.d.ts.map +1 -1
- package/dist/templates/themes/minimal.docx.theme.json +0 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/bookmarkRegistry.d.ts +14 -0
- package/dist/utils/bookmarkRegistry.d.ts.map +1 -1
- package/dist/utils/listLevels.d.ts +38 -0
- package/dist/utils/listLevels.d.ts.map +1 -0
- package/dist/utils/numberFormatting.d.ts +11 -0
- package/dist/utils/numberFormatting.d.ts.map +1 -0
- package/dist/utils/numberedItemsRegistry.d.ts +38 -0
- package/dist/utils/numberedItemsRegistry.d.ts.map +1 -0
- package/dist/utils/numberingConfig.d.ts +31 -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/textParser.d.ts +6 -0
- package/dist/utils/textParser.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -377,9 +377,6 @@ var init_minimal_docx_theme = __esm({
|
|
|
377
377
|
},
|
|
378
378
|
section: {
|
|
379
379
|
pageBreak: false
|
|
380
|
-
},
|
|
381
|
-
heading: {
|
|
382
|
-
numbering: false
|
|
383
380
|
}
|
|
384
381
|
}
|
|
385
382
|
};
|
|
@@ -502,9 +499,6 @@ var init_corporate_docx_theme = __esm({
|
|
|
502
499
|
},
|
|
503
500
|
section: {
|
|
504
501
|
pageBreak: false
|
|
505
|
-
},
|
|
506
|
-
heading: {
|
|
507
|
-
numbering: false
|
|
508
502
|
}
|
|
509
503
|
}
|
|
510
504
|
};
|
|
@@ -747,9 +741,6 @@ var init_apex_docx_theme = __esm({
|
|
|
747
741
|
},
|
|
748
742
|
section: {
|
|
749
743
|
pageBreak: false
|
|
750
|
-
},
|
|
751
|
-
heading: {
|
|
752
|
-
numbering: false
|
|
753
744
|
}
|
|
754
745
|
}
|
|
755
746
|
};
|
|
@@ -883,9 +874,6 @@ var init_devportal_docx_theme = __esm({
|
|
|
883
874
|
},
|
|
884
875
|
section: {
|
|
885
876
|
pageBreak: false
|
|
886
|
-
},
|
|
887
|
-
heading: {
|
|
888
|
-
numbering: false
|
|
889
877
|
}
|
|
890
878
|
}
|
|
891
879
|
};
|
|
@@ -2458,6 +2446,8 @@ import {
|
|
|
2458
2446
|
InternalHyperlink as InternalHyperlink2,
|
|
2459
2447
|
FootnoteReferenceRun as FootnoteReferenceRun2,
|
|
2460
2448
|
EndnoteReferenceRun as EndnoteReferenceRun2,
|
|
2449
|
+
NumberedItemReference,
|
|
2450
|
+
NumberedItemReferenceFormat,
|
|
2461
2451
|
Tab
|
|
2462
2452
|
} from "docx";
|
|
2463
2453
|
|
|
@@ -2658,6 +2648,45 @@ function initializeBuiltinPlaceholders() {
|
|
|
2658
2648
|
}
|
|
2659
2649
|
initializeBuiltinPlaceholders();
|
|
2660
2650
|
|
|
2651
|
+
// src/utils/numberedItemsRegistry.ts
|
|
2652
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
2653
|
+
var NumberedItemsRegistry = class {
|
|
2654
|
+
fallback = {
|
|
2655
|
+
items: /* @__PURE__ */ new Map(),
|
|
2656
|
+
seeded: false
|
|
2657
|
+
};
|
|
2658
|
+
scopes = new AsyncLocalStorage2();
|
|
2659
|
+
get state() {
|
|
2660
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
2661
|
+
}
|
|
2662
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
2663
|
+
runScoped(callback) {
|
|
2664
|
+
return this.scopes.run({ items: /* @__PURE__ */ new Map(), seeded: false }, callback);
|
|
2665
|
+
}
|
|
2666
|
+
/** Replace the contents with the pre-pass result. */
|
|
2667
|
+
seed(items) {
|
|
2668
|
+
const state = this.state;
|
|
2669
|
+
state.items = new Map(items);
|
|
2670
|
+
state.seeded = true;
|
|
2671
|
+
}
|
|
2672
|
+
/**
|
|
2673
|
+
* False outside a render (a unit test calling `createText` directly). An
|
|
2674
|
+
* unresolved reference is then expected rather than an authoring mistake, so
|
|
2675
|
+
* the caller stays quiet about it.
|
|
2676
|
+
*/
|
|
2677
|
+
isSeeded() {
|
|
2678
|
+
return this.state.seeded;
|
|
2679
|
+
}
|
|
2680
|
+
get(id) {
|
|
2681
|
+
return this.state.items.get(id);
|
|
2682
|
+
}
|
|
2683
|
+
clear() {
|
|
2684
|
+
this.state.items.clear();
|
|
2685
|
+
this.state.seeded = false;
|
|
2686
|
+
}
|
|
2687
|
+
};
|
|
2688
|
+
var globalNumberedItemsRegistry = new NumberedItemsRegistry();
|
|
2689
|
+
|
|
2661
2690
|
// src/utils/textParser.ts
|
|
2662
2691
|
var FOOTNOTE_MARKER_REGEX = /\[\^([^\]\s]+)\]/;
|
|
2663
2692
|
function escapeRegExp(s) {
|
|
@@ -2874,13 +2903,59 @@ function splitNoteMarkers(text, noteRef, runs) {
|
|
|
2874
2903
|
if (trailing) out.push(...runs(trailing));
|
|
2875
2904
|
return out;
|
|
2876
2905
|
}
|
|
2906
|
+
var CROSS_REFERENCE_PATTERN = "\\[@([^\\]\\s:]+)(?::(relative|no_context|full_context|none))?\\]";
|
|
2907
|
+
var INLINE_TOKEN_REGEX = `\\[([^\\]]+)\\]\\(([^)]+)\\)|${CROSS_REFERENCE_PATTERN}`;
|
|
2908
|
+
function hasCrossReference(text) {
|
|
2909
|
+
return new RegExp(CROSS_REFERENCE_PATTERN).test(text);
|
|
2910
|
+
}
|
|
2911
|
+
var REFERENCE_FORMATS = {
|
|
2912
|
+
relative: NumberedItemReferenceFormat.RELATIVE,
|
|
2913
|
+
no_context: NumberedItemReferenceFormat.NO_CONTEXT,
|
|
2914
|
+
full_context: NumberedItemReferenceFormat.FULL_CONTEXT,
|
|
2915
|
+
none: NumberedItemReferenceFormat.NONE
|
|
2916
|
+
};
|
|
2917
|
+
function createCrossReference(id, format2, token, baseStyle, options) {
|
|
2918
|
+
const info = globalNumberedItemsRegistry.get(id);
|
|
2919
|
+
if (!info) {
|
|
2920
|
+
if (globalNumberedItemsRegistry.isSeeded()) {
|
|
2921
|
+
console.warn(
|
|
2922
|
+
`[core-docx] Cross-reference ${token} has no target: no heading or list item declares the id "${id}". Rendering the token as literal text.`
|
|
2923
|
+
);
|
|
2924
|
+
}
|
|
2925
|
+
return buildTextRuns(
|
|
2926
|
+
token,
|
|
2927
|
+
buildRunCommonProps(baseStyle, { boldColor: options.boldColor }),
|
|
2928
|
+
{ noProof: baseStyle.noProof, noProofWords: options.noProofWords }
|
|
2929
|
+
);
|
|
2930
|
+
}
|
|
2931
|
+
if (format2 === "none") {
|
|
2932
|
+
return [
|
|
2933
|
+
new NumberedItemReference(id, info.text, {
|
|
2934
|
+
hyperlink: true,
|
|
2935
|
+
referenceFormat: REFERENCE_FORMATS.none
|
|
2936
|
+
})
|
|
2937
|
+
];
|
|
2938
|
+
}
|
|
2939
|
+
const cachedValue = format2 === "no_context" ? info.own : info.full;
|
|
2940
|
+
if (cachedValue === void 0) {
|
|
2941
|
+
console.warn(
|
|
2942
|
+
`[core-docx] Cross-reference ${token} targets an unnumbered ${info.kind} ("${id}"), so the field carries no cached number and reads blank until the reader updates fields. Use [@${id}:none] to reference its text instead.`
|
|
2943
|
+
);
|
|
2944
|
+
}
|
|
2945
|
+
return [
|
|
2946
|
+
new NumberedItemReference(id, cachedValue, {
|
|
2947
|
+
hyperlink: true,
|
|
2948
|
+
referenceFormat: REFERENCE_FORMATS[format2]
|
|
2949
|
+
})
|
|
2950
|
+
];
|
|
2951
|
+
}
|
|
2877
2952
|
function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
2878
2953
|
const normalizedText = normalizeUnicodeText(text);
|
|
2879
2954
|
const runs = [];
|
|
2880
|
-
const
|
|
2955
|
+
const tokenRegex = new RegExp(INLINE_TOKEN_REGEX, "g");
|
|
2881
2956
|
let lastIndex = 0;
|
|
2882
2957
|
let match;
|
|
2883
|
-
while ((match =
|
|
2958
|
+
while ((match = tokenRegex.exec(normalizedText)) !== null) {
|
|
2884
2959
|
if (match.index > lastIndex) {
|
|
2885
2960
|
const plainText = normalizedText.substring(lastIndex, match.index);
|
|
2886
2961
|
if (plainText) {
|
|
@@ -2892,6 +2967,19 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
2892
2967
|
runs.push(...plainRuns);
|
|
2893
2968
|
}
|
|
2894
2969
|
}
|
|
2970
|
+
lastIndex = match.index + match[0].length;
|
|
2971
|
+
if (match[1] === void 0) {
|
|
2972
|
+
runs.push(
|
|
2973
|
+
...createCrossReference(
|
|
2974
|
+
match[3],
|
|
2975
|
+
match[4] ?? "relative",
|
|
2976
|
+
match[0],
|
|
2977
|
+
baseStyle,
|
|
2978
|
+
options
|
|
2979
|
+
)
|
|
2980
|
+
);
|
|
2981
|
+
continue;
|
|
2982
|
+
}
|
|
2895
2983
|
const linkText = match[1];
|
|
2896
2984
|
const linkUrl = match[2];
|
|
2897
2985
|
const isInternal = linkUrl.startsWith("#");
|
|
@@ -2918,7 +3006,6 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
2918
3006
|
})
|
|
2919
3007
|
);
|
|
2920
3008
|
}
|
|
2921
|
-
lastIndex = match.index + match[0].length;
|
|
2922
3009
|
}
|
|
2923
3010
|
if (lastIndex < normalizedText.length) {
|
|
2924
3011
|
const remainingText = normalizedText.substring(lastIndex);
|
|
@@ -3612,10 +3699,21 @@ function getStyleIdForLevel(level) {
|
|
|
3612
3699
|
}
|
|
3613
3700
|
|
|
3614
3701
|
// src/utils/bookmarkRegistry.ts
|
|
3615
|
-
import { AsyncLocalStorage as
|
|
3702
|
+
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
3703
|
+
function slugifyBookmarkText(text) {
|
|
3704
|
+
return text.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").substring(0, 40);
|
|
3705
|
+
}
|
|
3706
|
+
function dedupeBookmarkId(base, taken) {
|
|
3707
|
+
let id = base;
|
|
3708
|
+
let attempt = 0;
|
|
3709
|
+
while (taken(id) && attempt < 100) {
|
|
3710
|
+
id = `${base}-${++attempt}`;
|
|
3711
|
+
}
|
|
3712
|
+
return id;
|
|
3713
|
+
}
|
|
3616
3714
|
var BookmarkRegistry = class {
|
|
3617
3715
|
fallback = { bookmarks: /* @__PURE__ */ new Map() };
|
|
3618
|
-
scopes = new
|
|
3716
|
+
scopes = new AsyncLocalStorage3();
|
|
3619
3717
|
get state() {
|
|
3620
3718
|
return this.scopes.getStore() ?? this.fallback;
|
|
3621
3719
|
}
|
|
@@ -3639,13 +3737,10 @@ var BookmarkRegistry = class {
|
|
|
3639
3737
|
* Converts text to a URL-friendly format
|
|
3640
3738
|
*/
|
|
3641
3739
|
generateId(text, _type = "bookmark") {
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
id = `${baseId}-${++attempt}`;
|
|
3647
|
-
}
|
|
3648
|
-
return id;
|
|
3740
|
+
return dedupeBookmarkId(
|
|
3741
|
+
slugifyBookmarkText(text),
|
|
3742
|
+
(id) => this.state.bookmarks.has(id)
|
|
3743
|
+
);
|
|
3649
3744
|
}
|
|
3650
3745
|
/**
|
|
3651
3746
|
* Check if a bookmark exists
|
|
@@ -3689,7 +3784,7 @@ var globalBookmarkRegistry = new BookmarkRegistry();
|
|
|
3689
3784
|
|
|
3690
3785
|
// src/utils/revisionUtils.ts
|
|
3691
3786
|
import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
|
|
3692
|
-
import { AsyncLocalStorage as
|
|
3787
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
|
|
3693
3788
|
|
|
3694
3789
|
// src/utils/componentAnnotations.ts
|
|
3695
3790
|
function isRecord(value) {
|
|
@@ -3740,7 +3835,7 @@ var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
|
3740
3835
|
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
3741
3836
|
var RevisionIdRegistry = class {
|
|
3742
3837
|
fallbackCounter = 0;
|
|
3743
|
-
scopes = new
|
|
3838
|
+
scopes = new AsyncLocalStorage4();
|
|
3744
3839
|
runScoped(callback) {
|
|
3745
3840
|
return this.scopes.run({ counter: 0 }, callback);
|
|
3746
3841
|
}
|
|
@@ -3851,7 +3946,7 @@ import {
|
|
|
3851
3946
|
|
|
3852
3947
|
// src/utils/commentRegistry.ts
|
|
3853
3948
|
import { Paragraph, TextRun as TextRun4 } from "docx";
|
|
3854
|
-
import { AsyncLocalStorage as
|
|
3949
|
+
import { AsyncLocalStorage as AsyncLocalStorage5 } from "async_hooks";
|
|
3855
3950
|
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
3856
3951
|
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
3857
3952
|
function createState() {
|
|
@@ -3866,7 +3961,7 @@ function bodyParagraphs(text) {
|
|
|
3866
3961
|
}
|
|
3867
3962
|
var CommentRegistry = class {
|
|
3868
3963
|
fallback = createState();
|
|
3869
|
-
scopes = new
|
|
3964
|
+
scopes = new AsyncLocalStorage5();
|
|
3870
3965
|
get state() {
|
|
3871
3966
|
return this.scopes.getStore() ?? this.fallback;
|
|
3872
3967
|
}
|
|
@@ -3961,7 +4056,7 @@ function closeCommentRange(ids) {
|
|
|
3961
4056
|
|
|
3962
4057
|
// src/utils/noteRegistry.ts
|
|
3963
4058
|
import { Paragraph as Paragraph2, TextRun as TextRun6 } from "docx";
|
|
3964
|
-
import { AsyncLocalStorage as
|
|
4059
|
+
import { AsyncLocalStorage as AsyncLocalStorage6 } from "async_hooks";
|
|
3965
4060
|
function createState2() {
|
|
3966
4061
|
return {
|
|
3967
4062
|
footnoteCounter: 0,
|
|
@@ -3980,7 +4075,7 @@ function bodyParagraphs2(text, style) {
|
|
|
3980
4075
|
}
|
|
3981
4076
|
var NoteRegistry = class {
|
|
3982
4077
|
fallback = createState2();
|
|
3983
|
-
scopes = new
|
|
4078
|
+
scopes = new AsyncLocalStorage6();
|
|
3984
4079
|
get state() {
|
|
3985
4080
|
return this.scopes.getStore() ?? this.fallback;
|
|
3986
4081
|
}
|
|
@@ -4336,7 +4431,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4336
4431
|
if (commentAnchor) {
|
|
4337
4432
|
children.push(...commentAnchor.start);
|
|
4338
4433
|
}
|
|
4339
|
-
const
|
|
4434
|
+
const hasInlineSyntax = /(\*\*\*|___|(\*\*|__)|(\*|_))/.test(normalizedText) || hasCrossReference(normalizedText);
|
|
4340
4435
|
const headingHasWeightRequest = options.fontWeight != null || options.bold === true;
|
|
4341
4436
|
const headingEffectiveFamily = options.fontFamily ?? (headingHasWeightRequest ? resolveFontFamily(theme, "heading") : void 0);
|
|
4342
4437
|
const headingWeighted = applyFontWeightAlias({
|
|
@@ -4403,7 +4498,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4403
4498
|
"heading"
|
|
4404
4499
|
);
|
|
4405
4500
|
const headingTextChildren = [];
|
|
4406
|
-
if (
|
|
4501
|
+
if (hasInlineSyntax) {
|
|
4407
4502
|
const textRuns = parseTextWithDecorators(normalizedText, baseTextStyle, {
|
|
4408
4503
|
boldColor: options.boldColor ? resolveColor(options.boldColor, theme) : void 0,
|
|
4409
4504
|
enableHyperlinks: true,
|
|
@@ -4420,7 +4515,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4420
4515
|
})
|
|
4421
4516
|
);
|
|
4422
4517
|
} else {
|
|
4423
|
-
if (
|
|
4518
|
+
if (hasInlineSyntax) {
|
|
4424
4519
|
const textRuns = parseTextWithDecorators(normalizedText, baseTextStyle, {
|
|
4425
4520
|
boldColor: options.boldColor ? resolveColor(options.boldColor, theme) : void 0,
|
|
4426
4521
|
enableHyperlinks: true,
|
|
@@ -4442,7 +4537,10 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
4442
4537
|
spacing: hasExplicitSpacing ? spacing : void 0,
|
|
4443
4538
|
...options.keepNext !== void 0 && { keepNext: options.keepNext },
|
|
4444
4539
|
...options.keepLines !== void 0 && { keepLines: options.keepLines },
|
|
4445
|
-
...options.indent && { indent: options.indent }
|
|
4540
|
+
...options.indent && { indent: options.indent },
|
|
4541
|
+
// docx creates the concrete numbering instance for the reference itself,
|
|
4542
|
+
// in ParagraphProperties.prepForXml.
|
|
4543
|
+
...options.numbering !== void 0 && { numbering: options.numbering }
|
|
4446
4544
|
});
|
|
4447
4545
|
}
|
|
4448
4546
|
async function createImage(path3, theme, themeName, options = {}) {
|
|
@@ -4602,9 +4700,17 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
4602
4700
|
} else if (options.spacing?.item) {
|
|
4603
4701
|
spacing.after = pointsToTwips(options.spacing.item);
|
|
4604
4702
|
}
|
|
4703
|
+
const itemId = typeof item === "object" ? item.id : void 0;
|
|
4704
|
+
let itemContent = textRuns;
|
|
4705
|
+
if (itemId) {
|
|
4706
|
+
globalBookmarkRegistry.register(itemId, itemText, "list-item");
|
|
4707
|
+
itemContent = [
|
|
4708
|
+
new Bookmark({ id: itemId, children: textRuns })
|
|
4709
|
+
];
|
|
4710
|
+
}
|
|
4605
4711
|
const paragraphChildren = [
|
|
4606
4712
|
...commentAnchor && index === firstRendered ? commentAnchor.start : [],
|
|
4607
|
-
...
|
|
4713
|
+
...itemContent,
|
|
4608
4714
|
...commentAnchor && index === lastRendered ? closeCommentRange(commentAnchor.ids) : []
|
|
4609
4715
|
];
|
|
4610
4716
|
const paragraph = new Paragraph3({
|
|
@@ -6807,54 +6913,14 @@ async function renderComponentWithCache(component, theme, themeName, context, by
|
|
|
6807
6913
|
return rendered;
|
|
6808
6914
|
}
|
|
6809
6915
|
|
|
6810
|
-
// src/components/heading.ts
|
|
6811
|
-
function renderHeadingComponent(component, theme, themeName) {
|
|
6812
|
-
if (!isHeadingComponent(component)) return [];
|
|
6813
|
-
const config = component.props;
|
|
6814
|
-
const bookmarkId = component.id || globalBookmarkRegistry.generateId(config.text, "heading");
|
|
6815
|
-
const header = createHeading(
|
|
6816
|
-
config.text,
|
|
6817
|
-
config.level || 1,
|
|
6818
|
-
theme,
|
|
6819
|
-
themeName,
|
|
6820
|
-
{
|
|
6821
|
-
alignment: config.alignment,
|
|
6822
|
-
spacing: config.spacing,
|
|
6823
|
-
lineSpacing: config.lineSpacing,
|
|
6824
|
-
columnBreak: config.columnBreak,
|
|
6825
|
-
// Local font overrides
|
|
6826
|
-
fontFamily: config.font?.family,
|
|
6827
|
-
fontSize: config.font?.size,
|
|
6828
|
-
fontColor: config.font?.color,
|
|
6829
|
-
bold: config.font?.bold,
|
|
6830
|
-
fontWeight: config.font?.fontWeight,
|
|
6831
|
-
italic: config.font?.italic,
|
|
6832
|
-
underline: config.font?.underline,
|
|
6833
|
-
scale: config.font?.scale,
|
|
6834
|
-
characterSpacing: config.font?.characterSpacing,
|
|
6835
|
-
// Proofing: local language override + no-proof toggle + known-words list
|
|
6836
|
-
language: config.language,
|
|
6837
|
-
noProof: config.noProof,
|
|
6838
|
-
noProofWords: config.noProofWords,
|
|
6839
|
-
// Pagination control
|
|
6840
|
-
keepNext: config.keepNext,
|
|
6841
|
-
keepLines: config.keepLines,
|
|
6842
|
-
// Paragraph indentation (w:ind) in twips
|
|
6843
|
-
indent: config.indent,
|
|
6844
|
-
// Bookmark ID for internal linking
|
|
6845
|
-
bookmarkId,
|
|
6846
|
-
// Tracked-change segments (rendered as native Word revisions)
|
|
6847
|
-
revision: config.revision,
|
|
6848
|
-
// Review comment anchored to this heading's text
|
|
6849
|
-
comment: config.comment
|
|
6850
|
-
}
|
|
6851
|
-
);
|
|
6852
|
-
return [header];
|
|
6853
|
-
}
|
|
6854
|
-
|
|
6855
6916
|
// src/utils/numberingConfig.ts
|
|
6856
|
-
import {
|
|
6857
|
-
|
|
6917
|
+
import {
|
|
6918
|
+
AlignmentType as AlignmentType3,
|
|
6919
|
+
convertInchesToTwip,
|
|
6920
|
+
LevelFormat,
|
|
6921
|
+
LevelSuffix
|
|
6922
|
+
} from "docx";
|
|
6923
|
+
import { AsyncLocalStorage as AsyncLocalStorage7 } from "async_hooks";
|
|
6858
6924
|
var LEVEL_FORMAT_MAP = {
|
|
6859
6925
|
decimal: LevelFormat.DECIMAL,
|
|
6860
6926
|
upperRoman: LevelFormat.UPPER_ROMAN,
|
|
@@ -6982,12 +7048,37 @@ function createNumberingConfig(config) {
|
|
|
6982
7048
|
levels
|
|
6983
7049
|
};
|
|
6984
7050
|
}
|
|
7051
|
+
var HEADING_NUMBERING_REFERENCE = "jto-heading-numbering";
|
|
7052
|
+
function createHeadingNumberingConfig() {
|
|
7053
|
+
const levels = [];
|
|
7054
|
+
for (let level = 0; level < 6; level++) {
|
|
7055
|
+
const text = Array.from({ length: level + 1 }, (_, i) => `%${i + 1}`).join(".") + ".";
|
|
7056
|
+
levels.push({
|
|
7057
|
+
level,
|
|
7058
|
+
format: LevelFormat.DECIMAL,
|
|
7059
|
+
text,
|
|
7060
|
+
alignment: AlignmentType3.LEFT,
|
|
7061
|
+
start: 1,
|
|
7062
|
+
// A space, not the default tab: a tab would push the heading text to the
|
|
7063
|
+
// next tab stop and misalign it against unnumbered headings.
|
|
7064
|
+
suffix: LevelSuffix.SPACE,
|
|
7065
|
+
style: {
|
|
7066
|
+
paragraph: { indent: { left: 0, hanging: 0 } },
|
|
7067
|
+
style: `Heading${level + 1}`
|
|
7068
|
+
}
|
|
7069
|
+
});
|
|
7070
|
+
}
|
|
7071
|
+
return { reference: HEADING_NUMBERING_REFERENCE, levels };
|
|
7072
|
+
}
|
|
7073
|
+
function headingNumberLabel(number) {
|
|
7074
|
+
return `${number}.`;
|
|
7075
|
+
}
|
|
6985
7076
|
var NumberingRegistry = class {
|
|
6986
7077
|
fallback = {
|
|
6987
7078
|
configs: /* @__PURE__ */ new Map(),
|
|
6988
7079
|
counter: 0
|
|
6989
7080
|
};
|
|
6990
|
-
scopes = new
|
|
7081
|
+
scopes = new AsyncLocalStorage7();
|
|
6991
7082
|
get state() {
|
|
6992
7083
|
return this.scopes.getStore() ?? this.fallback;
|
|
6993
7084
|
}
|
|
@@ -7037,6 +7128,63 @@ var NumberingRegistry = class {
|
|
|
7037
7128
|
};
|
|
7038
7129
|
var globalNumberingRegistry = new NumberingRegistry();
|
|
7039
7130
|
|
|
7131
|
+
// src/components/heading.ts
|
|
7132
|
+
var MAX_HEADING_LEVEL = 6;
|
|
7133
|
+
function headingNumbering(numbering, level) {
|
|
7134
|
+
if (numbering === false) return false;
|
|
7135
|
+
if (numbering !== true) return void 0;
|
|
7136
|
+
if (!globalNumberingRegistry.has(HEADING_NUMBERING_REFERENCE)) {
|
|
7137
|
+
globalNumberingRegistry.register(createHeadingNumberingConfig());
|
|
7138
|
+
}
|
|
7139
|
+
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL ? level : 1;
|
|
7140
|
+
return { reference: HEADING_NUMBERING_REFERENCE, level: styleLevel - 1 };
|
|
7141
|
+
}
|
|
7142
|
+
function renderHeadingComponent(component, theme, themeName) {
|
|
7143
|
+
if (!isHeadingComponent(component)) return [];
|
|
7144
|
+
const config = component.props;
|
|
7145
|
+
const bookmarkId = component.id || globalBookmarkRegistry.generateId(config.text, "heading");
|
|
7146
|
+
const header = createHeading(
|
|
7147
|
+
config.text,
|
|
7148
|
+
config.level || 1,
|
|
7149
|
+
theme,
|
|
7150
|
+
themeName,
|
|
7151
|
+
{
|
|
7152
|
+
alignment: config.alignment,
|
|
7153
|
+
spacing: config.spacing,
|
|
7154
|
+
lineSpacing: config.lineSpacing,
|
|
7155
|
+
columnBreak: config.columnBreak,
|
|
7156
|
+
// Local font overrides
|
|
7157
|
+
fontFamily: config.font?.family,
|
|
7158
|
+
fontSize: config.font?.size,
|
|
7159
|
+
fontColor: config.font?.color,
|
|
7160
|
+
bold: config.font?.bold,
|
|
7161
|
+
fontWeight: config.font?.fontWeight,
|
|
7162
|
+
italic: config.font?.italic,
|
|
7163
|
+
underline: config.font?.underline,
|
|
7164
|
+
scale: config.font?.scale,
|
|
7165
|
+
characterSpacing: config.font?.characterSpacing,
|
|
7166
|
+
// Proofing: local language override + no-proof toggle + known-words list
|
|
7167
|
+
language: config.language,
|
|
7168
|
+
noProof: config.noProof,
|
|
7169
|
+
noProofWords: config.noProofWords,
|
|
7170
|
+
// Pagination control
|
|
7171
|
+
keepNext: config.keepNext,
|
|
7172
|
+
keepLines: config.keepLines,
|
|
7173
|
+
// Paragraph indentation (w:ind) in twips
|
|
7174
|
+
indent: config.indent,
|
|
7175
|
+
// Bookmark ID for internal linking
|
|
7176
|
+
bookmarkId,
|
|
7177
|
+
// Auto-numbering (1., 1.1., …) through the shared heading definition
|
|
7178
|
+
numbering: headingNumbering(config.numbering, config.level || 1),
|
|
7179
|
+
// Tracked-change segments (rendered as native Word revisions)
|
|
7180
|
+
revision: config.revision,
|
|
7181
|
+
// Review comment anchored to this heading's text
|
|
7182
|
+
comment: config.comment
|
|
7183
|
+
}
|
|
7184
|
+
);
|
|
7185
|
+
return [header];
|
|
7186
|
+
}
|
|
7187
|
+
|
|
7040
7188
|
// src/components/paragraph.ts
|
|
7041
7189
|
function parseMarkdownList(text) {
|
|
7042
7190
|
const lines = text.split("\n");
|
|
@@ -7176,8 +7324,7 @@ function renderParagraphComponent(component, theme, themeName) {
|
|
|
7176
7324
|
return [text];
|
|
7177
7325
|
}
|
|
7178
7326
|
|
|
7179
|
-
// src/
|
|
7180
|
-
init_colorUtils();
|
|
7327
|
+
// src/utils/listLevels.ts
|
|
7181
7328
|
function createLevelsFromSimplifiedProps(props) {
|
|
7182
7329
|
const levels = [];
|
|
7183
7330
|
let format2;
|
|
@@ -7224,18 +7371,8 @@ function createLevelsFromSimplifiedProps(props) {
|
|
|
7224
7371
|
}
|
|
7225
7372
|
return levels;
|
|
7226
7373
|
}
|
|
7227
|
-
function resolveMarkerFonts(levels, theme) {
|
|
7228
|
-
return levels.map((level) => {
|
|
7229
|
-
const font = level.font;
|
|
7230
|
-
if (!font?.color) return level;
|
|
7231
|
-
return {
|
|
7232
|
-
...level,
|
|
7233
|
-
font: { ...font, color: resolveColor(font.color, theme) }
|
|
7234
|
-
};
|
|
7235
|
-
});
|
|
7236
|
-
}
|
|
7237
7374
|
function applyListStart(levels, start) {
|
|
7238
|
-
if (start === void 0) return levels;
|
|
7375
|
+
if (start === void 0) return [...levels];
|
|
7239
7376
|
return levels.map(
|
|
7240
7377
|
(level) => level.level === 0 && level.start === void 0 ? { ...level, start } : level
|
|
7241
7378
|
);
|
|
@@ -7293,28 +7430,37 @@ function fillMissingLevels(levels, maxLevel) {
|
|
|
7293
7430
|
}
|
|
7294
7431
|
return result;
|
|
7295
7432
|
}
|
|
7433
|
+
function resolveListLevels(props) {
|
|
7434
|
+
const maxLevel = getMaxLevelFromItems(props.items);
|
|
7435
|
+
if (props.levels && props.levels.length > 0) {
|
|
7436
|
+
return fillMissingLevels(
|
|
7437
|
+
applyListStart(props.levels, props.start),
|
|
7438
|
+
maxLevel
|
|
7439
|
+
);
|
|
7440
|
+
}
|
|
7441
|
+
return fillMissingLevels(createLevelsFromSimplifiedProps(props), maxLevel);
|
|
7442
|
+
}
|
|
7443
|
+
|
|
7444
|
+
// src/components/list.ts
|
|
7445
|
+
init_colorUtils();
|
|
7446
|
+
function resolveMarkerFonts(levels, theme) {
|
|
7447
|
+
return levels.map((level) => {
|
|
7448
|
+
const font = level.font;
|
|
7449
|
+
if (!font?.color) return level;
|
|
7450
|
+
return {
|
|
7451
|
+
...level,
|
|
7452
|
+
font: { ...font, color: resolveColor(font.color, theme) }
|
|
7453
|
+
};
|
|
7454
|
+
});
|
|
7455
|
+
}
|
|
7296
7456
|
function renderListComponent(component, theme, themeName) {
|
|
7297
7457
|
if (!isListComponent(component)) return [];
|
|
7298
7458
|
const resolvedConfig = component.props;
|
|
7299
|
-
const maxLevel = getMaxLevelFromItems(resolvedConfig.items);
|
|
7300
7459
|
const reference = resolvedConfig.reference || globalNumberingRegistry.generateReference("list");
|
|
7301
7460
|
if (!globalNumberingRegistry.has(reference)) {
|
|
7302
|
-
let levels;
|
|
7303
|
-
if (resolvedConfig.levels && resolvedConfig.levels.length > 0) {
|
|
7304
|
-
levels = fillMissingLevels(
|
|
7305
|
-
applyListStart(
|
|
7306
|
-
resolvedConfig.levels,
|
|
7307
|
-
resolvedConfig.start
|
|
7308
|
-
),
|
|
7309
|
-
maxLevel
|
|
7310
|
-
);
|
|
7311
|
-
} else {
|
|
7312
|
-
const baseLevels = createLevelsFromSimplifiedProps(resolvedConfig);
|
|
7313
|
-
levels = fillMissingLevels(baseLevels, maxLevel);
|
|
7314
|
-
}
|
|
7315
7461
|
const config = {
|
|
7316
7462
|
reference,
|
|
7317
|
-
levels: resolveMarkerFonts(
|
|
7463
|
+
levels: resolveMarkerFonts(resolveListLevels(resolvedConfig), theme)
|
|
7318
7464
|
};
|
|
7319
7465
|
const numberingConfig = createNumberingConfig(config);
|
|
7320
7466
|
globalNumberingRegistry.register(numberingConfig);
|
|
@@ -7354,6 +7500,7 @@ async function renderImageComponent(component, theme, themeName) {
|
|
|
7354
7500
|
|
|
7355
7501
|
// src/components/text-box.ts
|
|
7356
7502
|
import {
|
|
7503
|
+
Paragraph as Paragraph5,
|
|
7357
7504
|
Table as Table3,
|
|
7358
7505
|
TableRow as TableRow2,
|
|
7359
7506
|
TableCell as TableCell2,
|
|
@@ -7362,7 +7509,8 @@ import {
|
|
|
7362
7509
|
RelativeHorizontalPosition,
|
|
7363
7510
|
RelativeVerticalPosition,
|
|
7364
7511
|
OverlapType,
|
|
7365
|
-
TableLayoutType as TableLayoutType2
|
|
7512
|
+
TableLayoutType as TableLayoutType2,
|
|
7513
|
+
WpsShapeRun
|
|
7366
7514
|
} from "docx";
|
|
7367
7515
|
|
|
7368
7516
|
// src/styles/utils/borderUtils.ts
|
|
@@ -7439,6 +7587,8 @@ function buildCellOptions(children, styleCfg, theme) {
|
|
|
7439
7587
|
}
|
|
7440
7588
|
|
|
7441
7589
|
// src/components/text-box.ts
|
|
7590
|
+
init_colorUtils();
|
|
7591
|
+
init_docxImagePositioning();
|
|
7442
7592
|
init_widthUtils();
|
|
7443
7593
|
function mapTableFloatOptions(floating, theme, themeName) {
|
|
7444
7594
|
if (!floating) return void 0;
|
|
@@ -7494,26 +7644,23 @@ function mapTableFloatOptions(floating, theme, themeName) {
|
|
|
7494
7644
|
opt.overlap = OverlapType.OVERLAP;
|
|
7495
7645
|
return opt;
|
|
7496
7646
|
}
|
|
7497
|
-
async function
|
|
7498
|
-
|
|
7499
|
-
|
|
7647
|
+
async function renderTextBoxChildren(tb, theme, themeName, context) {
|
|
7648
|
+
const childContext = {
|
|
7649
|
+
...context,
|
|
7650
|
+
parent: tb
|
|
7651
|
+
};
|
|
7652
|
+
const rendered = [];
|
|
7653
|
+
for (const child of tb.children || []) {
|
|
7654
|
+
rendered.push(
|
|
7655
|
+
...await renderComponent(child, theme, themeName, childContext)
|
|
7656
|
+
);
|
|
7657
|
+
}
|
|
7658
|
+
return rendered;
|
|
7659
|
+
}
|
|
7660
|
+
async function renderTextBoxAsTable(tb, theme, themeName, _context, prerendered) {
|
|
7500
7661
|
const isInline = !tb.props.floating;
|
|
7501
|
-
const childComponents = tb.children || [];
|
|
7502
7662
|
if (isInline) {
|
|
7503
|
-
const cellChildren2 =
|
|
7504
|
-
const childContext2 = {
|
|
7505
|
-
..._context,
|
|
7506
|
-
parent: tb
|
|
7507
|
-
};
|
|
7508
|
-
for (const child of childComponents) {
|
|
7509
|
-
const rendered = await renderComponent(
|
|
7510
|
-
child,
|
|
7511
|
-
theme,
|
|
7512
|
-
themeName,
|
|
7513
|
-
childContext2
|
|
7514
|
-
);
|
|
7515
|
-
cellChildren2.push(...rendered);
|
|
7516
|
-
}
|
|
7663
|
+
const cellChildren2 = prerendered ?? await renderTextBoxChildren(tb, theme, themeName, _context);
|
|
7517
7664
|
const styleCfg2 = tb.props.style;
|
|
7518
7665
|
const cellOpts2 = buildCellOptions(cellChildren2, styleCfg2, theme);
|
|
7519
7666
|
const row2 = new TableRow2({ children: [new TableCell2(cellOpts2)] });
|
|
@@ -7526,20 +7673,7 @@ async function renderTextBoxComponent(component, theme, themeName, _context) {
|
|
|
7526
7673
|
});
|
|
7527
7674
|
return [table2];
|
|
7528
7675
|
}
|
|
7529
|
-
const cellChildren =
|
|
7530
|
-
const childContext = {
|
|
7531
|
-
..._context,
|
|
7532
|
-
parent: tb
|
|
7533
|
-
};
|
|
7534
|
-
for (const child of childComponents) {
|
|
7535
|
-
const rendered = await renderComponent(
|
|
7536
|
-
child,
|
|
7537
|
-
theme,
|
|
7538
|
-
themeName,
|
|
7539
|
-
childContext
|
|
7540
|
-
);
|
|
7541
|
-
cellChildren.push(...rendered);
|
|
7542
|
-
}
|
|
7676
|
+
const cellChildren = prerendered ?? await renderTextBoxChildren(tb, theme, themeName, _context);
|
|
7543
7677
|
const styleCfg = tb.props.style;
|
|
7544
7678
|
const cellOpts = buildCellOptions(cellChildren, styleCfg, theme);
|
|
7545
7679
|
const row = new TableRow2({
|
|
@@ -7571,6 +7705,162 @@ async function renderTextBoxComponent(component, theme, themeName, _context) {
|
|
|
7571
7705
|
});
|
|
7572
7706
|
return [table];
|
|
7573
7707
|
}
|
|
7708
|
+
var PIXELS_TO_EMU = 9525;
|
|
7709
|
+
var TWIPS_PER_PIXEL = 15;
|
|
7710
|
+
function resolveShapeSize(value, axis, theme, themeName) {
|
|
7711
|
+
if (typeof value === "number") {
|
|
7712
|
+
return { pixels: Math.round(value), resolvedPercentage: false };
|
|
7713
|
+
}
|
|
7714
|
+
if (typeof value !== "string") return { resolvedPercentage: false };
|
|
7715
|
+
const fraction = parseFloat(value) / 100;
|
|
7716
|
+
if (!Number.isFinite(fraction) || fraction <= 0) {
|
|
7717
|
+
return { resolvedPercentage: false };
|
|
7718
|
+
}
|
|
7719
|
+
const availableTwips = axis === "width" ? getAvailableWidthTwips(theme, themeName) : getAvailableHeightTwips(theme, themeName);
|
|
7720
|
+
return {
|
|
7721
|
+
pixels: Math.round(availableTwips * fraction / TWIPS_PER_PIXEL),
|
|
7722
|
+
resolvedPercentage: true
|
|
7723
|
+
};
|
|
7724
|
+
}
|
|
7725
|
+
function shapeColor(value, theme) {
|
|
7726
|
+
return resolveColor(value, theme).replace(/^#/, "");
|
|
7727
|
+
}
|
|
7728
|
+
function shapeOutline(style, theme) {
|
|
7729
|
+
const border = style?.border;
|
|
7730
|
+
if (!border) return { ignoredSides: [], unsupportedStyles: [] };
|
|
7731
|
+
const order = [
|
|
7732
|
+
"top",
|
|
7733
|
+
"left",
|
|
7734
|
+
"bottom",
|
|
7735
|
+
"right"
|
|
7736
|
+
];
|
|
7737
|
+
const declared = order.map((side) => [side, border[side]]).filter(
|
|
7738
|
+
(entry) => Boolean(entry[1])
|
|
7739
|
+
);
|
|
7740
|
+
if (declared.length === 0) return { ignoredSides: [], unsupportedStyles: [] };
|
|
7741
|
+
const unsupportedStyles = [
|
|
7742
|
+
...new Set(
|
|
7743
|
+
declared.map(([, config]) => config.style).filter(
|
|
7744
|
+
(value) => value === "dashed" || value === "dotted" || value === "double"
|
|
7745
|
+
)
|
|
7746
|
+
)
|
|
7747
|
+
];
|
|
7748
|
+
if (unsupportedStyles.length > 0) {
|
|
7749
|
+
return { ignoredSides: [], unsupportedStyles };
|
|
7750
|
+
}
|
|
7751
|
+
const [, used] = declared[0];
|
|
7752
|
+
const differs = ({ style: s, width, color }) => s !== used.style || width !== used.width || color !== used.color;
|
|
7753
|
+
const ignoredSides = declared.slice(1).filter(([, config]) => differs(config)).map(([side]) => side);
|
|
7754
|
+
if (used.style === "none") return { ignoredSides, unsupportedStyles };
|
|
7755
|
+
return {
|
|
7756
|
+
outline: {
|
|
7757
|
+
type: "solidFill",
|
|
7758
|
+
solidFillType: "rgb",
|
|
7759
|
+
value: used.color ? shapeColor(used.color, theme) : "000000",
|
|
7760
|
+
...used.width !== void 0 && {
|
|
7761
|
+
width: Math.round(used.width * PIXELS_TO_EMU)
|
|
7762
|
+
}
|
|
7763
|
+
},
|
|
7764
|
+
ignoredSides,
|
|
7765
|
+
unsupportedStyles
|
|
7766
|
+
};
|
|
7767
|
+
}
|
|
7768
|
+
function shapeBodyProperties(style) {
|
|
7769
|
+
const padding = style?.padding;
|
|
7770
|
+
if (!padding) return void 0;
|
|
7771
|
+
const toEmu = (value) => value === void 0 ? void 0 : Math.round(value * PIXELS_TO_EMU);
|
|
7772
|
+
return {
|
|
7773
|
+
margins: {
|
|
7774
|
+
...padding.top !== void 0 && { top: toEmu(padding.top) },
|
|
7775
|
+
...padding.bottom !== void 0 && { bottom: toEmu(padding.bottom) },
|
|
7776
|
+
...padding.left !== void 0 && { left: toEmu(padding.left) },
|
|
7777
|
+
...padding.right !== void 0 && { right: toEmu(padding.right) }
|
|
7778
|
+
}
|
|
7779
|
+
};
|
|
7780
|
+
}
|
|
7781
|
+
async function renderTextBoxAsShape(tb, theme, themeName, context) {
|
|
7782
|
+
const width = resolveShapeSize(tb.props.width, "width", theme, themeName);
|
|
7783
|
+
const height = resolveShapeSize(tb.props.height, "height", theme, themeName);
|
|
7784
|
+
if (width.pixels === void 0 || height.pixels === void 0) {
|
|
7785
|
+
console.warn(
|
|
7786
|
+
'[core-docx] text-box renderAs "shape" needs an explicit width and height (a shape has no autofit); falling back to table rendering.'
|
|
7787
|
+
);
|
|
7788
|
+
return { kind: "fallback" };
|
|
7789
|
+
}
|
|
7790
|
+
const style = tb.props.style;
|
|
7791
|
+
const { outline, ignoredSides, unsupportedStyles } = shapeOutline(
|
|
7792
|
+
style,
|
|
7793
|
+
theme
|
|
7794
|
+
);
|
|
7795
|
+
if (unsupportedStyles.length > 0) {
|
|
7796
|
+
console.warn(
|
|
7797
|
+
`[core-docx] text-box renderAs "shape" cannot draw a ${unsupportedStyles.join("/")} border (a shape outline has no dash pattern); falling back to table rendering, which draws it.`
|
|
7798
|
+
);
|
|
7799
|
+
return { kind: "fallback" };
|
|
7800
|
+
}
|
|
7801
|
+
const rendered = await renderTextBoxChildren(tb, theme, themeName, context);
|
|
7802
|
+
if (rendered.some((element) => !(element instanceof Paragraph5))) {
|
|
7803
|
+
console.warn(
|
|
7804
|
+
'[core-docx] text-box renderAs "shape" requires paragraph-only content; falling back to table rendering.'
|
|
7805
|
+
);
|
|
7806
|
+
return { kind: "fallback", rendered };
|
|
7807
|
+
}
|
|
7808
|
+
const children = rendered;
|
|
7809
|
+
if (width.resolvedPercentage || height.resolvedPercentage) {
|
|
7810
|
+
console.warn(
|
|
7811
|
+
'[core-docx] text-box renderAs "shape" resolves percentage sizes at generation time, against the current page content box; the shape will not reflow if the page size changes.'
|
|
7812
|
+
);
|
|
7813
|
+
}
|
|
7814
|
+
const fill = style?.shading?.fill;
|
|
7815
|
+
if (ignoredSides.length > 0) {
|
|
7816
|
+
console.warn(
|
|
7817
|
+
`[core-docx] text-box renderAs "shape" has one uniform outline; using the first declared border side and ignoring ${ignoredSides.join(", ")}.`
|
|
7818
|
+
);
|
|
7819
|
+
}
|
|
7820
|
+
const dropOutline = Boolean(fill) && Boolean(outline);
|
|
7821
|
+
if (dropOutline) {
|
|
7822
|
+
console.warn(
|
|
7823
|
+
'[core-docx] text-box renderAs "shape" cannot carry a fill and a border at once (docx emits invalid shape properties); keeping the fill and dropping the border.'
|
|
7824
|
+
);
|
|
7825
|
+
}
|
|
7826
|
+
const bodyProperties = shapeBodyProperties(style);
|
|
7827
|
+
const run = new WpsShapeRun({
|
|
7828
|
+
type: "wps",
|
|
7829
|
+
children,
|
|
7830
|
+
transformation: { width: width.pixels, height: height.pixels },
|
|
7831
|
+
...fill && {
|
|
7832
|
+
solidFill: { type: "rgb", value: shapeColor(fill, theme) }
|
|
7833
|
+
},
|
|
7834
|
+
...outline && !dropOutline && { outline },
|
|
7835
|
+
...bodyProperties && { bodyProperties },
|
|
7836
|
+
// Absent `floating` makes it a `wp:inline` drawing.
|
|
7837
|
+
...tb.props.floating && {
|
|
7838
|
+
floating: mapFloatingOptions(tb.props.floating, theme, themeName)
|
|
7839
|
+
}
|
|
7840
|
+
});
|
|
7841
|
+
return {
|
|
7842
|
+
kind: "shape",
|
|
7843
|
+
paragraphs: [
|
|
7844
|
+
new Paragraph5({ children: [run], spacing: { before: 0, after: 0 } })
|
|
7845
|
+
]
|
|
7846
|
+
};
|
|
7847
|
+
}
|
|
7848
|
+
async function renderTextBoxComponent(component, theme, themeName, context) {
|
|
7849
|
+
if (!isTextBoxComponent(component)) return [];
|
|
7850
|
+
const tb = component;
|
|
7851
|
+
if (tb.props.renderAs === "shape") {
|
|
7852
|
+
const attempt = await renderTextBoxAsShape(tb, theme, themeName, context);
|
|
7853
|
+
if (attempt.kind === "shape") return attempt.paragraphs;
|
|
7854
|
+
return renderTextBoxAsTable(
|
|
7855
|
+
tb,
|
|
7856
|
+
theme,
|
|
7857
|
+
themeName,
|
|
7858
|
+
context,
|
|
7859
|
+
attempt.rendered
|
|
7860
|
+
);
|
|
7861
|
+
}
|
|
7862
|
+
return renderTextBoxAsTable(tb, theme, themeName, context);
|
|
7863
|
+
}
|
|
7574
7864
|
|
|
7575
7865
|
// src/components/table.ts
|
|
7576
7866
|
async function renderTableComponent(component, theme, themeName) {
|
|
@@ -7624,14 +7914,14 @@ async function renderTableComponent(component, theme, themeName) {
|
|
|
7624
7914
|
import { Paragraph as Paragraph6, BookmarkStart, BookmarkEnd } from "docx";
|
|
7625
7915
|
|
|
7626
7916
|
// src/core/sectionBookmarks.ts
|
|
7627
|
-
import { AsyncLocalStorage as
|
|
7917
|
+
import { AsyncLocalStorage as AsyncLocalStorage8 } from "async_hooks";
|
|
7628
7918
|
var NESTED_LINK_ID_BASE = 1e6;
|
|
7629
7919
|
function createState3() {
|
|
7630
7920
|
return { nextNested: 1, resolved: /* @__PURE__ */ new WeakMap() };
|
|
7631
7921
|
}
|
|
7632
7922
|
var SectionBookmarkRegistry = class {
|
|
7633
7923
|
fallback = createState3();
|
|
7634
|
-
scopes = new
|
|
7924
|
+
scopes = new AsyncLocalStorage8();
|
|
7635
7925
|
get state() {
|
|
7636
7926
|
return this.scopes.getStore() ?? this.fallback;
|
|
7637
7927
|
}
|
|
@@ -7889,7 +8179,10 @@ function selectCachedEntries(collected, options) {
|
|
|
7889
8179
|
continue;
|
|
7890
8180
|
}
|
|
7891
8181
|
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
7892
|
-
entries.push({
|
|
8182
|
+
entries.push({
|
|
8183
|
+
title: entry.number ? `${headingNumberLabel(entry.number)} ${entry.title}` : entry.title,
|
|
8184
|
+
level: entry.level
|
|
8185
|
+
});
|
|
7893
8186
|
}
|
|
7894
8187
|
return entries;
|
|
7895
8188
|
}
|
|
@@ -8197,6 +8490,61 @@ function computeSectionOrdinals(sections) {
|
|
|
8197
8490
|
|
|
8198
8491
|
// src/core/collectTocHeadings.ts
|
|
8199
8492
|
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
8493
|
+
|
|
8494
|
+
// src/utils/numberFormatting.ts
|
|
8495
|
+
var ROMAN_NUMERALS = [
|
|
8496
|
+
[1e3, "m"],
|
|
8497
|
+
[900, "cm"],
|
|
8498
|
+
[500, "d"],
|
|
8499
|
+
[400, "cd"],
|
|
8500
|
+
[100, "c"],
|
|
8501
|
+
[90, "xc"],
|
|
8502
|
+
[50, "l"],
|
|
8503
|
+
[40, "xl"],
|
|
8504
|
+
[10, "x"],
|
|
8505
|
+
[9, "ix"],
|
|
8506
|
+
[5, "v"],
|
|
8507
|
+
[4, "iv"],
|
|
8508
|
+
[1, "i"]
|
|
8509
|
+
];
|
|
8510
|
+
function toRoman(value) {
|
|
8511
|
+
let remaining = value;
|
|
8512
|
+
let out = "";
|
|
8513
|
+
for (const [amount, glyph] of ROMAN_NUMERALS) {
|
|
8514
|
+
while (remaining >= amount) {
|
|
8515
|
+
out += glyph;
|
|
8516
|
+
remaining -= amount;
|
|
8517
|
+
}
|
|
8518
|
+
}
|
|
8519
|
+
return out;
|
|
8520
|
+
}
|
|
8521
|
+
function toLetters(value) {
|
|
8522
|
+
const index = (value - 1) % 26;
|
|
8523
|
+
const repeats = Math.floor((value - 1) / 26) + 1;
|
|
8524
|
+
return String.fromCharCode(97 + index).repeat(repeats);
|
|
8525
|
+
}
|
|
8526
|
+
function formatNumberForLevel(value, format2) {
|
|
8527
|
+
if (!Number.isFinite(value) || value < 1) return void 0;
|
|
8528
|
+
const n = Math.floor(value);
|
|
8529
|
+
switch (format2) {
|
|
8530
|
+
case "decimal":
|
|
8531
|
+
return String(n);
|
|
8532
|
+
case "lowerLetter":
|
|
8533
|
+
return toLetters(n);
|
|
8534
|
+
case "upperLetter":
|
|
8535
|
+
return toLetters(n).toUpperCase();
|
|
8536
|
+
case "lowerRoman":
|
|
8537
|
+
return toRoman(n);
|
|
8538
|
+
case "upperRoman":
|
|
8539
|
+
return toRoman(n).toUpperCase();
|
|
8540
|
+
default:
|
|
8541
|
+
return void 0;
|
|
8542
|
+
}
|
|
8543
|
+
}
|
|
8544
|
+
|
|
8545
|
+
// src/core/collectTocHeadings.ts
|
|
8546
|
+
var MAX_HEADING_LEVEL2 = 6;
|
|
8547
|
+
var MAX_LIST_LEVEL = 9;
|
|
8200
8548
|
function normalizeEntryTitle(text) {
|
|
8201
8549
|
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
8202
8550
|
}
|
|
@@ -8215,9 +8563,97 @@ function styleEntryKey(props) {
|
|
|
8215
8563
|
}
|
|
8216
8564
|
return themeStyle;
|
|
8217
8565
|
}
|
|
8218
|
-
function
|
|
8566
|
+
function levelStart(levels, level) {
|
|
8567
|
+
return levels[level]?.start ?? 1;
|
|
8568
|
+
}
|
|
8569
|
+
function collectDocumentOutline(sections) {
|
|
8219
8570
|
const entries = [];
|
|
8571
|
+
const numberedItems = /* @__PURE__ */ new Map();
|
|
8220
8572
|
const ordinals = computeSectionOrdinals(sections);
|
|
8573
|
+
const takenIds = /* @__PURE__ */ new Set();
|
|
8574
|
+
const headingCounters = new Array(MAX_HEADING_LEVEL2).fill(0);
|
|
8575
|
+
const listCounters = /* @__PURE__ */ new Map();
|
|
8576
|
+
const visitHeading = (component, props, sectionBookmarkId) => {
|
|
8577
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
8578
|
+
const title = normalizeEntryTitle(text);
|
|
8579
|
+
const level = typeof props.level === "number" ? props.level : 1;
|
|
8580
|
+
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL2 ? level : 1;
|
|
8581
|
+
let full;
|
|
8582
|
+
let own;
|
|
8583
|
+
if (props.numbering === true) {
|
|
8584
|
+
headingCounters[styleLevel - 1] += 1;
|
|
8585
|
+
for (let deeper = styleLevel; deeper < MAX_HEADING_LEVEL2; deeper++) {
|
|
8586
|
+
headingCounters[deeper] = 0;
|
|
8587
|
+
}
|
|
8588
|
+
full = headingCounters.slice(0, styleLevel).join(".");
|
|
8589
|
+
own = String(headingCounters[styleLevel - 1]);
|
|
8590
|
+
}
|
|
8591
|
+
const explicitId = component.id;
|
|
8592
|
+
const bookmarkId = typeof explicitId === "string" && explicitId ? explicitId : dedupeBookmarkId(slugifyBookmarkText(text), (id) => takenIds.has(id));
|
|
8593
|
+
takenIds.add(bookmarkId);
|
|
8594
|
+
numberedItems.set(bookmarkId, {
|
|
8595
|
+
kind: "heading",
|
|
8596
|
+
text: title,
|
|
8597
|
+
...full !== void 0 && { full, own }
|
|
8598
|
+
});
|
|
8599
|
+
if (title) {
|
|
8600
|
+
entries.push({
|
|
8601
|
+
title,
|
|
8602
|
+
level,
|
|
8603
|
+
sectionBookmarkId,
|
|
8604
|
+
...full !== void 0 && { number: full }
|
|
8605
|
+
});
|
|
8606
|
+
}
|
|
8607
|
+
};
|
|
8608
|
+
const visitList = (props) => {
|
|
8609
|
+
const items = Array.isArray(props.items) ? props.items : [];
|
|
8610
|
+
if (items.length === 0) return;
|
|
8611
|
+
const reference = typeof props.reference === "string" && props.reference ? props.reference : void 0;
|
|
8612
|
+
const freshState = () => {
|
|
8613
|
+
const levels = resolveListLevels(
|
|
8614
|
+
props
|
|
8615
|
+
);
|
|
8616
|
+
return {
|
|
8617
|
+
levels,
|
|
8618
|
+
counters: Array.from(
|
|
8619
|
+
{ length: MAX_LIST_LEVEL },
|
|
8620
|
+
(_, level) => levelStart(levels, level) - 1
|
|
8621
|
+
)
|
|
8622
|
+
};
|
|
8623
|
+
};
|
|
8624
|
+
let state;
|
|
8625
|
+
if (reference === void 0) {
|
|
8626
|
+
state = freshState();
|
|
8627
|
+
} else {
|
|
8628
|
+
state = listCounters.get(reference) ?? freshState();
|
|
8629
|
+
listCounters.set(reference, state);
|
|
8630
|
+
}
|
|
8631
|
+
for (const item of items) {
|
|
8632
|
+
const isObject = typeof item === "object" && item !== null;
|
|
8633
|
+
const raw = isObject ? item.text : item;
|
|
8634
|
+
const text = typeof raw === "string" ? raw : "";
|
|
8635
|
+
if (!text.trim() && !(isObject && item.revision)) continue;
|
|
8636
|
+
const rawLevel = isObject ? item.level : void 0;
|
|
8637
|
+
const level = typeof rawLevel === "number" && rawLevel >= 0 ? rawLevel : 0;
|
|
8638
|
+
if (level >= MAX_LIST_LEVEL) continue;
|
|
8639
|
+
state.counters[level] += 1;
|
|
8640
|
+
for (let deeper = level + 1; deeper < MAX_LIST_LEVEL; deeper++) {
|
|
8641
|
+
state.counters[deeper] = levelStart(state.levels, deeper) - 1;
|
|
8642
|
+
}
|
|
8643
|
+
const id = isObject ? item.id : void 0;
|
|
8644
|
+
if (typeof id !== "string" || !id) continue;
|
|
8645
|
+
takenIds.add(id);
|
|
8646
|
+
const number = formatNumberForLevel(
|
|
8647
|
+
state.counters[level],
|
|
8648
|
+
state.levels[level]?.format
|
|
8649
|
+
);
|
|
8650
|
+
numberedItems.set(id, {
|
|
8651
|
+
kind: "list-item",
|
|
8652
|
+
text: normalizeUnicodeText(text).trim(),
|
|
8653
|
+
...number !== void 0 && { full: number, own: number }
|
|
8654
|
+
});
|
|
8655
|
+
}
|
|
8656
|
+
};
|
|
8221
8657
|
sections.forEach((section, index) => {
|
|
8222
8658
|
const ordinal = ordinals[index]?.ordinal;
|
|
8223
8659
|
const sectionBookmarkId = ordinal ? globalSectionBookmarkRegistry.forLayoutSection(ordinal).id : void 0;
|
|
@@ -8225,15 +8661,11 @@ function collectTocHeadings(sections) {
|
|
|
8225
8661
|
if (!isEnabled(component)) return;
|
|
8226
8662
|
const props = component.props ?? {};
|
|
8227
8663
|
if (component.name === "heading") {
|
|
8228
|
-
|
|
8229
|
-
const title = normalizeEntryTitle(text);
|
|
8230
|
-
if (title) {
|
|
8231
|
-
const level = typeof props.level === "number" ? props.level : 1;
|
|
8232
|
-
entries.push({ title, level, sectionBookmarkId });
|
|
8233
|
-
}
|
|
8664
|
+
visitHeading(component, props, sectionBookmarkId);
|
|
8234
8665
|
return;
|
|
8235
8666
|
}
|
|
8236
8667
|
if (component.name === "paragraph") {
|
|
8668
|
+
if (typeof props.id === "string" && props.id) takenIds.add(props.id);
|
|
8237
8669
|
const styleId = styleEntryKey(props);
|
|
8238
8670
|
const text = typeof props.text === "string" ? props.text : "";
|
|
8239
8671
|
const title = normalizeEntryTitle(text);
|
|
@@ -8242,13 +8674,17 @@ function collectTocHeadings(sections) {
|
|
|
8242
8674
|
}
|
|
8243
8675
|
return;
|
|
8244
8676
|
}
|
|
8677
|
+
if (component.name === "list") {
|
|
8678
|
+
visitList(props);
|
|
8679
|
+
return;
|
|
8680
|
+
}
|
|
8245
8681
|
if (!isContainer(component.name)) return;
|
|
8246
8682
|
const children = component.children;
|
|
8247
8683
|
if (Array.isArray(children)) children.forEach(visit);
|
|
8248
8684
|
};
|
|
8249
8685
|
section.components.forEach(visit);
|
|
8250
8686
|
});
|
|
8251
|
-
return entries;
|
|
8687
|
+
return { entries, numberedItems };
|
|
8252
8688
|
}
|
|
8253
8689
|
|
|
8254
8690
|
// src/core/render.ts
|
|
@@ -8301,7 +8737,13 @@ async function renderDocument(structure, layout, options) {
|
|
|
8301
8737
|
// Footnote ids are document-scoped too: a reference resolved
|
|
8302
8738
|
// against another render's counter points at the wrong body.
|
|
8303
8739
|
globalNoteRegistry.runScoped(
|
|
8304
|
-
() =>
|
|
8740
|
+
() => (
|
|
8741
|
+
// Cross-reference targets are keyed by bookmark id, which
|
|
8742
|
+
// is only unique within one document.
|
|
8743
|
+
globalNumberedItemsRegistry.runScoped(
|
|
8744
|
+
() => renderDocumentScoped(structure, layout, options)
|
|
8745
|
+
)
|
|
8746
|
+
)
|
|
8305
8747
|
)
|
|
8306
8748
|
)
|
|
8307
8749
|
)
|
|
@@ -8344,13 +8786,14 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
8344
8786
|
);
|
|
8345
8787
|
}
|
|
8346
8788
|
try {
|
|
8347
|
-
const
|
|
8348
|
-
if (
|
|
8349
|
-
context.tocHeadings =
|
|
8789
|
+
const outline = collectDocumentOutline(layout.sections);
|
|
8790
|
+
if (outline.entries.length > 0) {
|
|
8791
|
+
context.tocHeadings = outline.entries;
|
|
8350
8792
|
}
|
|
8793
|
+
globalNumberedItemsRegistry.seed(outline.numberedItems);
|
|
8351
8794
|
} catch (error) {
|
|
8352
8795
|
console.warn(
|
|
8353
|
-
"[core-docx]
|
|
8796
|
+
"[core-docx] Document outline collection failed; the TOC field will rely on the reader refreshing it:",
|
|
8354
8797
|
error instanceof Error ? error.message : error
|
|
8355
8798
|
);
|
|
8356
8799
|
}
|