@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
package/dist/index.js
CHANGED
|
@@ -2768,6 +2768,16 @@ async function downloadImageFromUrl(url) {
|
|
|
2768
2768
|
throw new Error(`Failed to download image from ${url}: Unknown error`);
|
|
2769
2769
|
}
|
|
2770
2770
|
}
|
|
2771
|
+
function resolveImageSource(props) {
|
|
2772
|
+
const hasValue = (v) => typeof v === "string" && v.trim().length > 0;
|
|
2773
|
+
if (hasValue(props.svg)) {
|
|
2774
|
+
const encoded = Buffer.from(props.svg, "utf-8").toString("base64");
|
|
2775
|
+
return `data:image/svg+xml;base64,${encoded}`;
|
|
2776
|
+
}
|
|
2777
|
+
if (hasValue(props.base64)) return props.base64;
|
|
2778
|
+
if (hasValue(props.path)) return props.path;
|
|
2779
|
+
return void 0;
|
|
2780
|
+
}
|
|
2771
2781
|
async function getImageBuffer(imagePath) {
|
|
2772
2782
|
if (isBase64Image(imagePath)) {
|
|
2773
2783
|
return { buffer: decodeBase64Image(imagePath) };
|
|
@@ -3469,216 +3479,116 @@ function getStyleIdForLevel(level) {
|
|
|
3469
3479
|
return styleMap[level] || "Heading1";
|
|
3470
3480
|
}
|
|
3471
3481
|
|
|
3472
|
-
// src/
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
// src/utils/placeholderProcessor.ts
|
|
3476
|
-
import {
|
|
3477
|
-
TextRun,
|
|
3478
|
-
PageNumber
|
|
3479
|
-
} from "docx";
|
|
3482
|
+
// src/core/render.ts
|
|
3483
|
+
init_styleHelpers();
|
|
3484
|
+
init_layoutUtils();
|
|
3480
3485
|
|
|
3481
|
-
// src/
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3486
|
+
// src/cache/index.ts
|
|
3487
|
+
var cache_exports = {};
|
|
3488
|
+
__export(cache_exports, {
|
|
3489
|
+
CacheKeyGenerator: () => CacheKeyGenerator
|
|
3490
|
+
});
|
|
3491
|
+
__reExport(cache_exports, cache_star);
|
|
3492
|
+
import * as cache_star from "@json-to-office/shared/cache";
|
|
3485
3493
|
|
|
3486
|
-
// src/
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
static register(name, handler) {
|
|
3493
|
-
this.handlers.set(name.toUpperCase(), handler);
|
|
3494
|
+
// src/cache/key-generator.ts
|
|
3495
|
+
import { createHash } from "crypto";
|
|
3496
|
+
var CacheKeyGenerator = class {
|
|
3497
|
+
version;
|
|
3498
|
+
constructor(version = "1.0") {
|
|
3499
|
+
this.version = version;
|
|
3494
3500
|
}
|
|
3495
3501
|
/**
|
|
3496
|
-
*
|
|
3502
|
+
* Generate cache key for a component
|
|
3497
3503
|
*/
|
|
3498
|
-
|
|
3499
|
-
|
|
3504
|
+
generateKey(component, context, options = {}) {
|
|
3505
|
+
const parts = [
|
|
3506
|
+
this.version,
|
|
3507
|
+
component.name,
|
|
3508
|
+
this.hashProps(component.props)
|
|
3509
|
+
];
|
|
3510
|
+
if (options.includeTheme !== false) {
|
|
3511
|
+
parts.push(context.theme.name);
|
|
3512
|
+
}
|
|
3513
|
+
if (options.includeContext) {
|
|
3514
|
+
parts.push(this.hashContext(context));
|
|
3515
|
+
}
|
|
3516
|
+
if (options.additionalKeys) {
|
|
3517
|
+
parts.push(...options.additionalKeys);
|
|
3518
|
+
}
|
|
3519
|
+
if (options.version) {
|
|
3520
|
+
parts.push(options.version);
|
|
3521
|
+
}
|
|
3522
|
+
return parts.join(":");
|
|
3500
3523
|
}
|
|
3501
3524
|
/**
|
|
3502
|
-
*
|
|
3525
|
+
* Hash component props
|
|
3503
3526
|
*/
|
|
3504
|
-
|
|
3505
|
-
|
|
3527
|
+
hashProps(props) {
|
|
3528
|
+
if (!props) return "null";
|
|
3529
|
+
const normalized = this.normalizeObject(props);
|
|
3530
|
+
const json = JSON.stringify(normalized);
|
|
3531
|
+
return this.hash(json);
|
|
3506
3532
|
}
|
|
3507
3533
|
/**
|
|
3508
|
-
*
|
|
3534
|
+
* Hash render context
|
|
3509
3535
|
*/
|
|
3510
|
-
|
|
3511
|
-
|
|
3536
|
+
hashContext(context) {
|
|
3537
|
+
const relevant = {
|
|
3538
|
+
theme: context.theme.name,
|
|
3539
|
+
document: context.document
|
|
3540
|
+
// Exclude runtime properties like sectionIndex, componentIndex
|
|
3541
|
+
};
|
|
3542
|
+
return this.hash(JSON.stringify(relevant));
|
|
3512
3543
|
}
|
|
3513
3544
|
/**
|
|
3514
|
-
*
|
|
3545
|
+
* Normalize object for consistent hashing
|
|
3515
3546
|
*/
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
function processTextWithPlaceholders(text, baseStyle = {}, context = {}) {
|
|
3521
|
-
const normalizedText = normalizeUnicodeText(text);
|
|
3522
|
-
const combinedRegex = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
|
|
3523
|
-
const result = [];
|
|
3524
|
-
let lastIndex = 0;
|
|
3525
|
-
let match;
|
|
3526
|
-
while ((match = combinedRegex.exec(normalizedText)) !== null) {
|
|
3527
|
-
if (match.index > lastIndex) {
|
|
3528
|
-
const beforeText = normalizedText.substring(lastIndex, match.index);
|
|
3529
|
-
if (beforeText) {
|
|
3530
|
-
result.push(...createTextRunsWithNewlines(beforeText, baseStyle));
|
|
3531
|
-
}
|
|
3547
|
+
normalizeObject(obj) {
|
|
3548
|
+
if (obj === null || obj === void 0) return obj;
|
|
3549
|
+
if (Array.isArray(obj)) {
|
|
3550
|
+
return obj.map((item) => this.normalizeObject(item));
|
|
3532
3551
|
}
|
|
3533
|
-
if (
|
|
3534
|
-
|
|
3535
|
-
const handler = PlaceholderRegistry.get(placeholderName);
|
|
3536
|
-
if (handler) {
|
|
3537
|
-
const placeholderResult = handler({ ...context, style: baseStyle });
|
|
3538
|
-
if (Array.isArray(placeholderResult)) {
|
|
3539
|
-
result.push(...placeholderResult);
|
|
3540
|
-
} else if (placeholderResult instanceof TextRun) {
|
|
3541
|
-
result.push(placeholderResult);
|
|
3542
|
-
} else if (typeof placeholderResult === "string") {
|
|
3543
|
-
result.push(
|
|
3544
|
-
...createTextRunsWithNewlines(placeholderResult, baseStyle)
|
|
3545
|
-
);
|
|
3546
|
-
}
|
|
3547
|
-
} else {
|
|
3548
|
-
result.push(...createTextRunsWithNewlines(match[0], baseStyle));
|
|
3549
|
-
}
|
|
3550
|
-
} else {
|
|
3551
|
-
let decoratedText;
|
|
3552
|
-
let bold = baseStyle.bold || false;
|
|
3553
|
-
let italics = baseStyle.italics || false;
|
|
3554
|
-
if (match[1] === "***" || match[1] === "___") {
|
|
3555
|
-
decoratedText = match[2];
|
|
3556
|
-
bold = true;
|
|
3557
|
-
italics = true;
|
|
3558
|
-
} else if (match[3] === "**" || match[3] === "__") {
|
|
3559
|
-
decoratedText = match[4];
|
|
3560
|
-
bold = true;
|
|
3561
|
-
} else if (match[5] === "*" || match[5] === "_") {
|
|
3562
|
-
decoratedText = match[6];
|
|
3563
|
-
italics = true;
|
|
3564
|
-
} else {
|
|
3565
|
-
decoratedText = match[0];
|
|
3566
|
-
}
|
|
3567
|
-
const decoratedTextRuns = processTextWithPlaceholders(
|
|
3568
|
-
decoratedText,
|
|
3569
|
-
{
|
|
3570
|
-
...baseStyle,
|
|
3571
|
-
bold,
|
|
3572
|
-
italics
|
|
3573
|
-
},
|
|
3574
|
-
context
|
|
3575
|
-
);
|
|
3576
|
-
result.push(...decoratedTextRuns);
|
|
3552
|
+
if (obj instanceof Date) {
|
|
3553
|
+
return obj.toISOString();
|
|
3577
3554
|
}
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3555
|
+
if (typeof obj === "object") {
|
|
3556
|
+
const sorted = {};
|
|
3557
|
+
const keys = Object.keys(obj).sort();
|
|
3558
|
+
for (const key of keys) {
|
|
3559
|
+
sorted[key] = this.normalizeObject(obj[key]);
|
|
3560
|
+
}
|
|
3561
|
+
return sorted;
|
|
3584
3562
|
}
|
|
3563
|
+
return obj;
|
|
3585
3564
|
}
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
function createTextRunsWithNewlines(text, baseStyle) {
|
|
3592
|
-
const runs = [];
|
|
3593
|
-
const lines = text.split("\n");
|
|
3594
|
-
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
3595
|
-
const line = lines[lineIndex];
|
|
3596
|
-
const needsLineBreak = lineIndex > 0;
|
|
3597
|
-
if (line || needsLineBreak) {
|
|
3598
|
-
runs.push(
|
|
3599
|
-
new TextRun({
|
|
3600
|
-
text: line,
|
|
3601
|
-
font: baseStyle.font,
|
|
3602
|
-
size: baseStyle.size,
|
|
3603
|
-
color: baseStyle.color,
|
|
3604
|
-
bold: baseStyle.bold,
|
|
3605
|
-
italics: baseStyle.italics,
|
|
3606
|
-
underline: baseStyle.underline,
|
|
3607
|
-
break: needsLineBreak ? 1 : void 0
|
|
3608
|
-
})
|
|
3609
|
-
);
|
|
3610
|
-
}
|
|
3565
|
+
/**
|
|
3566
|
+
* Create hash
|
|
3567
|
+
*/
|
|
3568
|
+
hash(input) {
|
|
3569
|
+
return createHash("sha256").update(input).digest("hex").substring(0, 16);
|
|
3611
3570
|
}
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
color: context?.style?.color,
|
|
3621
|
-
bold: context?.style?.bold,
|
|
3622
|
-
italics: context?.style?.italics,
|
|
3623
|
-
underline: context?.style?.underline
|
|
3624
|
-
});
|
|
3625
|
-
});
|
|
3626
|
-
PlaceholderRegistry.register("TOTAL_PAGES", (context) => {
|
|
3627
|
-
return new TextRun({
|
|
3628
|
-
children: [PageNumber.TOTAL_PAGES],
|
|
3629
|
-
font: context?.style?.font,
|
|
3630
|
-
size: context?.style?.size,
|
|
3631
|
-
color: context?.style?.color,
|
|
3632
|
-
bold: context?.style?.bold,
|
|
3633
|
-
italics: context?.style?.italics,
|
|
3634
|
-
underline: context?.style?.underline
|
|
3635
|
-
});
|
|
3636
|
-
});
|
|
3637
|
-
PlaceholderRegistry.register("DATE", (context) => {
|
|
3638
|
-
const today = /* @__PURE__ */ new Date();
|
|
3639
|
-
const dateString = today.toLocaleDateString();
|
|
3640
|
-
return new TextRun({
|
|
3641
|
-
text: dateString,
|
|
3642
|
-
font: context?.style?.font,
|
|
3643
|
-
size: context?.style?.size,
|
|
3644
|
-
color: context?.style?.color,
|
|
3645
|
-
bold: context?.style?.bold,
|
|
3646
|
-
italics: context?.style?.italics,
|
|
3647
|
-
underline: context?.style?.underline
|
|
3648
|
-
});
|
|
3649
|
-
});
|
|
3650
|
-
PlaceholderRegistry.register("DATETIME", (context) => {
|
|
3651
|
-
const now = /* @__PURE__ */ new Date();
|
|
3652
|
-
const dateTimeString = now.toLocaleString();
|
|
3653
|
-
return new TextRun({
|
|
3654
|
-
text: dateTimeString,
|
|
3655
|
-
font: context?.style?.font,
|
|
3656
|
-
size: context?.style?.size,
|
|
3657
|
-
color: context?.style?.color,
|
|
3658
|
-
bold: context?.style?.bold,
|
|
3659
|
-
italics: context?.style?.italics,
|
|
3660
|
-
underline: context?.style?.underline
|
|
3661
|
-
});
|
|
3662
|
-
});
|
|
3663
|
-
PlaceholderRegistry.register("YEAR", (context) => {
|
|
3664
|
-
const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
3665
|
-
return new TextRun({
|
|
3666
|
-
text: year,
|
|
3667
|
-
font: context?.style?.font,
|
|
3668
|
-
size: context?.style?.size,
|
|
3669
|
-
color: context?.style?.color,
|
|
3670
|
-
bold: context?.style?.bold,
|
|
3671
|
-
italics: context?.style?.italics,
|
|
3672
|
-
underline: context?.style?.underline
|
|
3673
|
-
});
|
|
3674
|
-
});
|
|
3571
|
+
};
|
|
3572
|
+
|
|
3573
|
+
// src/utils/revisionUtils.ts
|
|
3574
|
+
import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
|
|
3575
|
+
|
|
3576
|
+
// src/utils/unicode.ts
|
|
3577
|
+
function normalizeUnicodeText(text) {
|
|
3578
|
+
return (text ?? "").normalize("NFC");
|
|
3675
3579
|
}
|
|
3676
|
-
|
|
3580
|
+
|
|
3581
|
+
// src/utils/placeholderProcessor.ts
|
|
3582
|
+
import {
|
|
3583
|
+
TextRun as TextRun2,
|
|
3584
|
+
PageNumber
|
|
3585
|
+
} from "docx";
|
|
3677
3586
|
|
|
3678
3587
|
// src/utils/textParser.ts
|
|
3588
|
+
import { TextRun, ExternalHyperlink, InternalHyperlink } from "docx";
|
|
3679
3589
|
function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
3680
3590
|
if (!text) {
|
|
3681
|
-
return [new
|
|
3591
|
+
return [new TextRun({ text: "", ...baseStyle })];
|
|
3682
3592
|
}
|
|
3683
3593
|
const normalizedText = normalizeUnicodeText(text);
|
|
3684
3594
|
const hasPlaceholders = /\{[^}]+\}/.test(normalizedText);
|
|
@@ -3700,7 +3610,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3700
3610
|
if (match.index > lastIndex) {
|
|
3701
3611
|
const plainText = normalizedText.substring(lastIndex, match.index);
|
|
3702
3612
|
if (plainText) {
|
|
3703
|
-
runs.push(...
|
|
3613
|
+
runs.push(...createTextRunsWithNewlines(plainText, baseStyle, options));
|
|
3704
3614
|
}
|
|
3705
3615
|
}
|
|
3706
3616
|
let decoratedText;
|
|
@@ -3719,7 +3629,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3719
3629
|
} else {
|
|
3720
3630
|
decoratedText = match[0];
|
|
3721
3631
|
}
|
|
3722
|
-
const decoratedRuns =
|
|
3632
|
+
const decoratedRuns = createTextRunsWithNewlines(
|
|
3723
3633
|
decoratedText,
|
|
3724
3634
|
baseStyle,
|
|
3725
3635
|
options,
|
|
@@ -3735,18 +3645,18 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
|
|
|
3735
3645
|
const remainingText = normalizedText.substring(lastIndex);
|
|
3736
3646
|
if (remainingText) {
|
|
3737
3647
|
runs.push(
|
|
3738
|
-
...
|
|
3648
|
+
...createTextRunsWithNewlines(remainingText, baseStyle, options)
|
|
3739
3649
|
);
|
|
3740
3650
|
}
|
|
3741
3651
|
}
|
|
3742
3652
|
if (runs.length === 0 && normalizedText) {
|
|
3743
3653
|
runs.push(
|
|
3744
|
-
...
|
|
3654
|
+
...createTextRunsWithNewlines(normalizedText, baseStyle, options)
|
|
3745
3655
|
);
|
|
3746
3656
|
}
|
|
3747
3657
|
return runs;
|
|
3748
3658
|
}
|
|
3749
|
-
function
|
|
3659
|
+
function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
|
|
3750
3660
|
const runs = [];
|
|
3751
3661
|
const lines = text.split("\n");
|
|
3752
3662
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
@@ -3758,7 +3668,7 @@ function createTextRunsWithNewlines2(text, baseStyle, options, overrideStyle) {
|
|
|
3758
3668
|
italics: overrideStyle?.italics ?? baseStyle.italics
|
|
3759
3669
|
};
|
|
3760
3670
|
runs.push(
|
|
3761
|
-
new
|
|
3671
|
+
new TextRun({
|
|
3762
3672
|
text: line,
|
|
3763
3673
|
...baseStyle.font && { font: baseStyle.font },
|
|
3764
3674
|
...baseStyle.size && { size: baseStyle.size },
|
|
@@ -3804,7 +3714,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3804
3714
|
if (isInternal) {
|
|
3805
3715
|
const bookmarkId = linkUrl.substring(1);
|
|
3806
3716
|
runs.push(
|
|
3807
|
-
new
|
|
3717
|
+
new InternalHyperlink({
|
|
3808
3718
|
children: linkTextRuns,
|
|
3809
3719
|
// Cast needed for docx types
|
|
3810
3720
|
anchor: bookmarkId
|
|
@@ -3812,7 +3722,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3812
3722
|
);
|
|
3813
3723
|
} else {
|
|
3814
3724
|
runs.push(
|
|
3815
|
-
new
|
|
3725
|
+
new ExternalHyperlink({
|
|
3816
3726
|
children: linkTextRuns,
|
|
3817
3727
|
// Cast needed for docx types
|
|
3818
3728
|
link: linkUrl
|
|
@@ -3841,100 +3751,199 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3841
3751
|
return runs;
|
|
3842
3752
|
}
|
|
3843
3753
|
|
|
3844
|
-
// src/
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
CacheKeyGenerator: () => CacheKeyGenerator
|
|
3853
|
-
});
|
|
3854
|
-
__reExport(cache_exports, cache_star);
|
|
3855
|
-
import * as cache_star from "@json-to-office/shared/cache";
|
|
3856
|
-
|
|
3857
|
-
// src/cache/key-generator.ts
|
|
3858
|
-
import { createHash } from "crypto";
|
|
3859
|
-
var CacheKeyGenerator = class {
|
|
3860
|
-
version;
|
|
3861
|
-
constructor(version = "1.0") {
|
|
3862
|
-
this.version = version;
|
|
3754
|
+
// src/utils/placeholderProcessor.ts
|
|
3755
|
+
var PlaceholderRegistry = class {
|
|
3756
|
+
static handlers = /* @__PURE__ */ new Map();
|
|
3757
|
+
/**
|
|
3758
|
+
* Register a placeholder handler
|
|
3759
|
+
*/
|
|
3760
|
+
static register(name, handler) {
|
|
3761
|
+
this.handlers.set(name.toUpperCase(), handler);
|
|
3863
3762
|
}
|
|
3864
3763
|
/**
|
|
3865
|
-
*
|
|
3764
|
+
* Get a placeholder handler
|
|
3866
3765
|
*/
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
this.version,
|
|
3870
|
-
component.name,
|
|
3871
|
-
this.hashProps(component.props)
|
|
3872
|
-
];
|
|
3873
|
-
if (options.includeTheme !== false) {
|
|
3874
|
-
parts.push(context.theme.name);
|
|
3875
|
-
}
|
|
3876
|
-
if (options.includeContext) {
|
|
3877
|
-
parts.push(this.hashContext(context));
|
|
3878
|
-
}
|
|
3879
|
-
if (options.additionalKeys) {
|
|
3880
|
-
parts.push(...options.additionalKeys);
|
|
3881
|
-
}
|
|
3882
|
-
if (options.version) {
|
|
3883
|
-
parts.push(options.version);
|
|
3884
|
-
}
|
|
3885
|
-
return parts.join(":");
|
|
3766
|
+
static get(name) {
|
|
3767
|
+
return this.handlers.get(name.toUpperCase());
|
|
3886
3768
|
}
|
|
3887
3769
|
/**
|
|
3888
|
-
*
|
|
3770
|
+
* Check if a placeholder is registered
|
|
3889
3771
|
*/
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
const normalized = this.normalizeObject(props);
|
|
3893
|
-
const json = JSON.stringify(normalized);
|
|
3894
|
-
return this.hash(json);
|
|
3772
|
+
static has(name) {
|
|
3773
|
+
return this.handlers.has(name.toUpperCase());
|
|
3895
3774
|
}
|
|
3896
3775
|
/**
|
|
3897
|
-
*
|
|
3776
|
+
* Get all registered placeholder names
|
|
3898
3777
|
*/
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
theme: context.theme.name,
|
|
3902
|
-
document: context.document
|
|
3903
|
-
// Exclude runtime properties like sectionIndex, componentIndex
|
|
3904
|
-
};
|
|
3905
|
-
return this.hash(JSON.stringify(relevant));
|
|
3778
|
+
static getRegisteredNames() {
|
|
3779
|
+
return Array.from(this.handlers.keys());
|
|
3906
3780
|
}
|
|
3907
3781
|
/**
|
|
3908
|
-
*
|
|
3782
|
+
* Clear all registered placeholders
|
|
3909
3783
|
*/
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3784
|
+
static clear() {
|
|
3785
|
+
this.handlers.clear();
|
|
3786
|
+
}
|
|
3787
|
+
};
|
|
3788
|
+
function processTextWithPlaceholders(text, baseStyle = {}, context = {}) {
|
|
3789
|
+
const normalizedText = normalizeUnicodeText(text);
|
|
3790
|
+
const combinedRegex = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
|
|
3791
|
+
const result = [];
|
|
3792
|
+
let lastIndex = 0;
|
|
3793
|
+
let match;
|
|
3794
|
+
while ((match = combinedRegex.exec(normalizedText)) !== null) {
|
|
3795
|
+
if (match.index > lastIndex) {
|
|
3796
|
+
const beforeText = normalizedText.substring(lastIndex, match.index);
|
|
3797
|
+
if (beforeText) {
|
|
3798
|
+
result.push(...createTextRunsWithNewlines2(beforeText, baseStyle));
|
|
3799
|
+
}
|
|
3917
3800
|
}
|
|
3918
|
-
if (
|
|
3919
|
-
const
|
|
3920
|
-
const
|
|
3921
|
-
|
|
3922
|
-
|
|
3801
|
+
if (match[7]) {
|
|
3802
|
+
const placeholderName = match[7];
|
|
3803
|
+
const handler = PlaceholderRegistry.get(placeholderName);
|
|
3804
|
+
if (handler) {
|
|
3805
|
+
const placeholderResult = handler({ ...context, style: baseStyle });
|
|
3806
|
+
if (Array.isArray(placeholderResult)) {
|
|
3807
|
+
result.push(...placeholderResult);
|
|
3808
|
+
} else if (placeholderResult instanceof TextRun2) {
|
|
3809
|
+
result.push(placeholderResult);
|
|
3810
|
+
} else if (typeof placeholderResult === "string") {
|
|
3811
|
+
result.push(
|
|
3812
|
+
...createTextRunsWithNewlines2(placeholderResult, baseStyle)
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3815
|
+
} else {
|
|
3816
|
+
result.push(...createTextRunsWithNewlines2(match[0], baseStyle));
|
|
3923
3817
|
}
|
|
3924
|
-
|
|
3818
|
+
} else {
|
|
3819
|
+
let decoratedText;
|
|
3820
|
+
let bold = baseStyle.bold || false;
|
|
3821
|
+
let italics = baseStyle.italics || false;
|
|
3822
|
+
if (match[1] === "***" || match[1] === "___") {
|
|
3823
|
+
decoratedText = match[2];
|
|
3824
|
+
bold = true;
|
|
3825
|
+
italics = true;
|
|
3826
|
+
} else if (match[3] === "**" || match[3] === "__") {
|
|
3827
|
+
decoratedText = match[4];
|
|
3828
|
+
bold = true;
|
|
3829
|
+
} else if (match[5] === "*" || match[5] === "_") {
|
|
3830
|
+
decoratedText = match[6];
|
|
3831
|
+
italics = true;
|
|
3832
|
+
} else {
|
|
3833
|
+
decoratedText = match[0];
|
|
3834
|
+
}
|
|
3835
|
+
const decoratedTextRuns = processTextWithPlaceholders(
|
|
3836
|
+
decoratedText,
|
|
3837
|
+
{
|
|
3838
|
+
...baseStyle,
|
|
3839
|
+
bold,
|
|
3840
|
+
italics
|
|
3841
|
+
},
|
|
3842
|
+
context
|
|
3843
|
+
);
|
|
3844
|
+
result.push(...decoratedTextRuns);
|
|
3925
3845
|
}
|
|
3926
|
-
|
|
3846
|
+
lastIndex = match.index + match[0].length;
|
|
3927
3847
|
}
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3848
|
+
if (lastIndex < normalizedText.length) {
|
|
3849
|
+
const remainingText = normalizedText.substring(lastIndex);
|
|
3850
|
+
if (remainingText) {
|
|
3851
|
+
result.push(...createTextRunsWithNewlines2(remainingText, baseStyle));
|
|
3852
|
+
}
|
|
3933
3853
|
}
|
|
3934
|
-
|
|
3854
|
+
if (result.length === 0 && normalizedText) {
|
|
3855
|
+
result.push(...createTextRunsWithNewlines2(normalizedText, baseStyle));
|
|
3856
|
+
}
|
|
3857
|
+
return result;
|
|
3858
|
+
}
|
|
3859
|
+
function createTextRunsWithNewlines2(text, baseStyle) {
|
|
3860
|
+
const runs = [];
|
|
3861
|
+
const lines = text.split("\n");
|
|
3862
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
3863
|
+
const line = lines[lineIndex];
|
|
3864
|
+
const needsLineBreak = lineIndex > 0;
|
|
3865
|
+
if (line || needsLineBreak) {
|
|
3866
|
+
runs.push(
|
|
3867
|
+
new TextRun2({
|
|
3868
|
+
text: line,
|
|
3869
|
+
font: baseStyle.font,
|
|
3870
|
+
size: baseStyle.size,
|
|
3871
|
+
color: baseStyle.color,
|
|
3872
|
+
bold: baseStyle.bold,
|
|
3873
|
+
italics: baseStyle.italics,
|
|
3874
|
+
underline: baseStyle.underline,
|
|
3875
|
+
break: needsLineBreak ? 1 : void 0
|
|
3876
|
+
})
|
|
3877
|
+
);
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
return runs;
|
|
3881
|
+
}
|
|
3882
|
+
function initializeBuiltinPlaceholders() {
|
|
3883
|
+
PlaceholderRegistry.register("PAGE", (context) => {
|
|
3884
|
+
return new TextRun2({
|
|
3885
|
+
children: [PageNumber.CURRENT],
|
|
3886
|
+
font: context?.style?.font,
|
|
3887
|
+
size: context?.style?.size,
|
|
3888
|
+
color: context?.style?.color,
|
|
3889
|
+
bold: context?.style?.bold,
|
|
3890
|
+
italics: context?.style?.italics,
|
|
3891
|
+
underline: context?.style?.underline
|
|
3892
|
+
});
|
|
3893
|
+
});
|
|
3894
|
+
PlaceholderRegistry.register("TOTAL_PAGES", (context) => {
|
|
3895
|
+
return new TextRun2({
|
|
3896
|
+
children: [PageNumber.TOTAL_PAGES],
|
|
3897
|
+
font: context?.style?.font,
|
|
3898
|
+
size: context?.style?.size,
|
|
3899
|
+
color: context?.style?.color,
|
|
3900
|
+
bold: context?.style?.bold,
|
|
3901
|
+
italics: context?.style?.italics,
|
|
3902
|
+
underline: context?.style?.underline
|
|
3903
|
+
});
|
|
3904
|
+
});
|
|
3905
|
+
PlaceholderRegistry.register("DATE", (context) => {
|
|
3906
|
+
const today = /* @__PURE__ */ new Date();
|
|
3907
|
+
const dateString = today.toLocaleDateString();
|
|
3908
|
+
return new TextRun2({
|
|
3909
|
+
text: dateString,
|
|
3910
|
+
font: context?.style?.font,
|
|
3911
|
+
size: context?.style?.size,
|
|
3912
|
+
color: context?.style?.color,
|
|
3913
|
+
bold: context?.style?.bold,
|
|
3914
|
+
italics: context?.style?.italics,
|
|
3915
|
+
underline: context?.style?.underline
|
|
3916
|
+
});
|
|
3917
|
+
});
|
|
3918
|
+
PlaceholderRegistry.register("DATETIME", (context) => {
|
|
3919
|
+
const now = /* @__PURE__ */ new Date();
|
|
3920
|
+
const dateTimeString = now.toLocaleString();
|
|
3921
|
+
return new TextRun2({
|
|
3922
|
+
text: dateTimeString,
|
|
3923
|
+
font: context?.style?.font,
|
|
3924
|
+
size: context?.style?.size,
|
|
3925
|
+
color: context?.style?.color,
|
|
3926
|
+
bold: context?.style?.bold,
|
|
3927
|
+
italics: context?.style?.italics,
|
|
3928
|
+
underline: context?.style?.underline
|
|
3929
|
+
});
|
|
3930
|
+
});
|
|
3931
|
+
PlaceholderRegistry.register("YEAR", (context) => {
|
|
3932
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
3933
|
+
return new TextRun2({
|
|
3934
|
+
text: year,
|
|
3935
|
+
font: context?.style?.font,
|
|
3936
|
+
size: context?.style?.size,
|
|
3937
|
+
color: context?.style?.color,
|
|
3938
|
+
bold: context?.style?.bold,
|
|
3939
|
+
italics: context?.style?.italics,
|
|
3940
|
+
underline: context?.style?.underline
|
|
3941
|
+
});
|
|
3942
|
+
});
|
|
3943
|
+
}
|
|
3944
|
+
initializeBuiltinPlaceholders();
|
|
3935
3945
|
|
|
3936
3946
|
// src/utils/revisionUtils.ts
|
|
3937
|
-
import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
|
|
3938
3947
|
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
3939
3948
|
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
3940
3949
|
var RevisionIdRegistry = class {
|
|
@@ -5017,10 +5026,10 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5017
5026
|
} else if (isImageComponent(cell)) {
|
|
5018
5027
|
const imageComp = cell;
|
|
5019
5028
|
try {
|
|
5020
|
-
const imageSource = imageComp.props
|
|
5029
|
+
const imageSource = resolveImageSource(imageComp.props);
|
|
5021
5030
|
if (!imageSource) {
|
|
5022
5031
|
throw new Error(
|
|
5023
|
-
'Image component requires
|
|
5032
|
+
'Image component requires one of "path", "base64", or "svg" property'
|
|
5024
5033
|
);
|
|
5025
5034
|
}
|
|
5026
5035
|
const imageResult = await getImageBuffer(imageSource);
|
|
@@ -5046,7 +5055,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5046
5055
|
});
|
|
5047
5056
|
cellChildren = [imageRun];
|
|
5048
5057
|
} catch (error) {
|
|
5049
|
-
const imageSource = imageComp.props.base64 || imageComp.props.path || "unknown";
|
|
5058
|
+
const imageSource = imageComp.props.svg?.trim() ? "inline-svg" : imageComp.props.base64 || imageComp.props.path || "unknown";
|
|
5050
5059
|
cellChildren = [
|
|
5051
5060
|
new TextRun4({
|
|
5052
5061
|
text: `[IMAGE: ${imageSource.substring(0, 50)}${imageSource.length > 50 ? "..." : ""}]`,
|
|
@@ -5723,10 +5732,10 @@ function renderListComponent(component, theme, themeName) {
|
|
|
5723
5732
|
async function renderImageComponent(component, theme, themeName) {
|
|
5724
5733
|
if (!isImageComponent(component)) return [];
|
|
5725
5734
|
const resolvedConfig = component.props;
|
|
5726
|
-
const imageSource = resolvedConfig
|
|
5735
|
+
const imageSource = resolveImageSource(resolvedConfig);
|
|
5727
5736
|
if (!imageSource) {
|
|
5728
5737
|
throw new Error(
|
|
5729
|
-
'Image component requires
|
|
5738
|
+
'Image component requires one of "path", "base64", or "svg" property'
|
|
5730
5739
|
);
|
|
5731
5740
|
}
|
|
5732
5741
|
return await createImage(imageSource, theme, themeName, {
|
|
@@ -6415,7 +6424,10 @@ async function generateChart(config, servicesConfig) {
|
|
|
6415
6424
|
infile: config.options,
|
|
6416
6425
|
type: "png",
|
|
6417
6426
|
b64: true,
|
|
6418
|
-
scale: config.scale
|
|
6427
|
+
scale: config.scale,
|
|
6428
|
+
// Forward resources verbatim only when present so the payload stays
|
|
6429
|
+
// byte-identical to before for callers that omit it.
|
|
6430
|
+
...config.resources ? { resources: config.resources } : {}
|
|
6419
6431
|
};
|
|
6420
6432
|
const response = await postJsonToService({
|
|
6421
6433
|
url: serverUrl,
|
|
@@ -6736,32 +6748,37 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
6736
6748
|
for (const component of activeComponents) {
|
|
6737
6749
|
if (isParagraphComponent(component)) {
|
|
6738
6750
|
const textComp = component;
|
|
6751
|
+
const font = textComp.props.font;
|
|
6739
6752
|
const normalStyle = getNormalStyle(theme);
|
|
6740
|
-
const textStyle = {
|
|
6741
|
-
font: textComp.props.font?.family || resolveFontFamily(theme, normalStyle.font) || getThemeFonts(theme).body.family,
|
|
6742
|
-
size: (textComp.props.font?.size ?? normalStyle.size ?? 11) * 2,
|
|
6743
|
-
// Convert to half-points
|
|
6744
|
-
bold: textComp.props.font?.bold ?? false,
|
|
6745
|
-
italics: textComp.props.font?.italic ?? false,
|
|
6746
|
-
color: textComp.props.font?.color && resolveColor(textComp.props.font.color, theme) || normalStyle.color && resolveColor(normalStyle.color, theme) || getThemeColors(theme).textPrimary
|
|
6747
|
-
};
|
|
6748
|
-
const textRuns = parseTextWithDecorators(textComp.props.text, textStyle);
|
|
6749
6753
|
elements.push(
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
alignment: textComp.props.alignment
|
|
6753
|
-
style
|
|
6754
|
+
createText(textComp.props.text, theme, themeName, {
|
|
6755
|
+
style: "Normal",
|
|
6756
|
+
alignment: textComp.props.alignment,
|
|
6757
|
+
// Resolve explicit run styling against the Normal style, preserving
|
|
6758
|
+
// prior header/footer rendering for these properties.
|
|
6759
|
+
fontFamily: font?.family || resolveFontFamily(theme, normalStyle.font) || getThemeFonts(theme).body.family,
|
|
6760
|
+
fontSize: font?.size ?? normalStyle.size ?? 11,
|
|
6761
|
+
// Pass the raw color/token; createText resolves it. Fall back to the
|
|
6762
|
+
// Normal style color, then the theme's primary text color.
|
|
6763
|
+
fontColor: font?.color || normalStyle.color || "textPrimary",
|
|
6764
|
+
bold: font?.bold ?? false,
|
|
6765
|
+
italic: font?.italic ?? false,
|
|
6766
|
+
underline: font?.underline,
|
|
6767
|
+
fontWeight: font?.fontWeight,
|
|
6768
|
+
boldColor: textComp.props.boldColor,
|
|
6769
|
+
spacing: textComp.props.spacing,
|
|
6770
|
+
lineSpacing: font?.lineSpacing
|
|
6754
6771
|
})
|
|
6755
6772
|
);
|
|
6756
6773
|
} else if (isImageComponent(component)) {
|
|
6757
6774
|
const imageComp = component;
|
|
6758
|
-
let imageSource = imageComp.props
|
|
6775
|
+
let imageSource = resolveImageSource(imageComp.props);
|
|
6759
6776
|
if (!imageSource) {
|
|
6760
6777
|
elements.push(
|
|
6761
6778
|
new Paragraph7({
|
|
6762
6779
|
children: [
|
|
6763
6780
|
new TextRun6({
|
|
6764
|
-
text: "[IMAGE: Missing path or
|
|
6781
|
+
text: "[IMAGE: Missing path, base64, or svg property]",
|
|
6765
6782
|
font: getThemeFonts(theme).body.family,
|
|
6766
6783
|
size: 20,
|
|
6767
6784
|
bold: true,
|
|
@@ -6835,15 +6852,16 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
6835
6852
|
})
|
|
6836
6853
|
);
|
|
6837
6854
|
} catch (error) {
|
|
6855
|
+
const sourcePreview = imageSource.substring(0, 50);
|
|
6838
6856
|
console.error(
|
|
6839
|
-
`[Header/Footer Image Error] Failed to render image: ${
|
|
6857
|
+
`[Header/Footer Image Error] Failed to render image: ${sourcePreview}...`,
|
|
6840
6858
|
error instanceof Error ? error.message : error
|
|
6841
6859
|
);
|
|
6842
6860
|
elements.push(
|
|
6843
6861
|
new Paragraph7({
|
|
6844
6862
|
children: [
|
|
6845
6863
|
new TextRun6({
|
|
6846
|
-
text: `[IMAGE: ${
|
|
6864
|
+
text: `[IMAGE: ${sourcePreview}]`,
|
|
6847
6865
|
font: getThemeFonts(theme).body.family,
|
|
6848
6866
|
size: 20,
|
|
6849
6867
|
color: getThemeColors(theme).secondary,
|