@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
package/dist/index.js
CHANGED
|
@@ -383,9 +383,6 @@ var init_minimal_docx_theme = __esm({
|
|
|
383
383
|
},
|
|
384
384
|
section: {
|
|
385
385
|
pageBreak: false
|
|
386
|
-
},
|
|
387
|
-
heading: {
|
|
388
|
-
numbering: false
|
|
389
386
|
}
|
|
390
387
|
}
|
|
391
388
|
};
|
|
@@ -508,9 +505,6 @@ var init_corporate_docx_theme = __esm({
|
|
|
508
505
|
},
|
|
509
506
|
section: {
|
|
510
507
|
pageBreak: false
|
|
511
|
-
},
|
|
512
|
-
heading: {
|
|
513
|
-
numbering: false
|
|
514
508
|
}
|
|
515
509
|
}
|
|
516
510
|
};
|
|
@@ -753,9 +747,6 @@ var init_apex_docx_theme = __esm({
|
|
|
753
747
|
},
|
|
754
748
|
section: {
|
|
755
749
|
pageBreak: false
|
|
756
|
-
},
|
|
757
|
-
heading: {
|
|
758
|
-
numbering: false
|
|
759
750
|
}
|
|
760
751
|
}
|
|
761
752
|
};
|
|
@@ -889,9 +880,6 @@ var init_devportal_docx_theme = __esm({
|
|
|
889
880
|
},
|
|
890
881
|
section: {
|
|
891
882
|
pageBreak: false
|
|
892
|
-
},
|
|
893
|
-
heading: {
|
|
894
|
-
numbering: false
|
|
895
883
|
}
|
|
896
884
|
}
|
|
897
885
|
};
|
|
@@ -3752,8 +3740,51 @@ import {
|
|
|
3752
3740
|
InternalHyperlink,
|
|
3753
3741
|
FootnoteReferenceRun,
|
|
3754
3742
|
EndnoteReferenceRun,
|
|
3743
|
+
NumberedItemReference,
|
|
3744
|
+
NumberedItemReferenceFormat,
|
|
3755
3745
|
Tab
|
|
3756
3746
|
} from "docx";
|
|
3747
|
+
|
|
3748
|
+
// src/utils/numberedItemsRegistry.ts
|
|
3749
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
3750
|
+
var NumberedItemsRegistry = class {
|
|
3751
|
+
fallback = {
|
|
3752
|
+
items: /* @__PURE__ */ new Map(),
|
|
3753
|
+
seeded: false
|
|
3754
|
+
};
|
|
3755
|
+
scopes = new AsyncLocalStorage2();
|
|
3756
|
+
get state() {
|
|
3757
|
+
return this.scopes.getStore() ?? this.fallback;
|
|
3758
|
+
}
|
|
3759
|
+
/** Run work with an isolated registry that follows its async call chain. */
|
|
3760
|
+
runScoped(callback) {
|
|
3761
|
+
return this.scopes.run({ items: /* @__PURE__ */ new Map(), seeded: false }, callback);
|
|
3762
|
+
}
|
|
3763
|
+
/** Replace the contents with the pre-pass result. */
|
|
3764
|
+
seed(items) {
|
|
3765
|
+
const state = this.state;
|
|
3766
|
+
state.items = new Map(items);
|
|
3767
|
+
state.seeded = true;
|
|
3768
|
+
}
|
|
3769
|
+
/**
|
|
3770
|
+
* False outside a render (a unit test calling `createText` directly). An
|
|
3771
|
+
* unresolved reference is then expected rather than an authoring mistake, so
|
|
3772
|
+
* the caller stays quiet about it.
|
|
3773
|
+
*/
|
|
3774
|
+
isSeeded() {
|
|
3775
|
+
return this.state.seeded;
|
|
3776
|
+
}
|
|
3777
|
+
get(id) {
|
|
3778
|
+
return this.state.items.get(id);
|
|
3779
|
+
}
|
|
3780
|
+
clear() {
|
|
3781
|
+
this.state.items.clear();
|
|
3782
|
+
this.state.seeded = false;
|
|
3783
|
+
}
|
|
3784
|
+
};
|
|
3785
|
+
var globalNumberedItemsRegistry = new NumberedItemsRegistry();
|
|
3786
|
+
|
|
3787
|
+
// src/utils/textParser.ts
|
|
3757
3788
|
var FOOTNOTE_MARKER_REGEX = /\[\^([^\]\s]+)\]/;
|
|
3758
3789
|
function escapeRegExp(s) {
|
|
3759
3790
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -3969,13 +4000,59 @@ function splitNoteMarkers(text, noteRef, runs) {
|
|
|
3969
4000
|
if (trailing) out.push(...runs(trailing));
|
|
3970
4001
|
return out;
|
|
3971
4002
|
}
|
|
4003
|
+
var CROSS_REFERENCE_PATTERN = "\\[@([^\\]\\s:]+)(?::(relative|no_context|full_context|none))?\\]";
|
|
4004
|
+
var INLINE_TOKEN_REGEX = `\\[([^\\]]+)\\]\\(([^)]+)\\)|${CROSS_REFERENCE_PATTERN}`;
|
|
4005
|
+
function hasCrossReference(text) {
|
|
4006
|
+
return new RegExp(CROSS_REFERENCE_PATTERN).test(text);
|
|
4007
|
+
}
|
|
4008
|
+
var REFERENCE_FORMATS = {
|
|
4009
|
+
relative: NumberedItemReferenceFormat.RELATIVE,
|
|
4010
|
+
no_context: NumberedItemReferenceFormat.NO_CONTEXT,
|
|
4011
|
+
full_context: NumberedItemReferenceFormat.FULL_CONTEXT,
|
|
4012
|
+
none: NumberedItemReferenceFormat.NONE
|
|
4013
|
+
};
|
|
4014
|
+
function createCrossReference(id, format2, token, baseStyle, options) {
|
|
4015
|
+
const info = globalNumberedItemsRegistry.get(id);
|
|
4016
|
+
if (!info) {
|
|
4017
|
+
if (globalNumberedItemsRegistry.isSeeded()) {
|
|
4018
|
+
console.warn(
|
|
4019
|
+
`[core-docx] Cross-reference ${token} has no target: no heading or list item declares the id "${id}". Rendering the token as literal text.`
|
|
4020
|
+
);
|
|
4021
|
+
}
|
|
4022
|
+
return buildTextRuns(
|
|
4023
|
+
token,
|
|
4024
|
+
buildRunCommonProps(baseStyle, { boldColor: options.boldColor }),
|
|
4025
|
+
{ noProof: baseStyle.noProof, noProofWords: options.noProofWords }
|
|
4026
|
+
);
|
|
4027
|
+
}
|
|
4028
|
+
if (format2 === "none") {
|
|
4029
|
+
return [
|
|
4030
|
+
new NumberedItemReference(id, info.text, {
|
|
4031
|
+
hyperlink: true,
|
|
4032
|
+
referenceFormat: REFERENCE_FORMATS.none
|
|
4033
|
+
})
|
|
4034
|
+
];
|
|
4035
|
+
}
|
|
4036
|
+
const cachedValue = format2 === "no_context" ? info.own : info.full;
|
|
4037
|
+
if (cachedValue === void 0) {
|
|
4038
|
+
console.warn(
|
|
4039
|
+
`[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.`
|
|
4040
|
+
);
|
|
4041
|
+
}
|
|
4042
|
+
return [
|
|
4043
|
+
new NumberedItemReference(id, cachedValue, {
|
|
4044
|
+
hyperlink: true,
|
|
4045
|
+
referenceFormat: REFERENCE_FORMATS[format2]
|
|
4046
|
+
})
|
|
4047
|
+
];
|
|
4048
|
+
}
|
|
3972
4049
|
function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
3973
4050
|
const normalizedText = normalizeUnicodeText(text);
|
|
3974
4051
|
const runs = [];
|
|
3975
|
-
const
|
|
4052
|
+
const tokenRegex = new RegExp(INLINE_TOKEN_REGEX, "g");
|
|
3976
4053
|
let lastIndex = 0;
|
|
3977
4054
|
let match;
|
|
3978
|
-
while ((match =
|
|
4055
|
+
while ((match = tokenRegex.exec(normalizedText)) !== null) {
|
|
3979
4056
|
if (match.index > lastIndex) {
|
|
3980
4057
|
const plainText = normalizedText.substring(lastIndex, match.index);
|
|
3981
4058
|
if (plainText) {
|
|
@@ -3987,6 +4064,19 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3987
4064
|
runs.push(...plainRuns);
|
|
3988
4065
|
}
|
|
3989
4066
|
}
|
|
4067
|
+
lastIndex = match.index + match[0].length;
|
|
4068
|
+
if (match[1] === void 0) {
|
|
4069
|
+
runs.push(
|
|
4070
|
+
...createCrossReference(
|
|
4071
|
+
match[3],
|
|
4072
|
+
match[4] ?? "relative",
|
|
4073
|
+
match[0],
|
|
4074
|
+
baseStyle,
|
|
4075
|
+
options
|
|
4076
|
+
)
|
|
4077
|
+
);
|
|
4078
|
+
continue;
|
|
4079
|
+
}
|
|
3990
4080
|
const linkText = match[1];
|
|
3991
4081
|
const linkUrl = match[2];
|
|
3992
4082
|
const isInternal = linkUrl.startsWith("#");
|
|
@@ -4013,7 +4103,6 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
4013
4103
|
})
|
|
4014
4104
|
);
|
|
4015
4105
|
}
|
|
4016
|
-
lastIndex = match.index + match[0].length;
|
|
4017
4106
|
}
|
|
4018
4107
|
if (lastIndex < normalizedText.length) {
|
|
4019
4108
|
const remainingText = normalizedText.substring(lastIndex);
|
|
@@ -4222,7 +4311,7 @@ function initializeBuiltinPlaceholders() {
|
|
|
4222
4311
|
initializeBuiltinPlaceholders();
|
|
4223
4312
|
|
|
4224
4313
|
// src/utils/revisionUtils.ts
|
|
4225
|
-
import { AsyncLocalStorage as
|
|
4314
|
+
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
4226
4315
|
|
|
4227
4316
|
// src/utils/componentAnnotations.ts
|
|
4228
4317
|
function isRecord(value) {
|
|
@@ -4273,7 +4362,7 @@ var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
|
4273
4362
|
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
4274
4363
|
var RevisionIdRegistry = class {
|
|
4275
4364
|
fallbackCounter = 0;
|
|
4276
|
-
scopes = new
|
|
4365
|
+
scopes = new AsyncLocalStorage3();
|
|
4277
4366
|
runScoped(callback) {
|
|
4278
4367
|
return this.scopes.run({ counter: 0 }, callback);
|
|
4279
4368
|
}
|
|
@@ -4555,10 +4644,21 @@ init_styles();
|
|
|
4555
4644
|
init_defaults();
|
|
4556
4645
|
|
|
4557
4646
|
// src/utils/bookmarkRegistry.ts
|
|
4558
|
-
import { AsyncLocalStorage as
|
|
4647
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
|
|
4648
|
+
function slugifyBookmarkText(text) {
|
|
4649
|
+
return text.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").substring(0, 40);
|
|
4650
|
+
}
|
|
4651
|
+
function dedupeBookmarkId(base, taken) {
|
|
4652
|
+
let id = base;
|
|
4653
|
+
let attempt = 0;
|
|
4654
|
+
while (taken(id) && attempt < 100) {
|
|
4655
|
+
id = `${base}-${++attempt}`;
|
|
4656
|
+
}
|
|
4657
|
+
return id;
|
|
4658
|
+
}
|
|
4559
4659
|
var BookmarkRegistry = class {
|
|
4560
4660
|
fallback = { bookmarks: /* @__PURE__ */ new Map() };
|
|
4561
|
-
scopes = new
|
|
4661
|
+
scopes = new AsyncLocalStorage4();
|
|
4562
4662
|
get state() {
|
|
4563
4663
|
return this.scopes.getStore() ?? this.fallback;
|
|
4564
4664
|
}
|
|
@@ -4582,13 +4682,10 @@ var BookmarkRegistry = class {
|
|
|
4582
4682
|
* Converts text to a URL-friendly format
|
|
4583
4683
|
*/
|
|
4584
4684
|
generateId(text, _type = "bookmark") {
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
id = `${baseId}-${++attempt}`;
|
|
4590
|
-
}
|
|
4591
|
-
return id;
|
|
4685
|
+
return dedupeBookmarkId(
|
|
4686
|
+
slugifyBookmarkText(text),
|
|
4687
|
+
(id) => this.state.bookmarks.has(id)
|
|
4688
|
+
);
|
|
4592
4689
|
}
|
|
4593
4690
|
/**
|
|
4594
4691
|
* Check if a bookmark exists
|
|
@@ -4640,7 +4737,7 @@ import {
|
|
|
4640
4737
|
|
|
4641
4738
|
// src/utils/commentRegistry.ts
|
|
4642
4739
|
import { Paragraph, TextRun as TextRun4 } from "docx";
|
|
4643
|
-
import { AsyncLocalStorage as
|
|
4740
|
+
import { AsyncLocalStorage as AsyncLocalStorage5 } from "async_hooks";
|
|
4644
4741
|
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
4645
4742
|
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
4646
4743
|
function createState() {
|
|
@@ -4655,7 +4752,7 @@ function bodyParagraphs(text) {
|
|
|
4655
4752
|
}
|
|
4656
4753
|
var CommentRegistry = class {
|
|
4657
4754
|
fallback = createState();
|
|
4658
|
-
scopes = new
|
|
4755
|
+
scopes = new AsyncLocalStorage5();
|
|
4659
4756
|
get state() {
|
|
4660
4757
|
return this.scopes.getStore() ?? this.fallback;
|
|
4661
4758
|
}
|
|
@@ -4750,7 +4847,7 @@ function closeCommentRange(ids) {
|
|
|
4750
4847
|
|
|
4751
4848
|
// src/utils/noteRegistry.ts
|
|
4752
4849
|
import { Paragraph as Paragraph2, TextRun as TextRun6 } from "docx";
|
|
4753
|
-
import { AsyncLocalStorage as
|
|
4850
|
+
import { AsyncLocalStorage as AsyncLocalStorage6 } from "async_hooks";
|
|
4754
4851
|
function createState2() {
|
|
4755
4852
|
return {
|
|
4756
4853
|
footnoteCounter: 0,
|
|
@@ -4769,7 +4866,7 @@ function bodyParagraphs2(text, style) {
|
|
|
4769
4866
|
}
|
|
4770
4867
|
var NoteRegistry = class {
|
|
4771
4868
|
fallback = createState2();
|
|
4772
|
-
scopes = new
|
|
4869
|
+
scopes = new AsyncLocalStorage6();
|
|
4773
4870
|
get state() {
|
|
4774
4871
|
return this.scopes.getStore() ?? this.fallback;
|
|
4775
4872
|
}
|
|
@@ -5125,7 +5222,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
5125
5222
|
if (commentAnchor) {
|
|
5126
5223
|
children.push(...commentAnchor.start);
|
|
5127
5224
|
}
|
|
5128
|
-
const
|
|
5225
|
+
const hasInlineSyntax = /(\*\*\*|___|(\*\*|__)|(\*|_))/.test(normalizedText) || hasCrossReference(normalizedText);
|
|
5129
5226
|
const headingHasWeightRequest = options.fontWeight != null || options.bold === true;
|
|
5130
5227
|
const headingEffectiveFamily = options.fontFamily ?? (headingHasWeightRequest ? resolveFontFamily(theme, "heading") : void 0);
|
|
5131
5228
|
const headingWeighted = applyFontWeightAlias({
|
|
@@ -5192,7 +5289,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
5192
5289
|
"heading"
|
|
5193
5290
|
);
|
|
5194
5291
|
const headingTextChildren = [];
|
|
5195
|
-
if (
|
|
5292
|
+
if (hasInlineSyntax) {
|
|
5196
5293
|
const textRuns = parseTextWithDecorators(normalizedText, baseTextStyle, {
|
|
5197
5294
|
boldColor: options.boldColor ? resolveColor(options.boldColor, theme) : void 0,
|
|
5198
5295
|
enableHyperlinks: true,
|
|
@@ -5209,7 +5306,7 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
5209
5306
|
})
|
|
5210
5307
|
);
|
|
5211
5308
|
} else {
|
|
5212
|
-
if (
|
|
5309
|
+
if (hasInlineSyntax) {
|
|
5213
5310
|
const textRuns = parseTextWithDecorators(normalizedText, baseTextStyle, {
|
|
5214
5311
|
boldColor: options.boldColor ? resolveColor(options.boldColor, theme) : void 0,
|
|
5215
5312
|
enableHyperlinks: true,
|
|
@@ -5231,7 +5328,10 @@ function createHeading(text, level, theme, _themeName, options = {}) {
|
|
|
5231
5328
|
spacing: hasExplicitSpacing ? spacing : void 0,
|
|
5232
5329
|
...options.keepNext !== void 0 && { keepNext: options.keepNext },
|
|
5233
5330
|
...options.keepLines !== void 0 && { keepLines: options.keepLines },
|
|
5234
|
-
...options.indent && { indent: options.indent }
|
|
5331
|
+
...options.indent && { indent: options.indent },
|
|
5332
|
+
// docx creates the concrete numbering instance for the reference itself,
|
|
5333
|
+
// in ParagraphProperties.prepForXml.
|
|
5334
|
+
...options.numbering !== void 0 && { numbering: options.numbering }
|
|
5235
5335
|
});
|
|
5236
5336
|
}
|
|
5237
5337
|
async function createImage(path4, theme, themeName, options = {}) {
|
|
@@ -5391,9 +5491,17 @@ function createList(items, _theme, _themeName, options = {}) {
|
|
|
5391
5491
|
} else if (options.spacing?.item) {
|
|
5392
5492
|
spacing.after = pointsToTwips(options.spacing.item);
|
|
5393
5493
|
}
|
|
5494
|
+
const itemId = typeof item === "object" ? item.id : void 0;
|
|
5495
|
+
let itemContent = textRuns;
|
|
5496
|
+
if (itemId) {
|
|
5497
|
+
globalBookmarkRegistry.register(itemId, itemText, "list-item");
|
|
5498
|
+
itemContent = [
|
|
5499
|
+
new Bookmark({ id: itemId, children: textRuns })
|
|
5500
|
+
];
|
|
5501
|
+
}
|
|
5394
5502
|
const paragraphChildren = [
|
|
5395
5503
|
...commentAnchor && index === firstRendered ? commentAnchor.start : [],
|
|
5396
|
-
...
|
|
5504
|
+
...itemContent,
|
|
5397
5505
|
...commentAnchor && index === lastRendered ? closeCommentRange(commentAnchor.ids) : []
|
|
5398
5506
|
];
|
|
5399
5507
|
const paragraph = new Paragraph3({
|
|
@@ -6236,54 +6344,14 @@ function createFooterElement(children, _options) {
|
|
|
6236
6344
|
});
|
|
6237
6345
|
}
|
|
6238
6346
|
|
|
6239
|
-
// src/components/heading.ts
|
|
6240
|
-
function renderHeadingComponent(component, theme, themeName) {
|
|
6241
|
-
if (!isHeadingComponent(component)) return [];
|
|
6242
|
-
const config = component.props;
|
|
6243
|
-
const bookmarkId = component.id || globalBookmarkRegistry.generateId(config.text, "heading");
|
|
6244
|
-
const header = createHeading(
|
|
6245
|
-
config.text,
|
|
6246
|
-
config.level || 1,
|
|
6247
|
-
theme,
|
|
6248
|
-
themeName,
|
|
6249
|
-
{
|
|
6250
|
-
alignment: config.alignment,
|
|
6251
|
-
spacing: config.spacing,
|
|
6252
|
-
lineSpacing: config.lineSpacing,
|
|
6253
|
-
columnBreak: config.columnBreak,
|
|
6254
|
-
// Local font overrides
|
|
6255
|
-
fontFamily: config.font?.family,
|
|
6256
|
-
fontSize: config.font?.size,
|
|
6257
|
-
fontColor: config.font?.color,
|
|
6258
|
-
bold: config.font?.bold,
|
|
6259
|
-
fontWeight: config.font?.fontWeight,
|
|
6260
|
-
italic: config.font?.italic,
|
|
6261
|
-
underline: config.font?.underline,
|
|
6262
|
-
scale: config.font?.scale,
|
|
6263
|
-
characterSpacing: config.font?.characterSpacing,
|
|
6264
|
-
// Proofing: local language override + no-proof toggle + known-words list
|
|
6265
|
-
language: config.language,
|
|
6266
|
-
noProof: config.noProof,
|
|
6267
|
-
noProofWords: config.noProofWords,
|
|
6268
|
-
// Pagination control
|
|
6269
|
-
keepNext: config.keepNext,
|
|
6270
|
-
keepLines: config.keepLines,
|
|
6271
|
-
// Paragraph indentation (w:ind) in twips
|
|
6272
|
-
indent: config.indent,
|
|
6273
|
-
// Bookmark ID for internal linking
|
|
6274
|
-
bookmarkId,
|
|
6275
|
-
// Tracked-change segments (rendered as native Word revisions)
|
|
6276
|
-
revision: config.revision,
|
|
6277
|
-
// Review comment anchored to this heading's text
|
|
6278
|
-
comment: config.comment
|
|
6279
|
-
}
|
|
6280
|
-
);
|
|
6281
|
-
return [header];
|
|
6282
|
-
}
|
|
6283
|
-
|
|
6284
6347
|
// src/utils/numberingConfig.ts
|
|
6285
|
-
import {
|
|
6286
|
-
|
|
6348
|
+
import {
|
|
6349
|
+
AlignmentType as AlignmentType3,
|
|
6350
|
+
convertInchesToTwip,
|
|
6351
|
+
LevelFormat,
|
|
6352
|
+
LevelSuffix
|
|
6353
|
+
} from "docx";
|
|
6354
|
+
import { AsyncLocalStorage as AsyncLocalStorage7 } from "async_hooks";
|
|
6287
6355
|
var LEVEL_FORMAT_MAP = {
|
|
6288
6356
|
decimal: LevelFormat.DECIMAL,
|
|
6289
6357
|
upperRoman: LevelFormat.UPPER_ROMAN,
|
|
@@ -6411,12 +6479,37 @@ function createNumberingConfig(config) {
|
|
|
6411
6479
|
levels
|
|
6412
6480
|
};
|
|
6413
6481
|
}
|
|
6482
|
+
var HEADING_NUMBERING_REFERENCE = "jto-heading-numbering";
|
|
6483
|
+
function createHeadingNumberingConfig() {
|
|
6484
|
+
const levels = [];
|
|
6485
|
+
for (let level = 0; level < 6; level++) {
|
|
6486
|
+
const text = Array.from({ length: level + 1 }, (_, i) => `%${i + 1}`).join(".") + ".";
|
|
6487
|
+
levels.push({
|
|
6488
|
+
level,
|
|
6489
|
+
format: LevelFormat.DECIMAL,
|
|
6490
|
+
text,
|
|
6491
|
+
alignment: AlignmentType3.LEFT,
|
|
6492
|
+
start: 1,
|
|
6493
|
+
// A space, not the default tab: a tab would push the heading text to the
|
|
6494
|
+
// next tab stop and misalign it against unnumbered headings.
|
|
6495
|
+
suffix: LevelSuffix.SPACE,
|
|
6496
|
+
style: {
|
|
6497
|
+
paragraph: { indent: { left: 0, hanging: 0 } },
|
|
6498
|
+
style: `Heading${level + 1}`
|
|
6499
|
+
}
|
|
6500
|
+
});
|
|
6501
|
+
}
|
|
6502
|
+
return { reference: HEADING_NUMBERING_REFERENCE, levels };
|
|
6503
|
+
}
|
|
6504
|
+
function headingNumberLabel(number) {
|
|
6505
|
+
return `${number}.`;
|
|
6506
|
+
}
|
|
6414
6507
|
var NumberingRegistry = class {
|
|
6415
6508
|
fallback = {
|
|
6416
6509
|
configs: /* @__PURE__ */ new Map(),
|
|
6417
6510
|
counter: 0
|
|
6418
6511
|
};
|
|
6419
|
-
scopes = new
|
|
6512
|
+
scopes = new AsyncLocalStorage7();
|
|
6420
6513
|
get state() {
|
|
6421
6514
|
return this.scopes.getStore() ?? this.fallback;
|
|
6422
6515
|
}
|
|
@@ -6466,6 +6559,63 @@ var NumberingRegistry = class {
|
|
|
6466
6559
|
};
|
|
6467
6560
|
var globalNumberingRegistry = new NumberingRegistry();
|
|
6468
6561
|
|
|
6562
|
+
// src/components/heading.ts
|
|
6563
|
+
var MAX_HEADING_LEVEL = 6;
|
|
6564
|
+
function headingNumbering(numbering, level) {
|
|
6565
|
+
if (numbering === false) return false;
|
|
6566
|
+
if (numbering !== true) return void 0;
|
|
6567
|
+
if (!globalNumberingRegistry.has(HEADING_NUMBERING_REFERENCE)) {
|
|
6568
|
+
globalNumberingRegistry.register(createHeadingNumberingConfig());
|
|
6569
|
+
}
|
|
6570
|
+
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL ? level : 1;
|
|
6571
|
+
return { reference: HEADING_NUMBERING_REFERENCE, level: styleLevel - 1 };
|
|
6572
|
+
}
|
|
6573
|
+
function renderHeadingComponent(component, theme, themeName) {
|
|
6574
|
+
if (!isHeadingComponent(component)) return [];
|
|
6575
|
+
const config = component.props;
|
|
6576
|
+
const bookmarkId = component.id || globalBookmarkRegistry.generateId(config.text, "heading");
|
|
6577
|
+
const header = createHeading(
|
|
6578
|
+
config.text,
|
|
6579
|
+
config.level || 1,
|
|
6580
|
+
theme,
|
|
6581
|
+
themeName,
|
|
6582
|
+
{
|
|
6583
|
+
alignment: config.alignment,
|
|
6584
|
+
spacing: config.spacing,
|
|
6585
|
+
lineSpacing: config.lineSpacing,
|
|
6586
|
+
columnBreak: config.columnBreak,
|
|
6587
|
+
// Local font overrides
|
|
6588
|
+
fontFamily: config.font?.family,
|
|
6589
|
+
fontSize: config.font?.size,
|
|
6590
|
+
fontColor: config.font?.color,
|
|
6591
|
+
bold: config.font?.bold,
|
|
6592
|
+
fontWeight: config.font?.fontWeight,
|
|
6593
|
+
italic: config.font?.italic,
|
|
6594
|
+
underline: config.font?.underline,
|
|
6595
|
+
scale: config.font?.scale,
|
|
6596
|
+
characterSpacing: config.font?.characterSpacing,
|
|
6597
|
+
// Proofing: local language override + no-proof toggle + known-words list
|
|
6598
|
+
language: config.language,
|
|
6599
|
+
noProof: config.noProof,
|
|
6600
|
+
noProofWords: config.noProofWords,
|
|
6601
|
+
// Pagination control
|
|
6602
|
+
keepNext: config.keepNext,
|
|
6603
|
+
keepLines: config.keepLines,
|
|
6604
|
+
// Paragraph indentation (w:ind) in twips
|
|
6605
|
+
indent: config.indent,
|
|
6606
|
+
// Bookmark ID for internal linking
|
|
6607
|
+
bookmarkId,
|
|
6608
|
+
// Auto-numbering (1., 1.1., …) through the shared heading definition
|
|
6609
|
+
numbering: headingNumbering(config.numbering, config.level || 1),
|
|
6610
|
+
// Tracked-change segments (rendered as native Word revisions)
|
|
6611
|
+
revision: config.revision,
|
|
6612
|
+
// Review comment anchored to this heading's text
|
|
6613
|
+
comment: config.comment
|
|
6614
|
+
}
|
|
6615
|
+
);
|
|
6616
|
+
return [header];
|
|
6617
|
+
}
|
|
6618
|
+
|
|
6469
6619
|
// src/components/paragraph.ts
|
|
6470
6620
|
function parseMarkdownList(text) {
|
|
6471
6621
|
const lines = text.split("\n");
|
|
@@ -6605,8 +6755,7 @@ function renderParagraphComponent(component, theme, themeName) {
|
|
|
6605
6755
|
return [text];
|
|
6606
6756
|
}
|
|
6607
6757
|
|
|
6608
|
-
// src/
|
|
6609
|
-
init_colorUtils();
|
|
6758
|
+
// src/utils/listLevels.ts
|
|
6610
6759
|
function createLevelsFromSimplifiedProps(props) {
|
|
6611
6760
|
const levels = [];
|
|
6612
6761
|
let format2;
|
|
@@ -6653,18 +6802,8 @@ function createLevelsFromSimplifiedProps(props) {
|
|
|
6653
6802
|
}
|
|
6654
6803
|
return levels;
|
|
6655
6804
|
}
|
|
6656
|
-
function resolveMarkerFonts(levels, theme) {
|
|
6657
|
-
return levels.map((level) => {
|
|
6658
|
-
const font = level.font;
|
|
6659
|
-
if (!font?.color) return level;
|
|
6660
|
-
return {
|
|
6661
|
-
...level,
|
|
6662
|
-
font: { ...font, color: resolveColor(font.color, theme) }
|
|
6663
|
-
};
|
|
6664
|
-
});
|
|
6665
|
-
}
|
|
6666
6805
|
function applyListStart(levels, start) {
|
|
6667
|
-
if (start === void 0) return levels;
|
|
6806
|
+
if (start === void 0) return [...levels];
|
|
6668
6807
|
return levels.map(
|
|
6669
6808
|
(level) => level.level === 0 && level.start === void 0 ? { ...level, start } : level
|
|
6670
6809
|
);
|
|
@@ -6722,28 +6861,37 @@ function fillMissingLevels(levels, maxLevel) {
|
|
|
6722
6861
|
}
|
|
6723
6862
|
return result;
|
|
6724
6863
|
}
|
|
6864
|
+
function resolveListLevels(props) {
|
|
6865
|
+
const maxLevel = getMaxLevelFromItems(props.items);
|
|
6866
|
+
if (props.levels && props.levels.length > 0) {
|
|
6867
|
+
return fillMissingLevels(
|
|
6868
|
+
applyListStart(props.levels, props.start),
|
|
6869
|
+
maxLevel
|
|
6870
|
+
);
|
|
6871
|
+
}
|
|
6872
|
+
return fillMissingLevels(createLevelsFromSimplifiedProps(props), maxLevel);
|
|
6873
|
+
}
|
|
6874
|
+
|
|
6875
|
+
// src/components/list.ts
|
|
6876
|
+
init_colorUtils();
|
|
6877
|
+
function resolveMarkerFonts(levels, theme) {
|
|
6878
|
+
return levels.map((level) => {
|
|
6879
|
+
const font = level.font;
|
|
6880
|
+
if (!font?.color) return level;
|
|
6881
|
+
return {
|
|
6882
|
+
...level,
|
|
6883
|
+
font: { ...font, color: resolveColor(font.color, theme) }
|
|
6884
|
+
};
|
|
6885
|
+
});
|
|
6886
|
+
}
|
|
6725
6887
|
function renderListComponent(component, theme, themeName) {
|
|
6726
6888
|
if (!isListComponent(component)) return [];
|
|
6727
6889
|
const resolvedConfig = component.props;
|
|
6728
|
-
const maxLevel = getMaxLevelFromItems(resolvedConfig.items);
|
|
6729
6890
|
const reference = resolvedConfig.reference || globalNumberingRegistry.generateReference("list");
|
|
6730
6891
|
if (!globalNumberingRegistry.has(reference)) {
|
|
6731
|
-
let levels;
|
|
6732
|
-
if (resolvedConfig.levels && resolvedConfig.levels.length > 0) {
|
|
6733
|
-
levels = fillMissingLevels(
|
|
6734
|
-
applyListStart(
|
|
6735
|
-
resolvedConfig.levels,
|
|
6736
|
-
resolvedConfig.start
|
|
6737
|
-
),
|
|
6738
|
-
maxLevel
|
|
6739
|
-
);
|
|
6740
|
-
} else {
|
|
6741
|
-
const baseLevels = createLevelsFromSimplifiedProps(resolvedConfig);
|
|
6742
|
-
levels = fillMissingLevels(baseLevels, maxLevel);
|
|
6743
|
-
}
|
|
6744
6892
|
const config = {
|
|
6745
6893
|
reference,
|
|
6746
|
-
levels: resolveMarkerFonts(
|
|
6894
|
+
levels: resolveMarkerFonts(resolveListLevels(resolvedConfig), theme)
|
|
6747
6895
|
};
|
|
6748
6896
|
const numberingConfig = createNumberingConfig(config);
|
|
6749
6897
|
globalNumberingRegistry.register(numberingConfig);
|
|
@@ -6783,6 +6931,7 @@ async function renderImageComponent(component, theme, themeName) {
|
|
|
6783
6931
|
|
|
6784
6932
|
// src/components/text-box.ts
|
|
6785
6933
|
import {
|
|
6934
|
+
Paragraph as Paragraph5,
|
|
6786
6935
|
Table as Table3,
|
|
6787
6936
|
TableRow as TableRow2,
|
|
6788
6937
|
TableCell as TableCell2,
|
|
@@ -6791,7 +6940,8 @@ import {
|
|
|
6791
6940
|
RelativeHorizontalPosition,
|
|
6792
6941
|
RelativeVerticalPosition,
|
|
6793
6942
|
OverlapType,
|
|
6794
|
-
TableLayoutType as TableLayoutType2
|
|
6943
|
+
TableLayoutType as TableLayoutType2,
|
|
6944
|
+
WpsShapeRun
|
|
6795
6945
|
} from "docx";
|
|
6796
6946
|
|
|
6797
6947
|
// src/styles/utils/borderUtils.ts
|
|
@@ -6868,6 +7018,8 @@ function buildCellOptions(children, styleCfg, theme) {
|
|
|
6868
7018
|
}
|
|
6869
7019
|
|
|
6870
7020
|
// src/components/text-box.ts
|
|
7021
|
+
init_colorUtils();
|
|
7022
|
+
init_docxImagePositioning();
|
|
6871
7023
|
init_widthUtils();
|
|
6872
7024
|
function mapTableFloatOptions(floating, theme, themeName) {
|
|
6873
7025
|
if (!floating) return void 0;
|
|
@@ -6923,26 +7075,23 @@ function mapTableFloatOptions(floating, theme, themeName) {
|
|
|
6923
7075
|
opt.overlap = OverlapType.OVERLAP;
|
|
6924
7076
|
return opt;
|
|
6925
7077
|
}
|
|
6926
|
-
async function
|
|
6927
|
-
|
|
6928
|
-
|
|
7078
|
+
async function renderTextBoxChildren(tb, theme, themeName, context) {
|
|
7079
|
+
const childContext = {
|
|
7080
|
+
...context,
|
|
7081
|
+
parent: tb
|
|
7082
|
+
};
|
|
7083
|
+
const rendered = [];
|
|
7084
|
+
for (const child of tb.children || []) {
|
|
7085
|
+
rendered.push(
|
|
7086
|
+
...await renderComponent(child, theme, themeName, childContext)
|
|
7087
|
+
);
|
|
7088
|
+
}
|
|
7089
|
+
return rendered;
|
|
7090
|
+
}
|
|
7091
|
+
async function renderTextBoxAsTable(tb, theme, themeName, _context, prerendered) {
|
|
6929
7092
|
const isInline = !tb.props.floating;
|
|
6930
|
-
const childComponents = tb.children || [];
|
|
6931
7093
|
if (isInline) {
|
|
6932
|
-
const cellChildren2 =
|
|
6933
|
-
const childContext2 = {
|
|
6934
|
-
..._context,
|
|
6935
|
-
parent: tb
|
|
6936
|
-
};
|
|
6937
|
-
for (const child of childComponents) {
|
|
6938
|
-
const rendered = await renderComponent(
|
|
6939
|
-
child,
|
|
6940
|
-
theme,
|
|
6941
|
-
themeName,
|
|
6942
|
-
childContext2
|
|
6943
|
-
);
|
|
6944
|
-
cellChildren2.push(...rendered);
|
|
6945
|
-
}
|
|
7094
|
+
const cellChildren2 = prerendered ?? await renderTextBoxChildren(tb, theme, themeName, _context);
|
|
6946
7095
|
const styleCfg2 = tb.props.style;
|
|
6947
7096
|
const cellOpts2 = buildCellOptions(cellChildren2, styleCfg2, theme);
|
|
6948
7097
|
const row2 = new TableRow2({ children: [new TableCell2(cellOpts2)] });
|
|
@@ -6955,20 +7104,7 @@ async function renderTextBoxComponent(component, theme, themeName, _context) {
|
|
|
6955
7104
|
});
|
|
6956
7105
|
return [table2];
|
|
6957
7106
|
}
|
|
6958
|
-
const cellChildren =
|
|
6959
|
-
const childContext = {
|
|
6960
|
-
..._context,
|
|
6961
|
-
parent: tb
|
|
6962
|
-
};
|
|
6963
|
-
for (const child of childComponents) {
|
|
6964
|
-
const rendered = await renderComponent(
|
|
6965
|
-
child,
|
|
6966
|
-
theme,
|
|
6967
|
-
themeName,
|
|
6968
|
-
childContext
|
|
6969
|
-
);
|
|
6970
|
-
cellChildren.push(...rendered);
|
|
6971
|
-
}
|
|
7107
|
+
const cellChildren = prerendered ?? await renderTextBoxChildren(tb, theme, themeName, _context);
|
|
6972
7108
|
const styleCfg = tb.props.style;
|
|
6973
7109
|
const cellOpts = buildCellOptions(cellChildren, styleCfg, theme);
|
|
6974
7110
|
const row = new TableRow2({
|
|
@@ -7000,6 +7136,162 @@ async function renderTextBoxComponent(component, theme, themeName, _context) {
|
|
|
7000
7136
|
});
|
|
7001
7137
|
return [table];
|
|
7002
7138
|
}
|
|
7139
|
+
var PIXELS_TO_EMU = 9525;
|
|
7140
|
+
var TWIPS_PER_PIXEL = 15;
|
|
7141
|
+
function resolveShapeSize(value, axis, theme, themeName) {
|
|
7142
|
+
if (typeof value === "number") {
|
|
7143
|
+
return { pixels: Math.round(value), resolvedPercentage: false };
|
|
7144
|
+
}
|
|
7145
|
+
if (typeof value !== "string") return { resolvedPercentage: false };
|
|
7146
|
+
const fraction = parseFloat(value) / 100;
|
|
7147
|
+
if (!Number.isFinite(fraction) || fraction <= 0) {
|
|
7148
|
+
return { resolvedPercentage: false };
|
|
7149
|
+
}
|
|
7150
|
+
const availableTwips = axis === "width" ? getAvailableWidthTwips(theme, themeName) : getAvailableHeightTwips(theme, themeName);
|
|
7151
|
+
return {
|
|
7152
|
+
pixels: Math.round(availableTwips * fraction / TWIPS_PER_PIXEL),
|
|
7153
|
+
resolvedPercentage: true
|
|
7154
|
+
};
|
|
7155
|
+
}
|
|
7156
|
+
function shapeColor(value, theme) {
|
|
7157
|
+
return resolveColor(value, theme).replace(/^#/, "");
|
|
7158
|
+
}
|
|
7159
|
+
function shapeOutline(style, theme) {
|
|
7160
|
+
const border = style?.border;
|
|
7161
|
+
if (!border) return { ignoredSides: [], unsupportedStyles: [] };
|
|
7162
|
+
const order = [
|
|
7163
|
+
"top",
|
|
7164
|
+
"left",
|
|
7165
|
+
"bottom",
|
|
7166
|
+
"right"
|
|
7167
|
+
];
|
|
7168
|
+
const declared = order.map((side) => [side, border[side]]).filter(
|
|
7169
|
+
(entry) => Boolean(entry[1])
|
|
7170
|
+
);
|
|
7171
|
+
if (declared.length === 0) return { ignoredSides: [], unsupportedStyles: [] };
|
|
7172
|
+
const unsupportedStyles = [
|
|
7173
|
+
...new Set(
|
|
7174
|
+
declared.map(([, config]) => config.style).filter(
|
|
7175
|
+
(value) => value === "dashed" || value === "dotted" || value === "double"
|
|
7176
|
+
)
|
|
7177
|
+
)
|
|
7178
|
+
];
|
|
7179
|
+
if (unsupportedStyles.length > 0) {
|
|
7180
|
+
return { ignoredSides: [], unsupportedStyles };
|
|
7181
|
+
}
|
|
7182
|
+
const [, used] = declared[0];
|
|
7183
|
+
const differs = ({ style: s, width, color }) => s !== used.style || width !== used.width || color !== used.color;
|
|
7184
|
+
const ignoredSides = declared.slice(1).filter(([, config]) => differs(config)).map(([side]) => side);
|
|
7185
|
+
if (used.style === "none") return { ignoredSides, unsupportedStyles };
|
|
7186
|
+
return {
|
|
7187
|
+
outline: {
|
|
7188
|
+
type: "solidFill",
|
|
7189
|
+
solidFillType: "rgb",
|
|
7190
|
+
value: used.color ? shapeColor(used.color, theme) : "000000",
|
|
7191
|
+
...used.width !== void 0 && {
|
|
7192
|
+
width: Math.round(used.width * PIXELS_TO_EMU)
|
|
7193
|
+
}
|
|
7194
|
+
},
|
|
7195
|
+
ignoredSides,
|
|
7196
|
+
unsupportedStyles
|
|
7197
|
+
};
|
|
7198
|
+
}
|
|
7199
|
+
function shapeBodyProperties(style) {
|
|
7200
|
+
const padding = style?.padding;
|
|
7201
|
+
if (!padding) return void 0;
|
|
7202
|
+
const toEmu = (value) => value === void 0 ? void 0 : Math.round(value * PIXELS_TO_EMU);
|
|
7203
|
+
return {
|
|
7204
|
+
margins: {
|
|
7205
|
+
...padding.top !== void 0 && { top: toEmu(padding.top) },
|
|
7206
|
+
...padding.bottom !== void 0 && { bottom: toEmu(padding.bottom) },
|
|
7207
|
+
...padding.left !== void 0 && { left: toEmu(padding.left) },
|
|
7208
|
+
...padding.right !== void 0 && { right: toEmu(padding.right) }
|
|
7209
|
+
}
|
|
7210
|
+
};
|
|
7211
|
+
}
|
|
7212
|
+
async function renderTextBoxAsShape(tb, theme, themeName, context) {
|
|
7213
|
+
const width = resolveShapeSize(tb.props.width, "width", theme, themeName);
|
|
7214
|
+
const height = resolveShapeSize(tb.props.height, "height", theme, themeName);
|
|
7215
|
+
if (width.pixels === void 0 || height.pixels === void 0) {
|
|
7216
|
+
console.warn(
|
|
7217
|
+
'[core-docx] text-box renderAs "shape" needs an explicit width and height (a shape has no autofit); falling back to table rendering.'
|
|
7218
|
+
);
|
|
7219
|
+
return { kind: "fallback" };
|
|
7220
|
+
}
|
|
7221
|
+
const style = tb.props.style;
|
|
7222
|
+
const { outline, ignoredSides, unsupportedStyles } = shapeOutline(
|
|
7223
|
+
style,
|
|
7224
|
+
theme
|
|
7225
|
+
);
|
|
7226
|
+
if (unsupportedStyles.length > 0) {
|
|
7227
|
+
console.warn(
|
|
7228
|
+
`[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.`
|
|
7229
|
+
);
|
|
7230
|
+
return { kind: "fallback" };
|
|
7231
|
+
}
|
|
7232
|
+
const rendered = await renderTextBoxChildren(tb, theme, themeName, context);
|
|
7233
|
+
if (rendered.some((element) => !(element instanceof Paragraph5))) {
|
|
7234
|
+
console.warn(
|
|
7235
|
+
'[core-docx] text-box renderAs "shape" requires paragraph-only content; falling back to table rendering.'
|
|
7236
|
+
);
|
|
7237
|
+
return { kind: "fallback", rendered };
|
|
7238
|
+
}
|
|
7239
|
+
const children = rendered;
|
|
7240
|
+
if (width.resolvedPercentage || height.resolvedPercentage) {
|
|
7241
|
+
console.warn(
|
|
7242
|
+
'[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.'
|
|
7243
|
+
);
|
|
7244
|
+
}
|
|
7245
|
+
const fill = style?.shading?.fill;
|
|
7246
|
+
if (ignoredSides.length > 0) {
|
|
7247
|
+
console.warn(
|
|
7248
|
+
`[core-docx] text-box renderAs "shape" has one uniform outline; using the first declared border side and ignoring ${ignoredSides.join(", ")}.`
|
|
7249
|
+
);
|
|
7250
|
+
}
|
|
7251
|
+
const dropOutline = Boolean(fill) && Boolean(outline);
|
|
7252
|
+
if (dropOutline) {
|
|
7253
|
+
console.warn(
|
|
7254
|
+
'[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.'
|
|
7255
|
+
);
|
|
7256
|
+
}
|
|
7257
|
+
const bodyProperties = shapeBodyProperties(style);
|
|
7258
|
+
const run = new WpsShapeRun({
|
|
7259
|
+
type: "wps",
|
|
7260
|
+
children,
|
|
7261
|
+
transformation: { width: width.pixels, height: height.pixels },
|
|
7262
|
+
...fill && {
|
|
7263
|
+
solidFill: { type: "rgb", value: shapeColor(fill, theme) }
|
|
7264
|
+
},
|
|
7265
|
+
...outline && !dropOutline && { outline },
|
|
7266
|
+
...bodyProperties && { bodyProperties },
|
|
7267
|
+
// Absent `floating` makes it a `wp:inline` drawing.
|
|
7268
|
+
...tb.props.floating && {
|
|
7269
|
+
floating: mapFloatingOptions(tb.props.floating, theme, themeName)
|
|
7270
|
+
}
|
|
7271
|
+
});
|
|
7272
|
+
return {
|
|
7273
|
+
kind: "shape",
|
|
7274
|
+
paragraphs: [
|
|
7275
|
+
new Paragraph5({ children: [run], spacing: { before: 0, after: 0 } })
|
|
7276
|
+
]
|
|
7277
|
+
};
|
|
7278
|
+
}
|
|
7279
|
+
async function renderTextBoxComponent(component, theme, themeName, context) {
|
|
7280
|
+
if (!isTextBoxComponent(component)) return [];
|
|
7281
|
+
const tb = component;
|
|
7282
|
+
if (tb.props.renderAs === "shape") {
|
|
7283
|
+
const attempt = await renderTextBoxAsShape(tb, theme, themeName, context);
|
|
7284
|
+
if (attempt.kind === "shape") return attempt.paragraphs;
|
|
7285
|
+
return renderTextBoxAsTable(
|
|
7286
|
+
tb,
|
|
7287
|
+
theme,
|
|
7288
|
+
themeName,
|
|
7289
|
+
context,
|
|
7290
|
+
attempt.rendered
|
|
7291
|
+
);
|
|
7292
|
+
}
|
|
7293
|
+
return renderTextBoxAsTable(tb, theme, themeName, context);
|
|
7294
|
+
}
|
|
7003
7295
|
|
|
7004
7296
|
// src/components/table.ts
|
|
7005
7297
|
async function renderTableComponent(component, theme, themeName) {
|
|
@@ -7053,14 +7345,14 @@ async function renderTableComponent(component, theme, themeName) {
|
|
|
7053
7345
|
import { Paragraph as Paragraph6, BookmarkStart, BookmarkEnd } from "docx";
|
|
7054
7346
|
|
|
7055
7347
|
// src/core/sectionBookmarks.ts
|
|
7056
|
-
import { AsyncLocalStorage as
|
|
7348
|
+
import { AsyncLocalStorage as AsyncLocalStorage8 } from "async_hooks";
|
|
7057
7349
|
var NESTED_LINK_ID_BASE = 1e6;
|
|
7058
7350
|
function createState3() {
|
|
7059
7351
|
return { nextNested: 1, resolved: /* @__PURE__ */ new WeakMap() };
|
|
7060
7352
|
}
|
|
7061
7353
|
var SectionBookmarkRegistry = class {
|
|
7062
7354
|
fallback = createState3();
|
|
7063
|
-
scopes = new
|
|
7355
|
+
scopes = new AsyncLocalStorage8();
|
|
7064
7356
|
get state() {
|
|
7065
7357
|
return this.scopes.getStore() ?? this.fallback;
|
|
7066
7358
|
}
|
|
@@ -7318,7 +7610,10 @@ function selectCachedEntries(collected, options) {
|
|
|
7318
7610
|
continue;
|
|
7319
7611
|
}
|
|
7320
7612
|
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
7321
|
-
entries.push({
|
|
7613
|
+
entries.push({
|
|
7614
|
+
title: entry.number ? `${headingNumberLabel(entry.number)} ${entry.title}` : entry.title,
|
|
7615
|
+
level: entry.level
|
|
7616
|
+
});
|
|
7322
7617
|
}
|
|
7323
7618
|
return entries;
|
|
7324
7619
|
}
|
|
@@ -8077,6 +8372,61 @@ function computeSectionOrdinals(sections) {
|
|
|
8077
8372
|
|
|
8078
8373
|
// src/core/collectTocHeadings.ts
|
|
8079
8374
|
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
8375
|
+
|
|
8376
|
+
// src/utils/numberFormatting.ts
|
|
8377
|
+
var ROMAN_NUMERALS = [
|
|
8378
|
+
[1e3, "m"],
|
|
8379
|
+
[900, "cm"],
|
|
8380
|
+
[500, "d"],
|
|
8381
|
+
[400, "cd"],
|
|
8382
|
+
[100, "c"],
|
|
8383
|
+
[90, "xc"],
|
|
8384
|
+
[50, "l"],
|
|
8385
|
+
[40, "xl"],
|
|
8386
|
+
[10, "x"],
|
|
8387
|
+
[9, "ix"],
|
|
8388
|
+
[5, "v"],
|
|
8389
|
+
[4, "iv"],
|
|
8390
|
+
[1, "i"]
|
|
8391
|
+
];
|
|
8392
|
+
function toRoman(value) {
|
|
8393
|
+
let remaining = value;
|
|
8394
|
+
let out = "";
|
|
8395
|
+
for (const [amount, glyph] of ROMAN_NUMERALS) {
|
|
8396
|
+
while (remaining >= amount) {
|
|
8397
|
+
out += glyph;
|
|
8398
|
+
remaining -= amount;
|
|
8399
|
+
}
|
|
8400
|
+
}
|
|
8401
|
+
return out;
|
|
8402
|
+
}
|
|
8403
|
+
function toLetters(value) {
|
|
8404
|
+
const index = (value - 1) % 26;
|
|
8405
|
+
const repeats = Math.floor((value - 1) / 26) + 1;
|
|
8406
|
+
return String.fromCharCode(97 + index).repeat(repeats);
|
|
8407
|
+
}
|
|
8408
|
+
function formatNumberForLevel(value, format2) {
|
|
8409
|
+
if (!Number.isFinite(value) || value < 1) return void 0;
|
|
8410
|
+
const n = Math.floor(value);
|
|
8411
|
+
switch (format2) {
|
|
8412
|
+
case "decimal":
|
|
8413
|
+
return String(n);
|
|
8414
|
+
case "lowerLetter":
|
|
8415
|
+
return toLetters(n);
|
|
8416
|
+
case "upperLetter":
|
|
8417
|
+
return toLetters(n).toUpperCase();
|
|
8418
|
+
case "lowerRoman":
|
|
8419
|
+
return toRoman(n);
|
|
8420
|
+
case "upperRoman":
|
|
8421
|
+
return toRoman(n).toUpperCase();
|
|
8422
|
+
default:
|
|
8423
|
+
return void 0;
|
|
8424
|
+
}
|
|
8425
|
+
}
|
|
8426
|
+
|
|
8427
|
+
// src/core/collectTocHeadings.ts
|
|
8428
|
+
var MAX_HEADING_LEVEL2 = 6;
|
|
8429
|
+
var MAX_LIST_LEVEL = 9;
|
|
8080
8430
|
function normalizeEntryTitle(text) {
|
|
8081
8431
|
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
8082
8432
|
}
|
|
@@ -8095,9 +8445,97 @@ function styleEntryKey(props) {
|
|
|
8095
8445
|
}
|
|
8096
8446
|
return themeStyle;
|
|
8097
8447
|
}
|
|
8098
|
-
function
|
|
8448
|
+
function levelStart(levels, level) {
|
|
8449
|
+
return levels[level]?.start ?? 1;
|
|
8450
|
+
}
|
|
8451
|
+
function collectDocumentOutline(sections) {
|
|
8099
8452
|
const entries = [];
|
|
8453
|
+
const numberedItems = /* @__PURE__ */ new Map();
|
|
8100
8454
|
const ordinals = computeSectionOrdinals(sections);
|
|
8455
|
+
const takenIds = /* @__PURE__ */ new Set();
|
|
8456
|
+
const headingCounters = new Array(MAX_HEADING_LEVEL2).fill(0);
|
|
8457
|
+
const listCounters = /* @__PURE__ */ new Map();
|
|
8458
|
+
const visitHeading = (component, props, sectionBookmarkId) => {
|
|
8459
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
8460
|
+
const title = normalizeEntryTitle(text);
|
|
8461
|
+
const level = typeof props.level === "number" ? props.level : 1;
|
|
8462
|
+
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL2 ? level : 1;
|
|
8463
|
+
let full;
|
|
8464
|
+
let own;
|
|
8465
|
+
if (props.numbering === true) {
|
|
8466
|
+
headingCounters[styleLevel - 1] += 1;
|
|
8467
|
+
for (let deeper = styleLevel; deeper < MAX_HEADING_LEVEL2; deeper++) {
|
|
8468
|
+
headingCounters[deeper] = 0;
|
|
8469
|
+
}
|
|
8470
|
+
full = headingCounters.slice(0, styleLevel).join(".");
|
|
8471
|
+
own = String(headingCounters[styleLevel - 1]);
|
|
8472
|
+
}
|
|
8473
|
+
const explicitId = component.id;
|
|
8474
|
+
const bookmarkId = typeof explicitId === "string" && explicitId ? explicitId : dedupeBookmarkId(slugifyBookmarkText(text), (id) => takenIds.has(id));
|
|
8475
|
+
takenIds.add(bookmarkId);
|
|
8476
|
+
numberedItems.set(bookmarkId, {
|
|
8477
|
+
kind: "heading",
|
|
8478
|
+
text: title,
|
|
8479
|
+
...full !== void 0 && { full, own }
|
|
8480
|
+
});
|
|
8481
|
+
if (title) {
|
|
8482
|
+
entries.push({
|
|
8483
|
+
title,
|
|
8484
|
+
level,
|
|
8485
|
+
sectionBookmarkId,
|
|
8486
|
+
...full !== void 0 && { number: full }
|
|
8487
|
+
});
|
|
8488
|
+
}
|
|
8489
|
+
};
|
|
8490
|
+
const visitList = (props) => {
|
|
8491
|
+
const items = Array.isArray(props.items) ? props.items : [];
|
|
8492
|
+
if (items.length === 0) return;
|
|
8493
|
+
const reference = typeof props.reference === "string" && props.reference ? props.reference : void 0;
|
|
8494
|
+
const freshState = () => {
|
|
8495
|
+
const levels = resolveListLevels(
|
|
8496
|
+
props
|
|
8497
|
+
);
|
|
8498
|
+
return {
|
|
8499
|
+
levels,
|
|
8500
|
+
counters: Array.from(
|
|
8501
|
+
{ length: MAX_LIST_LEVEL },
|
|
8502
|
+
(_, level) => levelStart(levels, level) - 1
|
|
8503
|
+
)
|
|
8504
|
+
};
|
|
8505
|
+
};
|
|
8506
|
+
let state;
|
|
8507
|
+
if (reference === void 0) {
|
|
8508
|
+
state = freshState();
|
|
8509
|
+
} else {
|
|
8510
|
+
state = listCounters.get(reference) ?? freshState();
|
|
8511
|
+
listCounters.set(reference, state);
|
|
8512
|
+
}
|
|
8513
|
+
for (const item of items) {
|
|
8514
|
+
const isObject = typeof item === "object" && item !== null;
|
|
8515
|
+
const raw = isObject ? item.text : item;
|
|
8516
|
+
const text = typeof raw === "string" ? raw : "";
|
|
8517
|
+
if (!text.trim() && !(isObject && item.revision)) continue;
|
|
8518
|
+
const rawLevel = isObject ? item.level : void 0;
|
|
8519
|
+
const level = typeof rawLevel === "number" && rawLevel >= 0 ? rawLevel : 0;
|
|
8520
|
+
if (level >= MAX_LIST_LEVEL) continue;
|
|
8521
|
+
state.counters[level] += 1;
|
|
8522
|
+
for (let deeper = level + 1; deeper < MAX_LIST_LEVEL; deeper++) {
|
|
8523
|
+
state.counters[deeper] = levelStart(state.levels, deeper) - 1;
|
|
8524
|
+
}
|
|
8525
|
+
const id = isObject ? item.id : void 0;
|
|
8526
|
+
if (typeof id !== "string" || !id) continue;
|
|
8527
|
+
takenIds.add(id);
|
|
8528
|
+
const number = formatNumberForLevel(
|
|
8529
|
+
state.counters[level],
|
|
8530
|
+
state.levels[level]?.format
|
|
8531
|
+
);
|
|
8532
|
+
numberedItems.set(id, {
|
|
8533
|
+
kind: "list-item",
|
|
8534
|
+
text: normalizeUnicodeText(text).trim(),
|
|
8535
|
+
...number !== void 0 && { full: number, own: number }
|
|
8536
|
+
});
|
|
8537
|
+
}
|
|
8538
|
+
};
|
|
8101
8539
|
sections.forEach((section, index) => {
|
|
8102
8540
|
const ordinal = ordinals[index]?.ordinal;
|
|
8103
8541
|
const sectionBookmarkId = ordinal ? globalSectionBookmarkRegistry.forLayoutSection(ordinal).id : void 0;
|
|
@@ -8105,15 +8543,11 @@ function collectTocHeadings(sections) {
|
|
|
8105
8543
|
if (!isEnabled(component)) return;
|
|
8106
8544
|
const props = component.props ?? {};
|
|
8107
8545
|
if (component.name === "heading") {
|
|
8108
|
-
|
|
8109
|
-
const title = normalizeEntryTitle(text);
|
|
8110
|
-
if (title) {
|
|
8111
|
-
const level = typeof props.level === "number" ? props.level : 1;
|
|
8112
|
-
entries.push({ title, level, sectionBookmarkId });
|
|
8113
|
-
}
|
|
8546
|
+
visitHeading(component, props, sectionBookmarkId);
|
|
8114
8547
|
return;
|
|
8115
8548
|
}
|
|
8116
8549
|
if (component.name === "paragraph") {
|
|
8550
|
+
if (typeof props.id === "string" && props.id) takenIds.add(props.id);
|
|
8117
8551
|
const styleId = styleEntryKey(props);
|
|
8118
8552
|
const text = typeof props.text === "string" ? props.text : "";
|
|
8119
8553
|
const title = normalizeEntryTitle(text);
|
|
@@ -8122,13 +8556,17 @@ function collectTocHeadings(sections) {
|
|
|
8122
8556
|
}
|
|
8123
8557
|
return;
|
|
8124
8558
|
}
|
|
8559
|
+
if (component.name === "list") {
|
|
8560
|
+
visitList(props);
|
|
8561
|
+
return;
|
|
8562
|
+
}
|
|
8125
8563
|
if (!isContainer(component.name)) return;
|
|
8126
8564
|
const children = component.children;
|
|
8127
8565
|
if (Array.isArray(children)) children.forEach(visit);
|
|
8128
8566
|
};
|
|
8129
8567
|
section.components.forEach(visit);
|
|
8130
8568
|
});
|
|
8131
|
-
return entries;
|
|
8569
|
+
return { entries, numberedItems };
|
|
8132
8570
|
}
|
|
8133
8571
|
|
|
8134
8572
|
// src/core/render.ts
|
|
@@ -8181,7 +8619,13 @@ async function renderDocument(structure, layout, options) {
|
|
|
8181
8619
|
// Footnote ids are document-scoped too: a reference resolved
|
|
8182
8620
|
// against another render's counter points at the wrong body.
|
|
8183
8621
|
globalNoteRegistry.runScoped(
|
|
8184
|
-
() =>
|
|
8622
|
+
() => (
|
|
8623
|
+
// Cross-reference targets are keyed by bookmark id, which
|
|
8624
|
+
// is only unique within one document.
|
|
8625
|
+
globalNumberedItemsRegistry.runScoped(
|
|
8626
|
+
() => renderDocumentScoped(structure, layout, options)
|
|
8627
|
+
)
|
|
8628
|
+
)
|
|
8185
8629
|
)
|
|
8186
8630
|
)
|
|
8187
8631
|
)
|
|
@@ -8224,13 +8668,14 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
8224
8668
|
);
|
|
8225
8669
|
}
|
|
8226
8670
|
try {
|
|
8227
|
-
const
|
|
8228
|
-
if (
|
|
8229
|
-
context.tocHeadings =
|
|
8671
|
+
const outline = collectDocumentOutline(layout.sections);
|
|
8672
|
+
if (outline.entries.length > 0) {
|
|
8673
|
+
context.tocHeadings = outline.entries;
|
|
8230
8674
|
}
|
|
8675
|
+
globalNumberedItemsRegistry.seed(outline.numberedItems);
|
|
8231
8676
|
} catch (error) {
|
|
8232
8677
|
console.warn(
|
|
8233
|
-
"[core-docx]
|
|
8678
|
+
"[core-docx] Document outline collection failed; the TOC field will rely on the reader refreshing it:",
|
|
8234
8679
|
error instanceof Error ? error.message : error
|
|
8235
8680
|
);
|
|
8236
8681
|
}
|