@json-to-office/core-docx 0.17.1 → 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/index.js CHANGED
@@ -3469,216 +3469,116 @@ function getStyleIdForLevel(level) {
3469
3469
  return styleMap[level] || "Heading1";
3470
3470
  }
3471
3471
 
3472
- // src/utils/textParser.ts
3473
- import { TextRun as TextRun2, ExternalHyperlink as ExternalHyperlink2, InternalHyperlink as InternalHyperlink2 } from "docx";
3474
-
3475
- // src/utils/placeholderProcessor.ts
3476
- import {
3477
- TextRun,
3478
- PageNumber
3479
- } from "docx";
3472
+ // src/core/render.ts
3473
+ init_styleHelpers();
3474
+ init_layoutUtils();
3480
3475
 
3481
- // src/utils/unicode.ts
3482
- function normalizeUnicodeText(text) {
3483
- return (text ?? "").normalize("NFC");
3484
- }
3476
+ // src/cache/index.ts
3477
+ var cache_exports = {};
3478
+ __export(cache_exports, {
3479
+ CacheKeyGenerator: () => CacheKeyGenerator
3480
+ });
3481
+ __reExport(cache_exports, cache_star);
3482
+ import * as cache_star from "@json-to-office/shared/cache";
3485
3483
 
3486
- // src/utils/placeholderProcessor.ts
3487
- var PlaceholderRegistry = class {
3488
- static handlers = /* @__PURE__ */ new Map();
3489
- /**
3490
- * Register a placeholder handler
3491
- */
3492
- static register(name, handler) {
3493
- this.handlers.set(name.toUpperCase(), handler);
3484
+ // src/cache/key-generator.ts
3485
+ import { createHash } from "crypto";
3486
+ var CacheKeyGenerator = class {
3487
+ version;
3488
+ constructor(version = "1.0") {
3489
+ this.version = version;
3494
3490
  }
3495
3491
  /**
3496
- * Get a placeholder handler
3492
+ * Generate cache key for a component
3497
3493
  */
3498
- static get(name) {
3499
- return this.handlers.get(name.toUpperCase());
3494
+ generateKey(component, context, options = {}) {
3495
+ const parts = [
3496
+ this.version,
3497
+ component.name,
3498
+ this.hashProps(component.props)
3499
+ ];
3500
+ if (options.includeTheme !== false) {
3501
+ parts.push(context.theme.name);
3502
+ }
3503
+ if (options.includeContext) {
3504
+ parts.push(this.hashContext(context));
3505
+ }
3506
+ if (options.additionalKeys) {
3507
+ parts.push(...options.additionalKeys);
3508
+ }
3509
+ if (options.version) {
3510
+ parts.push(options.version);
3511
+ }
3512
+ return parts.join(":");
3500
3513
  }
3501
3514
  /**
3502
- * Check if a placeholder is registered
3515
+ * Hash component props
3503
3516
  */
3504
- static has(name) {
3505
- return this.handlers.has(name.toUpperCase());
3517
+ hashProps(props) {
3518
+ if (!props) return "null";
3519
+ const normalized = this.normalizeObject(props);
3520
+ const json = JSON.stringify(normalized);
3521
+ return this.hash(json);
3506
3522
  }
3507
3523
  /**
3508
- * Get all registered placeholder names
3524
+ * Hash render context
3509
3525
  */
3510
- static getRegisteredNames() {
3511
- return Array.from(this.handlers.keys());
3526
+ hashContext(context) {
3527
+ const relevant = {
3528
+ theme: context.theme.name,
3529
+ document: context.document
3530
+ // Exclude runtime properties like sectionIndex, componentIndex
3531
+ };
3532
+ return this.hash(JSON.stringify(relevant));
3512
3533
  }
3513
3534
  /**
3514
- * Clear all registered placeholders
3535
+ * Normalize object for consistent hashing
3515
3536
  */
3516
- static clear() {
3517
- this.handlers.clear();
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
- }
3537
+ normalizeObject(obj) {
3538
+ if (obj === null || obj === void 0) return obj;
3539
+ if (Array.isArray(obj)) {
3540
+ return obj.map((item) => this.normalizeObject(item));
3532
3541
  }
3533
- if (match[7]) {
3534
- const placeholderName = match[7];
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);
3542
+ if (obj instanceof Date) {
3543
+ return obj.toISOString();
3577
3544
  }
3578
- lastIndex = match.index + match[0].length;
3579
- }
3580
- if (lastIndex < normalizedText.length) {
3581
- const remainingText = normalizedText.substring(lastIndex);
3582
- if (remainingText) {
3583
- result.push(...createTextRunsWithNewlines(remainingText, baseStyle));
3545
+ if (typeof obj === "object") {
3546
+ const sorted = {};
3547
+ const keys = Object.keys(obj).sort();
3548
+ for (const key of keys) {
3549
+ sorted[key] = this.normalizeObject(obj[key]);
3550
+ }
3551
+ return sorted;
3584
3552
  }
3553
+ return obj;
3585
3554
  }
3586
- if (result.length === 0 && normalizedText) {
3587
- result.push(...createTextRunsWithNewlines(normalizedText, baseStyle));
3588
- }
3589
- return result;
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
- }
3555
+ /**
3556
+ * Create hash
3557
+ */
3558
+ hash(input) {
3559
+ return createHash("sha256").update(input).digest("hex").substring(0, 16);
3611
3560
  }
3612
- return runs;
3613
- }
3614
- function initializeBuiltinPlaceholders() {
3615
- PlaceholderRegistry.register("PAGE", (context) => {
3616
- return new TextRun({
3617
- children: [PageNumber.CURRENT],
3618
- font: context?.style?.font,
3619
- size: context?.style?.size,
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
- });
3561
+ };
3562
+
3563
+ // src/utils/revisionUtils.ts
3564
+ import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
3565
+
3566
+ // src/utils/unicode.ts
3567
+ function normalizeUnicodeText(text) {
3568
+ return (text ?? "").normalize("NFC");
3675
3569
  }
3676
- initializeBuiltinPlaceholders();
3570
+
3571
+ // src/utils/placeholderProcessor.ts
3572
+ import {
3573
+ TextRun as TextRun2,
3574
+ PageNumber
3575
+ } from "docx";
3677
3576
 
3678
3577
  // src/utils/textParser.ts
3578
+ import { TextRun, ExternalHyperlink, InternalHyperlink } from "docx";
3679
3579
  function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
3680
3580
  if (!text) {
3681
- return [new TextRun2({ text: "", ...baseStyle })];
3581
+ return [new TextRun({ text: "", ...baseStyle })];
3682
3582
  }
3683
3583
  const normalizedText = normalizeUnicodeText(text);
3684
3584
  const hasPlaceholders = /\{[^}]+\}/.test(normalizedText);
@@ -3700,7 +3600,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
3700
3600
  if (match.index > lastIndex) {
3701
3601
  const plainText = normalizedText.substring(lastIndex, match.index);
3702
3602
  if (plainText) {
3703
- runs.push(...createTextRunsWithNewlines2(plainText, baseStyle, options));
3603
+ runs.push(...createTextRunsWithNewlines(plainText, baseStyle, options));
3704
3604
  }
3705
3605
  }
3706
3606
  let decoratedText;
@@ -3719,7 +3619,7 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
3719
3619
  } else {
3720
3620
  decoratedText = match[0];
3721
3621
  }
3722
- const decoratedRuns = createTextRunsWithNewlines2(
3622
+ const decoratedRuns = createTextRunsWithNewlines(
3723
3623
  decoratedText,
3724
3624
  baseStyle,
3725
3625
  options,
@@ -3735,18 +3635,18 @@ function parseTextWithDecorators(text, baseStyle = {}, options = {}) {
3735
3635
  const remainingText = normalizedText.substring(lastIndex);
3736
3636
  if (remainingText) {
3737
3637
  runs.push(
3738
- ...createTextRunsWithNewlines2(remainingText, baseStyle, options)
3638
+ ...createTextRunsWithNewlines(remainingText, baseStyle, options)
3739
3639
  );
3740
3640
  }
3741
3641
  }
3742
3642
  if (runs.length === 0 && normalizedText) {
3743
3643
  runs.push(
3744
- ...createTextRunsWithNewlines2(normalizedText, baseStyle, options)
3644
+ ...createTextRunsWithNewlines(normalizedText, baseStyle, options)
3745
3645
  );
3746
3646
  }
3747
3647
  return runs;
3748
3648
  }
3749
- function createTextRunsWithNewlines2(text, baseStyle, options, overrideStyle) {
3649
+ function createTextRunsWithNewlines(text, baseStyle, options, overrideStyle) {
3750
3650
  const runs = [];
3751
3651
  const lines = text.split("\n");
3752
3652
  for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
@@ -3758,7 +3658,7 @@ function createTextRunsWithNewlines2(text, baseStyle, options, overrideStyle) {
3758
3658
  italics: overrideStyle?.italics ?? baseStyle.italics
3759
3659
  };
3760
3660
  runs.push(
3761
- new TextRun2({
3661
+ new TextRun({
3762
3662
  text: line,
3763
3663
  ...baseStyle.font && { font: baseStyle.font },
3764
3664
  ...baseStyle.size && { size: baseStyle.size },
@@ -3804,7 +3704,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
3804
3704
  if (isInternal) {
3805
3705
  const bookmarkId = linkUrl.substring(1);
3806
3706
  runs.push(
3807
- new InternalHyperlink2({
3707
+ new InternalHyperlink({
3808
3708
  children: linkTextRuns,
3809
3709
  // Cast needed for docx types
3810
3710
  anchor: bookmarkId
@@ -3812,7 +3712,7 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
3812
3712
  );
3813
3713
  } else {
3814
3714
  runs.push(
3815
- new ExternalHyperlink2({
3715
+ new ExternalHyperlink({
3816
3716
  children: linkTextRuns,
3817
3717
  // Cast needed for docx types
3818
3718
  link: linkUrl
@@ -3841,100 +3741,199 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
3841
3741
  return runs;
3842
3742
  }
3843
3743
 
3844
- // src/core/render.ts
3845
- init_colorUtils();
3846
- init_styleHelpers();
3847
- init_layoutUtils();
3848
-
3849
- // src/cache/index.ts
3850
- var cache_exports = {};
3851
- __export(cache_exports, {
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;
3744
+ // src/utils/placeholderProcessor.ts
3745
+ var PlaceholderRegistry = class {
3746
+ static handlers = /* @__PURE__ */ new Map();
3747
+ /**
3748
+ * Register a placeholder handler
3749
+ */
3750
+ static register(name, handler) {
3751
+ this.handlers.set(name.toUpperCase(), handler);
3863
3752
  }
3864
3753
  /**
3865
- * Generate cache key for a component
3754
+ * Get a placeholder handler
3866
3755
  */
3867
- generateKey(component, context, options = {}) {
3868
- const parts = [
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(":");
3756
+ static get(name) {
3757
+ return this.handlers.get(name.toUpperCase());
3886
3758
  }
3887
3759
  /**
3888
- * Hash component props
3760
+ * Check if a placeholder is registered
3889
3761
  */
3890
- hashProps(props) {
3891
- if (!props) return "null";
3892
- const normalized = this.normalizeObject(props);
3893
- const json = JSON.stringify(normalized);
3894
- return this.hash(json);
3762
+ static has(name) {
3763
+ return this.handlers.has(name.toUpperCase());
3895
3764
  }
3896
3765
  /**
3897
- * Hash render context
3766
+ * Get all registered placeholder names
3898
3767
  */
3899
- hashContext(context) {
3900
- const relevant = {
3901
- theme: context.theme.name,
3902
- document: context.document
3903
- // Exclude runtime properties like sectionIndex, componentIndex
3904
- };
3905
- return this.hash(JSON.stringify(relevant));
3768
+ static getRegisteredNames() {
3769
+ return Array.from(this.handlers.keys());
3906
3770
  }
3907
3771
  /**
3908
- * Normalize object for consistent hashing
3772
+ * Clear all registered placeholders
3909
3773
  */
3910
- normalizeObject(obj) {
3911
- if (obj === null || obj === void 0) return obj;
3912
- if (Array.isArray(obj)) {
3913
- return obj.map((item) => this.normalizeObject(item));
3914
- }
3915
- if (obj instanceof Date) {
3916
- return obj.toISOString();
3774
+ static clear() {
3775
+ this.handlers.clear();
3776
+ }
3777
+ };
3778
+ function processTextWithPlaceholders(text, baseStyle = {}, context = {}) {
3779
+ const normalizedText = normalizeUnicodeText(text);
3780
+ const combinedRegex = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
3781
+ const result = [];
3782
+ let lastIndex = 0;
3783
+ let match;
3784
+ while ((match = combinedRegex.exec(normalizedText)) !== null) {
3785
+ if (match.index > lastIndex) {
3786
+ const beforeText = normalizedText.substring(lastIndex, match.index);
3787
+ if (beforeText) {
3788
+ result.push(...createTextRunsWithNewlines2(beforeText, baseStyle));
3789
+ }
3917
3790
  }
3918
- if (typeof obj === "object") {
3919
- const sorted = {};
3920
- const keys = Object.keys(obj).sort();
3921
- for (const key of keys) {
3922
- sorted[key] = this.normalizeObject(obj[key]);
3791
+ if (match[7]) {
3792
+ const placeholderName = match[7];
3793
+ const handler = PlaceholderRegistry.get(placeholderName);
3794
+ if (handler) {
3795
+ const placeholderResult = handler({ ...context, style: baseStyle });
3796
+ if (Array.isArray(placeholderResult)) {
3797
+ result.push(...placeholderResult);
3798
+ } else if (placeholderResult instanceof TextRun2) {
3799
+ result.push(placeholderResult);
3800
+ } else if (typeof placeholderResult === "string") {
3801
+ result.push(
3802
+ ...createTextRunsWithNewlines2(placeholderResult, baseStyle)
3803
+ );
3804
+ }
3805
+ } else {
3806
+ result.push(...createTextRunsWithNewlines2(match[0], baseStyle));
3923
3807
  }
3924
- return sorted;
3808
+ } else {
3809
+ let decoratedText;
3810
+ let bold = baseStyle.bold || false;
3811
+ let italics = baseStyle.italics || false;
3812
+ if (match[1] === "***" || match[1] === "___") {
3813
+ decoratedText = match[2];
3814
+ bold = true;
3815
+ italics = true;
3816
+ } else if (match[3] === "**" || match[3] === "__") {
3817
+ decoratedText = match[4];
3818
+ bold = true;
3819
+ } else if (match[5] === "*" || match[5] === "_") {
3820
+ decoratedText = match[6];
3821
+ italics = true;
3822
+ } else {
3823
+ decoratedText = match[0];
3824
+ }
3825
+ const decoratedTextRuns = processTextWithPlaceholders(
3826
+ decoratedText,
3827
+ {
3828
+ ...baseStyle,
3829
+ bold,
3830
+ italics
3831
+ },
3832
+ context
3833
+ );
3834
+ result.push(...decoratedTextRuns);
3925
3835
  }
3926
- return obj;
3836
+ lastIndex = match.index + match[0].length;
3927
3837
  }
3928
- /**
3929
- * Create hash
3930
- */
3931
- hash(input) {
3932
- return createHash("sha256").update(input).digest("hex").substring(0, 16);
3838
+ if (lastIndex < normalizedText.length) {
3839
+ const remainingText = normalizedText.substring(lastIndex);
3840
+ if (remainingText) {
3841
+ result.push(...createTextRunsWithNewlines2(remainingText, baseStyle));
3842
+ }
3933
3843
  }
3934
- };
3844
+ if (result.length === 0 && normalizedText) {
3845
+ result.push(...createTextRunsWithNewlines2(normalizedText, baseStyle));
3846
+ }
3847
+ return result;
3848
+ }
3849
+ function createTextRunsWithNewlines2(text, baseStyle) {
3850
+ const runs = [];
3851
+ const lines = text.split("\n");
3852
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
3853
+ const line = lines[lineIndex];
3854
+ const needsLineBreak = lineIndex > 0;
3855
+ if (line || needsLineBreak) {
3856
+ runs.push(
3857
+ new TextRun2({
3858
+ text: line,
3859
+ font: baseStyle.font,
3860
+ size: baseStyle.size,
3861
+ color: baseStyle.color,
3862
+ bold: baseStyle.bold,
3863
+ italics: baseStyle.italics,
3864
+ underline: baseStyle.underline,
3865
+ break: needsLineBreak ? 1 : void 0
3866
+ })
3867
+ );
3868
+ }
3869
+ }
3870
+ return runs;
3871
+ }
3872
+ function initializeBuiltinPlaceholders() {
3873
+ PlaceholderRegistry.register("PAGE", (context) => {
3874
+ return new TextRun2({
3875
+ children: [PageNumber.CURRENT],
3876
+ font: context?.style?.font,
3877
+ size: context?.style?.size,
3878
+ color: context?.style?.color,
3879
+ bold: context?.style?.bold,
3880
+ italics: context?.style?.italics,
3881
+ underline: context?.style?.underline
3882
+ });
3883
+ });
3884
+ PlaceholderRegistry.register("TOTAL_PAGES", (context) => {
3885
+ return new TextRun2({
3886
+ children: [PageNumber.TOTAL_PAGES],
3887
+ font: context?.style?.font,
3888
+ size: context?.style?.size,
3889
+ color: context?.style?.color,
3890
+ bold: context?.style?.bold,
3891
+ italics: context?.style?.italics,
3892
+ underline: context?.style?.underline
3893
+ });
3894
+ });
3895
+ PlaceholderRegistry.register("DATE", (context) => {
3896
+ const today = /* @__PURE__ */ new Date();
3897
+ const dateString = today.toLocaleDateString();
3898
+ return new TextRun2({
3899
+ text: dateString,
3900
+ font: context?.style?.font,
3901
+ size: context?.style?.size,
3902
+ color: context?.style?.color,
3903
+ bold: context?.style?.bold,
3904
+ italics: context?.style?.italics,
3905
+ underline: context?.style?.underline
3906
+ });
3907
+ });
3908
+ PlaceholderRegistry.register("DATETIME", (context) => {
3909
+ const now = /* @__PURE__ */ new Date();
3910
+ const dateTimeString = now.toLocaleString();
3911
+ return new TextRun2({
3912
+ text: dateTimeString,
3913
+ font: context?.style?.font,
3914
+ size: context?.style?.size,
3915
+ color: context?.style?.color,
3916
+ bold: context?.style?.bold,
3917
+ italics: context?.style?.italics,
3918
+ underline: context?.style?.underline
3919
+ });
3920
+ });
3921
+ PlaceholderRegistry.register("YEAR", (context) => {
3922
+ const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
3923
+ return new TextRun2({
3924
+ text: year,
3925
+ font: context?.style?.font,
3926
+ size: context?.style?.size,
3927
+ color: context?.style?.color,
3928
+ bold: context?.style?.bold,
3929
+ italics: context?.style?.italics,
3930
+ underline: context?.style?.underline
3931
+ });
3932
+ });
3933
+ }
3934
+ initializeBuiltinPlaceholders();
3935
3935
 
3936
3936
  // src/utils/revisionUtils.ts
3937
- import { TextRun as TextRun3, InsertedTextRun, DeletedTextRun } from "docx";
3938
3937
  var DEFAULT_REVISION_AUTHOR = "json-to-office";
3939
3938
  var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
3940
3939
  var RevisionIdRegistry = class {
@@ -6736,21 +6735,26 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
6736
6735
  for (const component of activeComponents) {
6737
6736
  if (isParagraphComponent(component)) {
6738
6737
  const textComp = component;
6738
+ const font = textComp.props.font;
6739
6739
  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
6740
  elements.push(
6750
- new Paragraph7({
6751
- children: textRuns,
6752
- alignment: textComp.props.alignment ? getAlignment3(textComp.props.alignment) : void 0,
6753
- style: "Normal"
6741
+ createText(textComp.props.text, theme, themeName, {
6742
+ style: "Normal",
6743
+ alignment: textComp.props.alignment,
6744
+ // Resolve explicit run styling against the Normal style, preserving
6745
+ // prior header/footer rendering for these properties.
6746
+ fontFamily: font?.family || resolveFontFamily(theme, normalStyle.font) || getThemeFonts(theme).body.family,
6747
+ fontSize: font?.size ?? normalStyle.size ?? 11,
6748
+ // Pass the raw color/token; createText resolves it. Fall back to the
6749
+ // Normal style color, then the theme's primary text color.
6750
+ fontColor: font?.color || normalStyle.color || "textPrimary",
6751
+ bold: font?.bold ?? false,
6752
+ italic: font?.italic ?? false,
6753
+ underline: font?.underline,
6754
+ fontWeight: font?.fontWeight,
6755
+ boldColor: textComp.props.boldColor,
6756
+ spacing: textComp.props.spacing,
6757
+ lineSpacing: font?.lineSpacing
6754
6758
  })
6755
6759
  );
6756
6760
  } else if (isImageComponent(component)) {