@json-to-office/core-docx 0.17.1 → 0.18.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/highcharts.d.ts.map +1 -1
- package/dist/components/image.d.ts.map +1 -1
- package/dist/core/content.d.ts.map +1 -1
- package/dist/core/render.d.ts.map +1 -1
- package/dist/index.js +310 -292
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/eldermoor-census.component.d.ts +32 -0
- package/dist/plugin/example/eldermoor-census.component.d.ts.map +1 -0
- package/dist/plugin/example/index.js +310 -292
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/templates/themes/index.d.ts +4 -0
- package/dist/templates/themes/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/imageUtils.d.ts +13 -0
- package/dist/utils/imageUtils.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -2849,6 +2849,16 @@ async function downloadImageFromUrl(url) {
|
|
|
2849
2849
|
throw new Error(`Failed to download image from ${url}: Unknown error`);
|
|
2850
2850
|
}
|
|
2851
2851
|
}
|
|
2852
|
+
function resolveImageSource(props) {
|
|
2853
|
+
const hasValue = (v) => typeof v === "string" && v.trim().length > 0;
|
|
2854
|
+
if (hasValue(props.svg)) {
|
|
2855
|
+
const encoded = Buffer.from(props.svg, "utf-8").toString("base64");
|
|
2856
|
+
return `data:image/svg+xml;base64,${encoded}`;
|
|
2857
|
+
}
|
|
2858
|
+
if (hasValue(props.base64)) return props.base64;
|
|
2859
|
+
if (hasValue(props.path)) return props.path;
|
|
2860
|
+
return void 0;
|
|
2861
|
+
}
|
|
2852
2862
|
async function getImageBuffer(imagePath) {
|
|
2853
2863
|
if (isBase64Image(imagePath)) {
|
|
2854
2864
|
return { buffer: decodeBase64Image(imagePath) };
|
|
@@ -3550,216 +3560,116 @@ function getStyleIdForLevel(level) {
|
|
|
3550
3560
|
return styleMap[level] || "Heading1";
|
|
3551
3561
|
}
|
|
3552
3562
|
|
|
3553
|
-
// src/
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
// src/utils/placeholderProcessor.ts
|
|
3557
|
-
import {
|
|
3558
|
-
TextRun,
|
|
3559
|
-
PageNumber
|
|
3560
|
-
} from "docx";
|
|
3563
|
+
// src/core/render.ts
|
|
3564
|
+
init_styleHelpers();
|
|
3565
|
+
init_layoutUtils();
|
|
3561
3566
|
|
|
3562
|
-
// src/
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3567
|
+
// src/cache/index.ts
|
|
3568
|
+
var cache_exports = {};
|
|
3569
|
+
__export(cache_exports, {
|
|
3570
|
+
CacheKeyGenerator: () => CacheKeyGenerator
|
|
3571
|
+
});
|
|
3572
|
+
__reExport(cache_exports, cache_star);
|
|
3573
|
+
import * as cache_star from "@json-to-office/shared/cache";
|
|
3566
3574
|
|
|
3567
|
-
// src/
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
static register(name, handler) {
|
|
3574
|
-
this.handlers.set(name.toUpperCase(), handler);
|
|
3575
|
+
// src/cache/key-generator.ts
|
|
3576
|
+
import { createHash } from "crypto";
|
|
3577
|
+
var CacheKeyGenerator = class {
|
|
3578
|
+
version;
|
|
3579
|
+
constructor(version = "1.0") {
|
|
3580
|
+
this.version = version;
|
|
3575
3581
|
}
|
|
3576
3582
|
/**
|
|
3577
|
-
*
|
|
3583
|
+
* Generate cache key for a component
|
|
3578
3584
|
*/
|
|
3579
|
-
|
|
3580
|
-
|
|
3585
|
+
generateKey(component, context, options = {}) {
|
|
3586
|
+
const parts = [
|
|
3587
|
+
this.version,
|
|
3588
|
+
component.name,
|
|
3589
|
+
this.hashProps(component.props)
|
|
3590
|
+
];
|
|
3591
|
+
if (options.includeTheme !== false) {
|
|
3592
|
+
parts.push(context.theme.name);
|
|
3593
|
+
}
|
|
3594
|
+
if (options.includeContext) {
|
|
3595
|
+
parts.push(this.hashContext(context));
|
|
3596
|
+
}
|
|
3597
|
+
if (options.additionalKeys) {
|
|
3598
|
+
parts.push(...options.additionalKeys);
|
|
3599
|
+
}
|
|
3600
|
+
if (options.version) {
|
|
3601
|
+
parts.push(options.version);
|
|
3602
|
+
}
|
|
3603
|
+
return parts.join(":");
|
|
3581
3604
|
}
|
|
3582
3605
|
/**
|
|
3583
|
-
*
|
|
3606
|
+
* Hash component props
|
|
3584
3607
|
*/
|
|
3585
|
-
|
|
3586
|
-
|
|
3608
|
+
hashProps(props) {
|
|
3609
|
+
if (!props) return "null";
|
|
3610
|
+
const normalized = this.normalizeObject(props);
|
|
3611
|
+
const json = JSON.stringify(normalized);
|
|
3612
|
+
return this.hash(json);
|
|
3587
3613
|
}
|
|
3588
3614
|
/**
|
|
3589
|
-
*
|
|
3615
|
+
* Hash render context
|
|
3590
3616
|
*/
|
|
3591
|
-
|
|
3592
|
-
|
|
3617
|
+
hashContext(context) {
|
|
3618
|
+
const relevant = {
|
|
3619
|
+
theme: context.theme.name,
|
|
3620
|
+
document: context.document
|
|
3621
|
+
// Exclude runtime properties like sectionIndex, componentIndex
|
|
3622
|
+
};
|
|
3623
|
+
return this.hash(JSON.stringify(relevant));
|
|
3593
3624
|
}
|
|
3594
3625
|
/**
|
|
3595
|
-
*
|
|
3626
|
+
* Normalize object for consistent hashing
|
|
3596
3627
|
*/
|
|
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
|
-
}
|
|
3628
|
+
normalizeObject(obj) {
|
|
3629
|
+
if (obj === null || obj === void 0) return obj;
|
|
3630
|
+
if (Array.isArray(obj)) {
|
|
3631
|
+
return obj.map((item) => this.normalizeObject(item));
|
|
3613
3632
|
}
|
|
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);
|
|
3633
|
+
if (obj instanceof Date) {
|
|
3634
|
+
return obj.toISOString();
|
|
3658
3635
|
}
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3636
|
+
if (typeof obj === "object") {
|
|
3637
|
+
const sorted = {};
|
|
3638
|
+
const keys = Object.keys(obj).sort();
|
|
3639
|
+
for (const key of keys) {
|
|
3640
|
+
sorted[key] = this.normalizeObject(obj[key]);
|
|
3641
|
+
}
|
|
3642
|
+
return sorted;
|
|
3665
3643
|
}
|
|
3644
|
+
return obj;
|
|
3666
3645
|
}
|
|
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
|
-
}
|
|
3646
|
+
/**
|
|
3647
|
+
* Create hash
|
|
3648
|
+
*/
|
|
3649
|
+
hash(input) {
|
|
3650
|
+
return createHash("sha256").update(input).digest("hex").substring(0, 16);
|
|
3692
3651
|
}
|
|
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
|
-
});
|
|
3652
|
+
};
|
|
3653
|
+
|
|
3654
|
+
// src/utils/revisionUtils.ts
|
|
3655
|
+
import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
|
|
3656
|
+
|
|
3657
|
+
// src/utils/unicode.ts
|
|
3658
|
+
function normalizeUnicodeText(text) {
|
|
3659
|
+
return (text ?? "").normalize("NFC");
|
|
3756
3660
|
}
|
|
3757
|
-
|
|
3661
|
+
|
|
3662
|
+
// src/utils/placeholderProcessor.ts
|
|
3663
|
+
import {
|
|
3664
|
+
TextRun as TextRun2,
|
|
3665
|
+
PageNumber
|
|
3666
|
+
} from "docx";
|
|
3758
3667
|
|
|
3759
3668
|
// src/utils/textParser.ts
|
|
3669
|
+
import { TextRun, ExternalHyperlink, InternalHyperlink } from "docx";
|
|
3760
3670
|
function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
3761
3671
|
if (!text) {
|
|
3762
|
-
return [new
|
|
3672
|
+
return [new TextRun({ text: "", ...baseStyle })];
|
|
3763
3673
|
}
|
|
3764
3674
|
const normalizedText = normalizeUnicodeText(text);
|
|
3765
3675
|
const hasPlaceholders = /\{[^}]+\}/.test(normalizedText);
|
|
@@ -3781,7 +3691,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3781
3691
|
if (match.index > lastIndex) {
|
|
3782
3692
|
const plainText = normalizedText.substring(lastIndex, match.index);
|
|
3783
3693
|
if (plainText) {
|
|
3784
|
-
runs.push(...
|
|
3694
|
+
runs.push(...createTextRunsWithNewlines(plainText, baseStyle, options));
|
|
3785
3695
|
}
|
|
3786
3696
|
}
|
|
3787
3697
|
let decoratedText;
|
|
@@ -3800,7 +3710,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3800
3710
|
} else {
|
|
3801
3711
|
decoratedText = match[0];
|
|
3802
3712
|
}
|
|
3803
|
-
const decoratedRuns =
|
|
3713
|
+
const decoratedRuns = createTextRunsWithNewlines(
|
|
3804
3714
|
decoratedText,
|
|
3805
3715
|
baseStyle,
|
|
3806
3716
|
options,
|
|
@@ -3816,18 +3726,18 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3816
3726
|
const remainingText = normalizedText.substring(lastIndex);
|
|
3817
3727
|
if (remainingText) {
|
|
3818
3728
|
runs.push(
|
|
3819
|
-
...
|
|
3729
|
+
...createTextRunsWithNewlines(remainingText, baseStyle, options)
|
|
3820
3730
|
);
|
|
3821
3731
|
}
|
|
3822
3732
|
}
|
|
3823
3733
|
if (runs.length === 0 && normalizedText) {
|
|
3824
3734
|
runs.push(
|
|
3825
|
-
...
|
|
3735
|
+
...createTextRunsWithNewlines(normalizedText, baseStyle, options)
|
|
3826
3736
|
);
|
|
3827
3737
|
}
|
|
3828
3738
|
return runs;
|
|
3829
3739
|
}
|
|
3830
|
-
function
|
|
3740
|
+
function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
|
|
3831
3741
|
const runs = [];
|
|
3832
3742
|
const lines = text.split("\n");
|
|
3833
3743
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
@@ -3839,7 +3749,7 @@ function createTextRunsWithNewlines2(text, baseStyle, options, overrideStyle) {
|
|
|
3839
3749
|
italics: overrideStyle?.italics ?? baseStyle.italics
|
|
3840
3750
|
};
|
|
3841
3751
|
runs.push(
|
|
3842
|
-
new
|
|
3752
|
+
new TextRun({
|
|
3843
3753
|
text: line,
|
|
3844
3754
|
...baseStyle.font && { font: baseStyle.font },
|
|
3845
3755
|
...baseStyle.size && { size: baseStyle.size },
|
|
@@ -3885,7 +3795,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3885
3795
|
if (isInternal) {
|
|
3886
3796
|
const bookmarkId = linkUrl.substring(1);
|
|
3887
3797
|
runs.push(
|
|
3888
|
-
new
|
|
3798
|
+
new InternalHyperlink({
|
|
3889
3799
|
children: linkTextRuns,
|
|
3890
3800
|
// Cast needed for docx types
|
|
3891
3801
|
anchor: bookmarkId
|
|
@@ -3893,7 +3803,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3893
3803
|
);
|
|
3894
3804
|
} else {
|
|
3895
3805
|
runs.push(
|
|
3896
|
-
new
|
|
3806
|
+
new ExternalHyperlink({
|
|
3897
3807
|
children: linkTextRuns,
|
|
3898
3808
|
// Cast needed for docx types
|
|
3899
3809
|
link: linkUrl
|
|
@@ -3922,100 +3832,199 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3922
3832
|
return runs;
|
|
3923
3833
|
}
|
|
3924
3834
|
|
|
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;
|
|
3835
|
+
// src/utils/placeholderProcessor.ts
|
|
3836
|
+
var PlaceholderRegistry = class {
|
|
3837
|
+
static handlers = /* @__PURE__ */ new Map();
|
|
3838
|
+
/**
|
|
3839
|
+
* Register a placeholder handler
|
|
3840
|
+
*/
|
|
3841
|
+
static register(name, handler) {
|
|
3842
|
+
this.handlers.set(name.toUpperCase(), handler);
|
|
3944
3843
|
}
|
|
3945
3844
|
/**
|
|
3946
|
-
*
|
|
3845
|
+
* Get a placeholder handler
|
|
3947
3846
|
*/
|
|
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(":");
|
|
3847
|
+
static get(name) {
|
|
3848
|
+
return this.handlers.get(name.toUpperCase());
|
|
3967
3849
|
}
|
|
3968
3850
|
/**
|
|
3969
|
-
*
|
|
3851
|
+
* Check if a placeholder is registered
|
|
3970
3852
|
*/
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
const normalized = this.normalizeObject(props);
|
|
3974
|
-
const json = JSON.stringify(normalized);
|
|
3975
|
-
return this.hash(json);
|
|
3853
|
+
static has(name) {
|
|
3854
|
+
return this.handlers.has(name.toUpperCase());
|
|
3976
3855
|
}
|
|
3977
3856
|
/**
|
|
3978
|
-
*
|
|
3857
|
+
* Get all registered placeholder names
|
|
3979
3858
|
*/
|
|
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));
|
|
3859
|
+
static getRegisteredNames() {
|
|
3860
|
+
return Array.from(this.handlers.keys());
|
|
3987
3861
|
}
|
|
3988
3862
|
/**
|
|
3989
|
-
*
|
|
3863
|
+
* Clear all registered placeholders
|
|
3990
3864
|
*/
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3865
|
+
static clear() {
|
|
3866
|
+
this.handlers.clear();
|
|
3867
|
+
}
|
|
3868
|
+
};
|
|
3869
|
+
function processTextWithPlaceholders(text, baseStyle = {}, context = {}) {
|
|
3870
|
+
const normalizedText = normalizeUnicodeText(text);
|
|
3871
|
+
const combinedRegex = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
|
|
3872
|
+
const result = [];
|
|
3873
|
+
let lastIndex = 0;
|
|
3874
|
+
let match;
|
|
3875
|
+
while ((match = combinedRegex.exec(normalizedText)) !== null) {
|
|
3876
|
+
if (match.index > lastIndex) {
|
|
3877
|
+
const beforeText = normalizedText.substring(lastIndex, match.index);
|
|
3878
|
+
if (beforeText) {
|
|
3879
|
+
result.push(...createTextRunsWithNewlines2(beforeText, baseStyle));
|
|
3880
|
+
}
|
|
3998
3881
|
}
|
|
3999
|
-
if (
|
|
4000
|
-
const
|
|
4001
|
-
const
|
|
4002
|
-
|
|
4003
|
-
|
|
3882
|
+
if (match[7]) {
|
|
3883
|
+
const placeholderName = match[7];
|
|
3884
|
+
const handler = PlaceholderRegistry.get(placeholderName);
|
|
3885
|
+
if (handler) {
|
|
3886
|
+
const placeholderResult = handler({ ...context, style: baseStyle });
|
|
3887
|
+
if (Array.isArray(placeholderResult)) {
|
|
3888
|
+
result.push(...placeholderResult);
|
|
3889
|
+
} else if (placeholderResult instanceof TextRun2) {
|
|
3890
|
+
result.push(placeholderResult);
|
|
3891
|
+
} else if (typeof placeholderResult === "string") {
|
|
3892
|
+
result.push(
|
|
3893
|
+
...createTextRunsWithNewlines2(placeholderResult, baseStyle)
|
|
3894
|
+
);
|
|
3895
|
+
}
|
|
3896
|
+
} else {
|
|
3897
|
+
result.push(...createTextRunsWithNewlines2(match[0], baseStyle));
|
|
4004
3898
|
}
|
|
4005
|
-
|
|
3899
|
+
} else {
|
|
3900
|
+
let decoratedText;
|
|
3901
|
+
let bold = baseStyle.bold || false;
|
|
3902
|
+
let italics = baseStyle.italics || false;
|
|
3903
|
+
if (match[1] === "***" || match[1] === "___") {
|
|
3904
|
+
decoratedText = match[2];
|
|
3905
|
+
bold = true;
|
|
3906
|
+
italics = true;
|
|
3907
|
+
} else if (match[3] === "**" || match[3] === "__") {
|
|
3908
|
+
decoratedText = match[4];
|
|
3909
|
+
bold = true;
|
|
3910
|
+
} else if (match[5] === "*" || match[5] === "_") {
|
|
3911
|
+
decoratedText = match[6];
|
|
3912
|
+
italics = true;
|
|
3913
|
+
} else {
|
|
3914
|
+
decoratedText = match[0];
|
|
3915
|
+
}
|
|
3916
|
+
const decoratedTextRuns = processTextWithPlaceholders(
|
|
3917
|
+
decoratedText,
|
|
3918
|
+
{
|
|
3919
|
+
...baseStyle,
|
|
3920
|
+
bold,
|
|
3921
|
+
italics
|
|
3922
|
+
},
|
|
3923
|
+
context
|
|
3924
|
+
);
|
|
3925
|
+
result.push(...decoratedTextRuns);
|
|
4006
3926
|
}
|
|
4007
|
-
|
|
3927
|
+
lastIndex = match.index + match[0].length;
|
|
4008
3928
|
}
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
3929
|
+
if (lastIndex < normalizedText.length) {
|
|
3930
|
+
const remainingText = normalizedText.substring(lastIndex);
|
|
3931
|
+
if (remainingText) {
|
|
3932
|
+
result.push(...createTextRunsWithNewlines2(remainingText, baseStyle));
|
|
3933
|
+
}
|
|
4014
3934
|
}
|
|
4015
|
-
|
|
3935
|
+
if (result.length === 0 && normalizedText) {
|
|
3936
|
+
result.push(...createTextRunsWithNewlines2(normalizedText, baseStyle));
|
|
3937
|
+
}
|
|
3938
|
+
return result;
|
|
3939
|
+
}
|
|
3940
|
+
function createTextRunsWithNewlines2(text, baseStyle) {
|
|
3941
|
+
const runs = [];
|
|
3942
|
+
const lines = text.split("\n");
|
|
3943
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
3944
|
+
const line = lines[lineIndex];
|
|
3945
|
+
const needsLineBreak = lineIndex > 0;
|
|
3946
|
+
if (line || needsLineBreak) {
|
|
3947
|
+
runs.push(
|
|
3948
|
+
new TextRun2({
|
|
3949
|
+
text: line,
|
|
3950
|
+
font: baseStyle.font,
|
|
3951
|
+
size: baseStyle.size,
|
|
3952
|
+
color: baseStyle.color,
|
|
3953
|
+
bold: baseStyle.bold,
|
|
3954
|
+
italics: baseStyle.italics,
|
|
3955
|
+
underline: baseStyle.underline,
|
|
3956
|
+
break: needsLineBreak ? 1 : void 0
|
|
3957
|
+
})
|
|
3958
|
+
);
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
return runs;
|
|
3962
|
+
}
|
|
3963
|
+
function initializeBuiltinPlaceholders() {
|
|
3964
|
+
PlaceholderRegistry.register("PAGE", (context) => {
|
|
3965
|
+
return new TextRun2({
|
|
3966
|
+
children: [PageNumber.CURRENT],
|
|
3967
|
+
font: context?.style?.font,
|
|
3968
|
+
size: context?.style?.size,
|
|
3969
|
+
color: context?.style?.color,
|
|
3970
|
+
bold: context?.style?.bold,
|
|
3971
|
+
italics: context?.style?.italics,
|
|
3972
|
+
underline: context?.style?.underline
|
|
3973
|
+
});
|
|
3974
|
+
});
|
|
3975
|
+
PlaceholderRegistry.register("TOTAL_PAGES", (context) => {
|
|
3976
|
+
return new TextRun2({
|
|
3977
|
+
children: [PageNumber.TOTAL_PAGES],
|
|
3978
|
+
font: context?.style?.font,
|
|
3979
|
+
size: context?.style?.size,
|
|
3980
|
+
color: context?.style?.color,
|
|
3981
|
+
bold: context?.style?.bold,
|
|
3982
|
+
italics: context?.style?.italics,
|
|
3983
|
+
underline: context?.style?.underline
|
|
3984
|
+
});
|
|
3985
|
+
});
|
|
3986
|
+
PlaceholderRegistry.register("DATE", (context) => {
|
|
3987
|
+
const today = /* @__PURE__ */ new Date();
|
|
3988
|
+
const dateString = today.toLocaleDateString();
|
|
3989
|
+
return new TextRun2({
|
|
3990
|
+
text: dateString,
|
|
3991
|
+
font: context?.style?.font,
|
|
3992
|
+
size: context?.style?.size,
|
|
3993
|
+
color: context?.style?.color,
|
|
3994
|
+
bold: context?.style?.bold,
|
|
3995
|
+
italics: context?.style?.italics,
|
|
3996
|
+
underline: context?.style?.underline
|
|
3997
|
+
});
|
|
3998
|
+
});
|
|
3999
|
+
PlaceholderRegistry.register("DATETIME", (context) => {
|
|
4000
|
+
const now = /* @__PURE__ */ new Date();
|
|
4001
|
+
const dateTimeString = now.toLocaleString();
|
|
4002
|
+
return new TextRun2({
|
|
4003
|
+
text: dateTimeString,
|
|
4004
|
+
font: context?.style?.font,
|
|
4005
|
+
size: context?.style?.size,
|
|
4006
|
+
color: context?.style?.color,
|
|
4007
|
+
bold: context?.style?.bold,
|
|
4008
|
+
italics: context?.style?.italics,
|
|
4009
|
+
underline: context?.style?.underline
|
|
4010
|
+
});
|
|
4011
|
+
});
|
|
4012
|
+
PlaceholderRegistry.register("YEAR", (context) => {
|
|
4013
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
4014
|
+
return new TextRun2({
|
|
4015
|
+
text: year,
|
|
4016
|
+
font: context?.style?.font,
|
|
4017
|
+
size: context?.style?.size,
|
|
4018
|
+
color: context?.style?.color,
|
|
4019
|
+
bold: context?.style?.bold,
|
|
4020
|
+
italics: context?.style?.italics,
|
|
4021
|
+
underline: context?.style?.underline
|
|
4022
|
+
});
|
|
4023
|
+
});
|
|
4024
|
+
}
|
|
4025
|
+
initializeBuiltinPlaceholders();
|
|
4016
4026
|
|
|
4017
4027
|
// src/utils/revisionUtils.ts
|
|
4018
|
-
import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
|
|
4019
4028
|
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
4020
4029
|
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
4021
4030
|
var RevisionIdRegistry = class {
|
|
@@ -5067,10 +5076,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5067
5076
|
} else if (isImageComponent(cell)) {
|
|
5068
5077
|
const imageComp = cell;
|
|
5069
5078
|
try {
|
|
5070
|
-
const imageSource = imageComp.props
|
|
5079
|
+
const imageSource = resolveImageSource(imageComp.props);
|
|
5071
5080
|
if (!imageSource) {
|
|
5072
5081
|
throw new Error(
|
|
5073
|
-
'Image component requires
|
|
5082
|
+
'Image component requires one of "path", "base64", or "svg" property'
|
|
5074
5083
|
);
|
|
5075
5084
|
}
|
|
5076
5085
|
const imageResult = await getImageBuffer(imageSource);
|
|
@@ -5096,7 +5105,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5096
5105
|
});
|
|
5097
5106
|
cellChildren = [imageRun];
|
|
5098
5107
|
} catch (error) {
|
|
5099
|
-
const imageSource = imageComp.props.base64 || imageComp.props.path || "unknown";
|
|
5108
|
+
const imageSource = imageComp.props.svg?.trim() ? "inline-svg" : imageComp.props.base64 || imageComp.props.path || "unknown";
|
|
5100
5109
|
cellChildren = [
|
|
5101
5110
|
new TextRun4({
|
|
5102
5111
|
text: `[IMAGE: ${imageSource.substring(0, 50)}${imageSource.length > 50 ? "..." : ""}]`,
|
|
@@ -5773,10 +5782,10 @@ function renderListComponent(component, theme, themeName) {
|
|
|
5773
5782
|
async function renderImageComponent(component, theme, themeName) {
|
|
5774
5783
|
if (!isImageComponent(component)) return [];
|
|
5775
5784
|
const resolvedConfig = component.props;
|
|
5776
|
-
const imageSource = resolvedConfig
|
|
5785
|
+
const imageSource = resolveImageSource(resolvedConfig);
|
|
5777
5786
|
if (!imageSource) {
|
|
5778
5787
|
throw new Error(
|
|
5779
|
-
'Image component requires
|
|
5788
|
+
'Image component requires one of "path", "base64", or "svg" property'
|
|
5780
5789
|
);
|
|
5781
5790
|
}
|
|
5782
5791
|
return await createImage(imageSource, theme, themeName, {
|
|
@@ -6458,7 +6467,10 @@ async function generateChart(config, servicesConfig) {
|
|
|
6458
6467
|
infile: config.options,
|
|
6459
6468
|
type: "png",
|
|
6460
6469
|
b64: true,
|
|
6461
|
-
scale: config.scale
|
|
6470
|
+
scale: config.scale,
|
|
6471
|
+
// Forward resources verbatim only when present so the payload stays
|
|
6472
|
+
// byte-identical to before for callers that omit it.
|
|
6473
|
+
...config.resources ? { resources: config.resources } : {}
|
|
6462
6474
|
};
|
|
6463
6475
|
const response = await postJsonToService({
|
|
6464
6476
|
url: serverUrl,
|
|
@@ -6772,32 +6784,37 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
6772
6784
|
for (const component of activeComponents) {
|
|
6773
6785
|
if (isParagraphComponent(component)) {
|
|
6774
6786
|
const textComp = component;
|
|
6787
|
+
const font = textComp.props.font;
|
|
6775
6788
|
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
6789
|
elements.push(
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
alignment: textComp.props.alignment
|
|
6789
|
-
style
|
|
6790
|
+
createText(textComp.props.text, theme, themeName, {
|
|
6791
|
+
style: "Normal",
|
|
6792
|
+
alignment: textComp.props.alignment,
|
|
6793
|
+
// Resolve explicit run styling against the Normal style, preserving
|
|
6794
|
+
// prior header/footer rendering for these properties.
|
|
6795
|
+
fontFamily: font?.family || resolveFontFamily(theme, normalStyle.font) || getThemeFonts(theme).body.family,
|
|
6796
|
+
fontSize: font?.size ?? normalStyle.size ?? 11,
|
|
6797
|
+
// Pass the raw color/token; createText resolves it. Fall back to the
|
|
6798
|
+
// Normal style color, then the theme's primary text color.
|
|
6799
|
+
fontColor: font?.color || normalStyle.color || "textPrimary",
|
|
6800
|
+
bold: font?.bold ?? false,
|
|
6801
|
+
italic: font?.italic ?? false,
|
|
6802
|
+
underline: font?.underline,
|
|
6803
|
+
fontWeight: font?.fontWeight,
|
|
6804
|
+
boldColor: textComp.props.boldColor,
|
|
6805
|
+
spacing: textComp.props.spacing,
|
|
6806
|
+
lineSpacing: font?.lineSpacing
|
|
6790
6807
|
})
|
|
6791
6808
|
);
|
|
6792
6809
|
} else if (isImageComponent(component)) {
|
|
6793
6810
|
const imageComp = component;
|
|
6794
|
-
let imageSource = imageComp.props
|
|
6811
|
+
let imageSource = resolveImageSource(imageComp.props);
|
|
6795
6812
|
if (!imageSource) {
|
|
6796
6813
|
elements.push(
|
|
6797
6814
|
new Paragraph7({
|
|
6798
6815
|
children: [
|
|
6799
6816
|
new TextRun6({
|
|
6800
|
-
text: "[IMAGE: Missing path or
|
|
6817
|
+
text: "[IMAGE: Missing path, base64, or svg property]",
|
|
6801
6818
|
font: getThemeFonts(theme).body.family,
|
|
6802
6819
|
size: 20,
|
|
6803
6820
|
bold: true,
|
|
@@ -6871,15 +6888,16 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
6871
6888
|
})
|
|
6872
6889
|
);
|
|
6873
6890
|
} catch (error) {
|
|
6891
|
+
const sourcePreview = imageSource.substring(0, 50);
|
|
6874
6892
|
console.error(
|
|
6875
|
-
`[Header/Footer Image Error] Failed to render image: ${
|
|
6893
|
+
`[Header/Footer Image Error] Failed to render image: ${sourcePreview}...`,
|
|
6876
6894
|
error instanceof Error ? error.message : error
|
|
6877
6895
|
);
|
|
6878
6896
|
elements.push(
|
|
6879
6897
|
new Paragraph7({
|
|
6880
6898
|
children: [
|
|
6881
6899
|
new TextRun6({
|
|
6882
|
-
text: `[IMAGE: ${
|
|
6900
|
+
text: `[IMAGE: ${sourcePreview}]`,
|
|
6883
6901
|
font: getThemeFonts(theme).body.family,
|
|
6884
6902
|
size: 20,
|
|
6885
6903
|
color: getThemeColors(theme).secondary,
|