@json-to-office/core-docx 0.17.0 → 0.17.3
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/core/render.d.ts.map +1 -1
- package/dist/index.js +311 -284
- package/dist/index.js.map +1 -1
- package/dist/plugin/createDocumentGenerator.d.ts.map +1 -1
- package/dist/plugin/example/index.js +311 -284
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -3550,216 +3550,116 @@ function getStyleIdForLevel(level) {
|
|
|
3550
3550
|
return styleMap[level] || "Heading1";
|
|
3551
3551
|
}
|
|
3552
3552
|
|
|
3553
|
-
// src/
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
// src/utils/placeholderProcessor.ts
|
|
3557
|
-
import {
|
|
3558
|
-
TextRun,
|
|
3559
|
-
PageNumber
|
|
3560
|
-
} from "docx";
|
|
3553
|
+
// src/core/render.ts
|
|
3554
|
+
init_styleHelpers();
|
|
3555
|
+
init_layoutUtils();
|
|
3561
3556
|
|
|
3562
|
-
// src/
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3557
|
+
// src/cache/index.ts
|
|
3558
|
+
var cache_exports = {};
|
|
3559
|
+
__export(cache_exports, {
|
|
3560
|
+
CacheKeyGenerator: () => CacheKeyGenerator
|
|
3561
|
+
});
|
|
3562
|
+
__reExport(cache_exports, cache_star);
|
|
3563
|
+
import * as cache_star from "@json-to-office/shared/cache";
|
|
3566
3564
|
|
|
3567
|
-
// src/
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
static register(name, handler) {
|
|
3574
|
-
this.handlers.set(name.toUpperCase(), handler);
|
|
3565
|
+
// src/cache/key-generator.ts
|
|
3566
|
+
import { createHash } from "crypto";
|
|
3567
|
+
var CacheKeyGenerator = class {
|
|
3568
|
+
version;
|
|
3569
|
+
constructor(version = "1.0") {
|
|
3570
|
+
this.version = version;
|
|
3575
3571
|
}
|
|
3576
3572
|
/**
|
|
3577
|
-
*
|
|
3573
|
+
* Generate cache key for a component
|
|
3578
3574
|
*/
|
|
3579
|
-
|
|
3580
|
-
|
|
3575
|
+
generateKey(component, context, options = {}) {
|
|
3576
|
+
const parts = [
|
|
3577
|
+
this.version,
|
|
3578
|
+
component.name,
|
|
3579
|
+
this.hashProps(component.props)
|
|
3580
|
+
];
|
|
3581
|
+
if (options.includeTheme !== false) {
|
|
3582
|
+
parts.push(context.theme.name);
|
|
3583
|
+
}
|
|
3584
|
+
if (options.includeContext) {
|
|
3585
|
+
parts.push(this.hashContext(context));
|
|
3586
|
+
}
|
|
3587
|
+
if (options.additionalKeys) {
|
|
3588
|
+
parts.push(...options.additionalKeys);
|
|
3589
|
+
}
|
|
3590
|
+
if (options.version) {
|
|
3591
|
+
parts.push(options.version);
|
|
3592
|
+
}
|
|
3593
|
+
return parts.join(":");
|
|
3581
3594
|
}
|
|
3582
3595
|
/**
|
|
3583
|
-
*
|
|
3596
|
+
* Hash component props
|
|
3584
3597
|
*/
|
|
3585
|
-
|
|
3586
|
-
|
|
3598
|
+
hashProps(props) {
|
|
3599
|
+
if (!props) return "null";
|
|
3600
|
+
const normalized = this.normalizeObject(props);
|
|
3601
|
+
const json = JSON.stringify(normalized);
|
|
3602
|
+
return this.hash(json);
|
|
3587
3603
|
}
|
|
3588
3604
|
/**
|
|
3589
|
-
*
|
|
3605
|
+
* Hash render context
|
|
3590
3606
|
*/
|
|
3591
|
-
|
|
3592
|
-
|
|
3607
|
+
hashContext(context) {
|
|
3608
|
+
const relevant = {
|
|
3609
|
+
theme: context.theme.name,
|
|
3610
|
+
document: context.document
|
|
3611
|
+
// Exclude runtime properties like sectionIndex, componentIndex
|
|
3612
|
+
};
|
|
3613
|
+
return this.hash(JSON.stringify(relevant));
|
|
3593
3614
|
}
|
|
3594
3615
|
/**
|
|
3595
|
-
*
|
|
3616
|
+
* Normalize object for consistent hashing
|
|
3596
3617
|
*/
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
function processTextWithPlaceholders(text, baseStyle = {}, context = {}) {
|
|
3602
|
-
const normalizedText = normalizeUnicodeText(text);
|
|
3603
|
-
const combinedRegex = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
|
|
3604
|
-
const result = [];
|
|
3605
|
-
let lastIndex = 0;
|
|
3606
|
-
let match;
|
|
3607
|
-
while ((match = combinedRegex.exec(normalizedText)) !== null) {
|
|
3608
|
-
if (match.index > lastIndex) {
|
|
3609
|
-
const beforeText = normalizedText.substring(lastIndex, match.index);
|
|
3610
|
-
if (beforeText) {
|
|
3611
|
-
result.push(...createTextRunsWithNewlines(beforeText, baseStyle));
|
|
3612
|
-
}
|
|
3618
|
+
normalizeObject(obj) {
|
|
3619
|
+
if (obj === null || obj === void 0) return obj;
|
|
3620
|
+
if (Array.isArray(obj)) {
|
|
3621
|
+
return obj.map((item) => this.normalizeObject(item));
|
|
3613
3622
|
}
|
|
3614
|
-
if (
|
|
3615
|
-
|
|
3616
|
-
const handler = PlaceholderRegistry.get(placeholderName);
|
|
3617
|
-
if (handler) {
|
|
3618
|
-
const placeholderResult = handler({ ...context, style: baseStyle });
|
|
3619
|
-
if (Array.isArray(placeholderResult)) {
|
|
3620
|
-
result.push(...placeholderResult);
|
|
3621
|
-
} else if (placeholderResult instanceof TextRun) {
|
|
3622
|
-
result.push(placeholderResult);
|
|
3623
|
-
} else if (typeof placeholderResult === "string") {
|
|
3624
|
-
result.push(
|
|
3625
|
-
...createTextRunsWithNewlines(placeholderResult, baseStyle)
|
|
3626
|
-
);
|
|
3627
|
-
}
|
|
3628
|
-
} else {
|
|
3629
|
-
result.push(...createTextRunsWithNewlines(match[0], baseStyle));
|
|
3630
|
-
}
|
|
3631
|
-
} else {
|
|
3632
|
-
let decoratedText;
|
|
3633
|
-
let bold = baseStyle.bold || false;
|
|
3634
|
-
let italics = baseStyle.italics || false;
|
|
3635
|
-
if (match[1] === "***" || match[1] === "___") {
|
|
3636
|
-
decoratedText = match[2];
|
|
3637
|
-
bold = true;
|
|
3638
|
-
italics = true;
|
|
3639
|
-
} else if (match[3] === "**" || match[3] === "__") {
|
|
3640
|
-
decoratedText = match[4];
|
|
3641
|
-
bold = true;
|
|
3642
|
-
} else if (match[5] === "*" || match[5] === "_") {
|
|
3643
|
-
decoratedText = match[6];
|
|
3644
|
-
italics = true;
|
|
3645
|
-
} else {
|
|
3646
|
-
decoratedText = match[0];
|
|
3647
|
-
}
|
|
3648
|
-
const decoratedTextRuns = processTextWithPlaceholders(
|
|
3649
|
-
decoratedText,
|
|
3650
|
-
{
|
|
3651
|
-
...baseStyle,
|
|
3652
|
-
bold,
|
|
3653
|
-
italics
|
|
3654
|
-
},
|
|
3655
|
-
context
|
|
3656
|
-
);
|
|
3657
|
-
result.push(...decoratedTextRuns);
|
|
3623
|
+
if (obj instanceof Date) {
|
|
3624
|
+
return obj.toISOString();
|
|
3658
3625
|
}
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3626
|
+
if (typeof obj === "object") {
|
|
3627
|
+
const sorted = {};
|
|
3628
|
+
const keys = Object.keys(obj).sort();
|
|
3629
|
+
for (const key of keys) {
|
|
3630
|
+
sorted[key] = this.normalizeObject(obj[key]);
|
|
3631
|
+
}
|
|
3632
|
+
return sorted;
|
|
3665
3633
|
}
|
|
3634
|
+
return obj;
|
|
3666
3635
|
}
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
function createTextRunsWithNewlines(text, baseStyle) {
|
|
3673
|
-
const runs = [];
|
|
3674
|
-
const lines = text.split("\n");
|
|
3675
|
-
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
3676
|
-
const line = lines[lineIndex];
|
|
3677
|
-
const needsLineBreak = lineIndex > 0;
|
|
3678
|
-
if (line || needsLineBreak) {
|
|
3679
|
-
runs.push(
|
|
3680
|
-
new TextRun({
|
|
3681
|
-
text: line,
|
|
3682
|
-
font: baseStyle.font,
|
|
3683
|
-
size: baseStyle.size,
|
|
3684
|
-
color: baseStyle.color,
|
|
3685
|
-
bold: baseStyle.bold,
|
|
3686
|
-
italics: baseStyle.italics,
|
|
3687
|
-
underline: baseStyle.underline,
|
|
3688
|
-
break: needsLineBreak ? 1 : void 0
|
|
3689
|
-
})
|
|
3690
|
-
);
|
|
3691
|
-
}
|
|
3636
|
+
/**
|
|
3637
|
+
* Create hash
|
|
3638
|
+
*/
|
|
3639
|
+
hash(input) {
|
|
3640
|
+
return createHash("sha256").update(input).digest("hex").substring(0, 16);
|
|
3692
3641
|
}
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
color: context?.style?.color,
|
|
3702
|
-
bold: context?.style?.bold,
|
|
3703
|
-
italics: context?.style?.italics,
|
|
3704
|
-
underline: context?.style?.underline
|
|
3705
|
-
});
|
|
3706
|
-
});
|
|
3707
|
-
PlaceholderRegistry.register("TOTAL_PAGES", (context) => {
|
|
3708
|
-
return new TextRun({
|
|
3709
|
-
children: [PageNumber.TOTAL_PAGES],
|
|
3710
|
-
font: context?.style?.font,
|
|
3711
|
-
size: context?.style?.size,
|
|
3712
|
-
color: context?.style?.color,
|
|
3713
|
-
bold: context?.style?.bold,
|
|
3714
|
-
italics: context?.style?.italics,
|
|
3715
|
-
underline: context?.style?.underline
|
|
3716
|
-
});
|
|
3717
|
-
});
|
|
3718
|
-
PlaceholderRegistry.register("DATE", (context) => {
|
|
3719
|
-
const today = /* @__PURE__ */ new Date();
|
|
3720
|
-
const dateString = today.toLocaleDateString();
|
|
3721
|
-
return new TextRun({
|
|
3722
|
-
text: dateString,
|
|
3723
|
-
font: context?.style?.font,
|
|
3724
|
-
size: context?.style?.size,
|
|
3725
|
-
color: context?.style?.color,
|
|
3726
|
-
bold: context?.style?.bold,
|
|
3727
|
-
italics: context?.style?.italics,
|
|
3728
|
-
underline: context?.style?.underline
|
|
3729
|
-
});
|
|
3730
|
-
});
|
|
3731
|
-
PlaceholderRegistry.register("DATETIME", (context) => {
|
|
3732
|
-
const now = /* @__PURE__ */ new Date();
|
|
3733
|
-
const dateTimeString = now.toLocaleString();
|
|
3734
|
-
return new TextRun({
|
|
3735
|
-
text: dateTimeString,
|
|
3736
|
-
font: context?.style?.font,
|
|
3737
|
-
size: context?.style?.size,
|
|
3738
|
-
color: context?.style?.color,
|
|
3739
|
-
bold: context?.style?.bold,
|
|
3740
|
-
italics: context?.style?.italics,
|
|
3741
|
-
underline: context?.style?.underline
|
|
3742
|
-
});
|
|
3743
|
-
});
|
|
3744
|
-
PlaceholderRegistry.register("YEAR", (context) => {
|
|
3745
|
-
const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
3746
|
-
return new TextRun({
|
|
3747
|
-
text: year,
|
|
3748
|
-
font: context?.style?.font,
|
|
3749
|
-
size: context?.style?.size,
|
|
3750
|
-
color: context?.style?.color,
|
|
3751
|
-
bold: context?.style?.bold,
|
|
3752
|
-
italics: context?.style?.italics,
|
|
3753
|
-
underline: context?.style?.underline
|
|
3754
|
-
});
|
|
3755
|
-
});
|
|
3642
|
+
};
|
|
3643
|
+
|
|
3644
|
+
// src/utils/revisionUtils.ts
|
|
3645
|
+
import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
|
|
3646
|
+
|
|
3647
|
+
// src/utils/unicode.ts
|
|
3648
|
+
function normalizeUnicodeText(text) {
|
|
3649
|
+
return (text ?? "").normalize("NFC");
|
|
3756
3650
|
}
|
|
3757
|
-
|
|
3651
|
+
|
|
3652
|
+
// src/utils/placeholderProcessor.ts
|
|
3653
|
+
import {
|
|
3654
|
+
TextRun as TextRun2,
|
|
3655
|
+
PageNumber
|
|
3656
|
+
} from "docx";
|
|
3758
3657
|
|
|
3759
3658
|
// src/utils/textParser.ts
|
|
3659
|
+
import { TextRun, ExternalHyperlink, InternalHyperlink } from "docx";
|
|
3760
3660
|
function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
3761
3661
|
if (!text) {
|
|
3762
|
-
return [new
|
|
3662
|
+
return [new TextRun({ text: "", ...baseStyle })];
|
|
3763
3663
|
}
|
|
3764
3664
|
const normalizedText = normalizeUnicodeText(text);
|
|
3765
3665
|
const hasPlaceholders = /\{[^}]+\}/.test(normalizedText);
|
|
@@ -3781,7 +3681,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3781
3681
|
if (match.index > lastIndex) {
|
|
3782
3682
|
const plainText = normalizedText.substring(lastIndex, match.index);
|
|
3783
3683
|
if (plainText) {
|
|
3784
|
-
runs.push(...
|
|
3684
|
+
runs.push(...createTextRunsWithNewlines(plainText, baseStyle, options));
|
|
3785
3685
|
}
|
|
3786
3686
|
}
|
|
3787
3687
|
let decoratedText;
|
|
@@ -3800,7 +3700,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3800
3700
|
} else {
|
|
3801
3701
|
decoratedText = match[0];
|
|
3802
3702
|
}
|
|
3803
|
-
const decoratedRuns =
|
|
3703
|
+
const decoratedRuns = createTextRunsWithNewlines(
|
|
3804
3704
|
decoratedText,
|
|
3805
3705
|
baseStyle,
|
|
3806
3706
|
options,
|
|
@@ -3816,18 +3716,18 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3816
3716
|
const remainingText = normalizedText.substring(lastIndex);
|
|
3817
3717
|
if (remainingText) {
|
|
3818
3718
|
runs.push(
|
|
3819
|
-
...
|
|
3719
|
+
...createTextRunsWithNewlines(remainingText, baseStyle, options)
|
|
3820
3720
|
);
|
|
3821
3721
|
}
|
|
3822
3722
|
}
|
|
3823
3723
|
if (runs.length === 0 && normalizedText) {
|
|
3824
3724
|
runs.push(
|
|
3825
|
-
...
|
|
3725
|
+
...createTextRunsWithNewlines(normalizedText, baseStyle, options)
|
|
3826
3726
|
);
|
|
3827
3727
|
}
|
|
3828
3728
|
return runs;
|
|
3829
3729
|
}
|
|
3830
|
-
function
|
|
3730
|
+
function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
|
|
3831
3731
|
const runs = [];
|
|
3832
3732
|
const lines = text.split("\n");
|
|
3833
3733
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
@@ -3839,7 +3739,7 @@ function createTextRunsWithNewlines2(text, baseStyle, options, overrideStyle) {
|
|
|
3839
3739
|
italics: overrideStyle?.italics ?? baseStyle.italics
|
|
3840
3740
|
};
|
|
3841
3741
|
runs.push(
|
|
3842
|
-
new
|
|
3742
|
+
new TextRun({
|
|
3843
3743
|
text: line,
|
|
3844
3744
|
...baseStyle.font && { font: baseStyle.font },
|
|
3845
3745
|
...baseStyle.size && { size: baseStyle.size },
|
|
@@ -3885,7 +3785,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3885
3785
|
if (isInternal) {
|
|
3886
3786
|
const bookmarkId = linkUrl.substring(1);
|
|
3887
3787
|
runs.push(
|
|
3888
|
-
new
|
|
3788
|
+
new InternalHyperlink({
|
|
3889
3789
|
children: linkTextRuns,
|
|
3890
3790
|
// Cast needed for docx types
|
|
3891
3791
|
anchor: bookmarkId
|
|
@@ -3893,7 +3793,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3893
3793
|
);
|
|
3894
3794
|
} else {
|
|
3895
3795
|
runs.push(
|
|
3896
|
-
new
|
|
3796
|
+
new ExternalHyperlink({
|
|
3897
3797
|
children: linkTextRuns,
|
|
3898
3798
|
// Cast needed for docx types
|
|
3899
3799
|
link: linkUrl
|
|
@@ -3922,100 +3822,199 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3922
3822
|
return runs;
|
|
3923
3823
|
}
|
|
3924
3824
|
|
|
3925
|
-
// src/
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
CacheKeyGenerator: () => CacheKeyGenerator
|
|
3934
|
-
});
|
|
3935
|
-
__reExport(cache_exports, cache_star);
|
|
3936
|
-
import * as cache_star from "@json-to-office/shared/cache";
|
|
3937
|
-
|
|
3938
|
-
// src/cache/key-generator.ts
|
|
3939
|
-
import { createHash } from "crypto";
|
|
3940
|
-
var CacheKeyGenerator = class {
|
|
3941
|
-
version;
|
|
3942
|
-
constructor(version = "1.0") {
|
|
3943
|
-
this.version = version;
|
|
3825
|
+
// src/utils/placeholderProcessor.ts
|
|
3826
|
+
var PlaceholderRegistry = class {
|
|
3827
|
+
static handlers = /* @__PURE__ */ new Map();
|
|
3828
|
+
/**
|
|
3829
|
+
* Register a placeholder handler
|
|
3830
|
+
*/
|
|
3831
|
+
static register(name, handler) {
|
|
3832
|
+
this.handlers.set(name.toUpperCase(), handler);
|
|
3944
3833
|
}
|
|
3945
3834
|
/**
|
|
3946
|
-
*
|
|
3835
|
+
* Get a placeholder handler
|
|
3947
3836
|
*/
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
this.version,
|
|
3951
|
-
component.name,
|
|
3952
|
-
this.hashProps(component.props)
|
|
3953
|
-
];
|
|
3954
|
-
if (options.includeTheme !== false) {
|
|
3955
|
-
parts.push(context.theme.name);
|
|
3956
|
-
}
|
|
3957
|
-
if (options.includeContext) {
|
|
3958
|
-
parts.push(this.hashContext(context));
|
|
3959
|
-
}
|
|
3960
|
-
if (options.additionalKeys) {
|
|
3961
|
-
parts.push(...options.additionalKeys);
|
|
3962
|
-
}
|
|
3963
|
-
if (options.version) {
|
|
3964
|
-
parts.push(options.version);
|
|
3965
|
-
}
|
|
3966
|
-
return parts.join(":");
|
|
3837
|
+
static get(name) {
|
|
3838
|
+
return this.handlers.get(name.toUpperCase());
|
|
3967
3839
|
}
|
|
3968
3840
|
/**
|
|
3969
|
-
*
|
|
3841
|
+
* Check if a placeholder is registered
|
|
3970
3842
|
*/
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
const normalized = this.normalizeObject(props);
|
|
3974
|
-
const json = JSON.stringify(normalized);
|
|
3975
|
-
return this.hash(json);
|
|
3843
|
+
static has(name) {
|
|
3844
|
+
return this.handlers.has(name.toUpperCase());
|
|
3976
3845
|
}
|
|
3977
3846
|
/**
|
|
3978
|
-
*
|
|
3847
|
+
* Get all registered placeholder names
|
|
3979
3848
|
*/
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
theme: context.theme.name,
|
|
3983
|
-
document: context.document
|
|
3984
|
-
// Exclude runtime properties like sectionIndex, componentIndex
|
|
3985
|
-
};
|
|
3986
|
-
return this.hash(JSON.stringify(relevant));
|
|
3849
|
+
static getRegisteredNames() {
|
|
3850
|
+
return Array.from(this.handlers.keys());
|
|
3987
3851
|
}
|
|
3988
3852
|
/**
|
|
3989
|
-
*
|
|
3853
|
+
* Clear all registered placeholders
|
|
3990
3854
|
*/
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3855
|
+
static clear() {
|
|
3856
|
+
this.handlers.clear();
|
|
3857
|
+
}
|
|
3858
|
+
};
|
|
3859
|
+
function processTextWithPlaceholders(text, baseStyle = {}, context = {}) {
|
|
3860
|
+
const normalizedText = normalizeUnicodeText(text);
|
|
3861
|
+
const combinedRegex = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
|
|
3862
|
+
const result = [];
|
|
3863
|
+
let lastIndex = 0;
|
|
3864
|
+
let match;
|
|
3865
|
+
while ((match = combinedRegex.exec(normalizedText)) !== null) {
|
|
3866
|
+
if (match.index > lastIndex) {
|
|
3867
|
+
const beforeText = normalizedText.substring(lastIndex, match.index);
|
|
3868
|
+
if (beforeText) {
|
|
3869
|
+
result.push(...createTextRunsWithNewlines2(beforeText, baseStyle));
|
|
3870
|
+
}
|
|
3998
3871
|
}
|
|
3999
|
-
if (
|
|
4000
|
-
const
|
|
4001
|
-
const
|
|
4002
|
-
|
|
4003
|
-
|
|
3872
|
+
if (match[7]) {
|
|
3873
|
+
const placeholderName = match[7];
|
|
3874
|
+
const handler = PlaceholderRegistry.get(placeholderName);
|
|
3875
|
+
if (handler) {
|
|
3876
|
+
const placeholderResult = handler({ ...context, style: baseStyle });
|
|
3877
|
+
if (Array.isArray(placeholderResult)) {
|
|
3878
|
+
result.push(...placeholderResult);
|
|
3879
|
+
} else if (placeholderResult instanceof TextRun2) {
|
|
3880
|
+
result.push(placeholderResult);
|
|
3881
|
+
} else if (typeof placeholderResult === "string") {
|
|
3882
|
+
result.push(
|
|
3883
|
+
...createTextRunsWithNewlines2(placeholderResult, baseStyle)
|
|
3884
|
+
);
|
|
3885
|
+
}
|
|
3886
|
+
} else {
|
|
3887
|
+
result.push(...createTextRunsWithNewlines2(match[0], baseStyle));
|
|
4004
3888
|
}
|
|
4005
|
-
|
|
3889
|
+
} else {
|
|
3890
|
+
let decoratedText;
|
|
3891
|
+
let bold = baseStyle.bold || false;
|
|
3892
|
+
let italics = baseStyle.italics || false;
|
|
3893
|
+
if (match[1] === "***" || match[1] === "___") {
|
|
3894
|
+
decoratedText = match[2];
|
|
3895
|
+
bold = true;
|
|
3896
|
+
italics = true;
|
|
3897
|
+
} else if (match[3] === "**" || match[3] === "__") {
|
|
3898
|
+
decoratedText = match[4];
|
|
3899
|
+
bold = true;
|
|
3900
|
+
} else if (match[5] === "*" || match[5] === "_") {
|
|
3901
|
+
decoratedText = match[6];
|
|
3902
|
+
italics = true;
|
|
3903
|
+
} else {
|
|
3904
|
+
decoratedText = match[0];
|
|
3905
|
+
}
|
|
3906
|
+
const decoratedTextRuns = processTextWithPlaceholders(
|
|
3907
|
+
decoratedText,
|
|
3908
|
+
{
|
|
3909
|
+
...baseStyle,
|
|
3910
|
+
bold,
|
|
3911
|
+
italics
|
|
3912
|
+
},
|
|
3913
|
+
context
|
|
3914
|
+
);
|
|
3915
|
+
result.push(...decoratedTextRuns);
|
|
4006
3916
|
}
|
|
4007
|
-
|
|
3917
|
+
lastIndex = match.index + match[0].length;
|
|
4008
3918
|
}
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
3919
|
+
if (lastIndex < normalizedText.length) {
|
|
3920
|
+
const remainingText = normalizedText.substring(lastIndex);
|
|
3921
|
+
if (remainingText) {
|
|
3922
|
+
result.push(...createTextRunsWithNewlines2(remainingText, baseStyle));
|
|
3923
|
+
}
|
|
4014
3924
|
}
|
|
4015
|
-
|
|
3925
|
+
if (result.length === 0 && normalizedText) {
|
|
3926
|
+
result.push(...createTextRunsWithNewlines2(normalizedText, baseStyle));
|
|
3927
|
+
}
|
|
3928
|
+
return result;
|
|
3929
|
+
}
|
|
3930
|
+
function createTextRunsWithNewlines2(text, baseStyle) {
|
|
3931
|
+
const runs = [];
|
|
3932
|
+
const lines = text.split("\n");
|
|
3933
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
3934
|
+
const line = lines[lineIndex];
|
|
3935
|
+
const needsLineBreak = lineIndex > 0;
|
|
3936
|
+
if (line || needsLineBreak) {
|
|
3937
|
+
runs.push(
|
|
3938
|
+
new TextRun2({
|
|
3939
|
+
text: line,
|
|
3940
|
+
font: baseStyle.font,
|
|
3941
|
+
size: baseStyle.size,
|
|
3942
|
+
color: baseStyle.color,
|
|
3943
|
+
bold: baseStyle.bold,
|
|
3944
|
+
italics: baseStyle.italics,
|
|
3945
|
+
underline: baseStyle.underline,
|
|
3946
|
+
break: needsLineBreak ? 1 : void 0
|
|
3947
|
+
})
|
|
3948
|
+
);
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
return runs;
|
|
3952
|
+
}
|
|
3953
|
+
function initializeBuiltinPlaceholders() {
|
|
3954
|
+
PlaceholderRegistry.register("PAGE", (context) => {
|
|
3955
|
+
return new TextRun2({
|
|
3956
|
+
children: [PageNumber.CURRENT],
|
|
3957
|
+
font: context?.style?.font,
|
|
3958
|
+
size: context?.style?.size,
|
|
3959
|
+
color: context?.style?.color,
|
|
3960
|
+
bold: context?.style?.bold,
|
|
3961
|
+
italics: context?.style?.italics,
|
|
3962
|
+
underline: context?.style?.underline
|
|
3963
|
+
});
|
|
3964
|
+
});
|
|
3965
|
+
PlaceholderRegistry.register("TOTAL_PAGES", (context) => {
|
|
3966
|
+
return new TextRun2({
|
|
3967
|
+
children: [PageNumber.TOTAL_PAGES],
|
|
3968
|
+
font: context?.style?.font,
|
|
3969
|
+
size: context?.style?.size,
|
|
3970
|
+
color: context?.style?.color,
|
|
3971
|
+
bold: context?.style?.bold,
|
|
3972
|
+
italics: context?.style?.italics,
|
|
3973
|
+
underline: context?.style?.underline
|
|
3974
|
+
});
|
|
3975
|
+
});
|
|
3976
|
+
PlaceholderRegistry.register("DATE", (context) => {
|
|
3977
|
+
const today = /* @__PURE__ */ new Date();
|
|
3978
|
+
const dateString = today.toLocaleDateString();
|
|
3979
|
+
return new TextRun2({
|
|
3980
|
+
text: dateString,
|
|
3981
|
+
font: context?.style?.font,
|
|
3982
|
+
size: context?.style?.size,
|
|
3983
|
+
color: context?.style?.color,
|
|
3984
|
+
bold: context?.style?.bold,
|
|
3985
|
+
italics: context?.style?.italics,
|
|
3986
|
+
underline: context?.style?.underline
|
|
3987
|
+
});
|
|
3988
|
+
});
|
|
3989
|
+
PlaceholderRegistry.register("DATETIME", (context) => {
|
|
3990
|
+
const now = /* @__PURE__ */ new Date();
|
|
3991
|
+
const dateTimeString = now.toLocaleString();
|
|
3992
|
+
return new TextRun2({
|
|
3993
|
+
text: dateTimeString,
|
|
3994
|
+
font: context?.style?.font,
|
|
3995
|
+
size: context?.style?.size,
|
|
3996
|
+
color: context?.style?.color,
|
|
3997
|
+
bold: context?.style?.bold,
|
|
3998
|
+
italics: context?.style?.italics,
|
|
3999
|
+
underline: context?.style?.underline
|
|
4000
|
+
});
|
|
4001
|
+
});
|
|
4002
|
+
PlaceholderRegistry.register("YEAR", (context) => {
|
|
4003
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
4004
|
+
return new TextRun2({
|
|
4005
|
+
text: year,
|
|
4006
|
+
font: context?.style?.font,
|
|
4007
|
+
size: context?.style?.size,
|
|
4008
|
+
color: context?.style?.color,
|
|
4009
|
+
bold: context?.style?.bold,
|
|
4010
|
+
italics: context?.style?.italics,
|
|
4011
|
+
underline: context?.style?.underline
|
|
4012
|
+
});
|
|
4013
|
+
});
|
|
4014
|
+
}
|
|
4015
|
+
initializeBuiltinPlaceholders();
|
|
4016
4016
|
|
|
4017
4017
|
// src/utils/revisionUtils.ts
|
|
4018
|
-
import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
|
|
4019
4018
|
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
4020
4019
|
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
4021
4020
|
var RevisionIdRegistry = class {
|
|
@@ -6772,21 +6771,26 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
6772
6771
|
for (const component of activeComponents) {
|
|
6773
6772
|
if (isParagraphComponent(component)) {
|
|
6774
6773
|
const textComp = component;
|
|
6774
|
+
const font = textComp.props.font;
|
|
6775
6775
|
const normalStyle = getNormalStyle(theme);
|
|
6776
|
-
const textStyle = {
|
|
6777
|
-
font: textComp.props.font?.family || resolveFontFamily(theme, normalStyle.font) || getThemeFonts(theme).body.family,
|
|
6778
|
-
size: (textComp.props.font?.size ?? normalStyle.size ?? 11) * 2,
|
|
6779
|
-
// Convert to half-points
|
|
6780
|
-
bold: textComp.props.font?.bold ?? false,
|
|
6781
|
-
italics: textComp.props.font?.italic ?? false,
|
|
6782
|
-
color: textComp.props.font?.color && resolveColor(textComp.props.font.color, theme) || normalStyle.color && resolveColor(normalStyle.color, theme) || getThemeColors(theme).textPrimary
|
|
6783
|
-
};
|
|
6784
|
-
const textRuns = parseTextWithDecorators(textComp.props.text, textStyle);
|
|
6785
6776
|
elements.push(
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
alignment: textComp.props.alignment
|
|
6789
|
-
style
|
|
6777
|
+
createText(textComp.props.text, theme, themeName, {
|
|
6778
|
+
style: "Normal",
|
|
6779
|
+
alignment: textComp.props.alignment,
|
|
6780
|
+
// Resolve explicit run styling against the Normal style, preserving
|
|
6781
|
+
// prior header/footer rendering for these properties.
|
|
6782
|
+
fontFamily: font?.family || resolveFontFamily(theme, normalStyle.font) || getThemeFonts(theme).body.family,
|
|
6783
|
+
fontSize: font?.size ?? normalStyle.size ?? 11,
|
|
6784
|
+
// Pass the raw color/token; createText resolves it. Fall back to the
|
|
6785
|
+
// Normal style color, then the theme's primary text color.
|
|
6786
|
+
fontColor: font?.color || normalStyle.color || "textPrimary",
|
|
6787
|
+
bold: font?.bold ?? false,
|
|
6788
|
+
italic: font?.italic ?? false,
|
|
6789
|
+
underline: font?.underline,
|
|
6790
|
+
fontWeight: font?.fontWeight,
|
|
6791
|
+
boldColor: textComp.props.boldColor,
|
|
6792
|
+
spacing: textComp.props.spacing,
|
|
6793
|
+
lineSpacing: font?.lineSpacing
|
|
6790
6794
|
})
|
|
6791
6795
|
);
|
|
6792
6796
|
} else if (isImageComponent(component)) {
|
|
@@ -7133,7 +7137,7 @@ function createBuilderImpl(state) {
|
|
|
7133
7137
|
}
|
|
7134
7138
|
return getThemeWithFallback(themeName);
|
|
7135
7139
|
}
|
|
7136
|
-
async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, depth = 0) {
|
|
7140
|
+
async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, validateEmitted, depth = 0) {
|
|
7137
7141
|
if (depth > 20) {
|
|
7138
7142
|
throw new Error(
|
|
7139
7143
|
"Maximum component nesting depth exceeded (20). Check for circular component references."
|
|
@@ -7173,6 +7177,7 @@ function createBuilderImpl(state) {
|
|
|
7173
7177
|
preserveSet,
|
|
7174
7178
|
warningsCollector,
|
|
7175
7179
|
resolvedTheme,
|
|
7180
|
+
validateEmitted,
|
|
7176
7181
|
depth + 1
|
|
7177
7182
|
);
|
|
7178
7183
|
nestedChildren = nested.standard;
|
|
@@ -7193,11 +7198,15 @@ function createBuilderImpl(state) {
|
|
|
7193
7198
|
children: nestedChildren
|
|
7194
7199
|
});
|
|
7195
7200
|
const resultComponents = Array.isArray(result) ? result : [result];
|
|
7201
|
+
if (validateEmitted) {
|
|
7202
|
+
validateEmitted(resultComponents, versionLabel);
|
|
7203
|
+
}
|
|
7196
7204
|
const processedResult = await processDocumentComponents(
|
|
7197
7205
|
resultComponents,
|
|
7198
7206
|
preserveSet,
|
|
7199
7207
|
warningsCollector,
|
|
7200
7208
|
resolvedTheme,
|
|
7209
|
+
validateEmitted,
|
|
7201
7210
|
depth + 1
|
|
7202
7211
|
);
|
|
7203
7212
|
standardOut.push(...processedResult.standard);
|
|
@@ -7227,6 +7236,7 @@ function createBuilderImpl(state) {
|
|
|
7227
7236
|
preserveSet,
|
|
7228
7237
|
warningsCollector,
|
|
7229
7238
|
resolvedTheme,
|
|
7239
|
+
validateEmitted,
|
|
7230
7240
|
depth + 1
|
|
7231
7241
|
);
|
|
7232
7242
|
standardOut.push({
|
|
@@ -7307,6 +7317,22 @@ function createBuilderImpl(state) {
|
|
|
7307
7317
|
);
|
|
7308
7318
|
}
|
|
7309
7319
|
}
|
|
7320
|
+
const validateEmitted = vOpts.enabled === false ? void 0 : (emitted, componentLabel) => {
|
|
7321
|
+
const result = validateDocument(
|
|
7322
|
+
{ ...internalDocument, children: emitted },
|
|
7323
|
+
state.components,
|
|
7324
|
+
{ allowUnknownFields: vOpts.allowUnknownFields }
|
|
7325
|
+
);
|
|
7326
|
+
if (!result.valid) {
|
|
7327
|
+
throw new ComponentValidationError2(
|
|
7328
|
+
(result.errors ?? []).map((e) => ({
|
|
7329
|
+
path: e.path ?? "",
|
|
7330
|
+
message: `custom component '${componentLabel}' emitted invalid output \u2014 ${e.message}`
|
|
7331
|
+
})),
|
|
7332
|
+
emitted
|
|
7333
|
+
);
|
|
7334
|
+
}
|
|
7335
|
+
};
|
|
7310
7336
|
const baseThemeName = internalDocument.props.theme || "minimal";
|
|
7311
7337
|
const docTheme = resolveDocumentTheme(baseThemeName);
|
|
7312
7338
|
const warnings = [];
|
|
@@ -7329,7 +7355,8 @@ function createBuilderImpl(state) {
|
|
|
7329
7355
|
mode.doc.children || [],
|
|
7330
7356
|
preserveSet,
|
|
7331
7357
|
warnings,
|
|
7332
|
-
modedTheme
|
|
7358
|
+
modedTheme,
|
|
7359
|
+
validateEmitted
|
|
7333
7360
|
);
|
|
7334
7361
|
const processedDocument = {
|
|
7335
7362
|
...mode.doc,
|