@json-to-office/core-docx 0.20.0 → 0.22.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.
Files changed (50) hide show
  1. package/dist/components/highcharts.d.ts.map +1 -1
  2. package/dist/components/section.d.ts.map +1 -1
  3. package/dist/components/toc/index.d.ts.map +1 -1
  4. package/dist/core/cached-render.d.ts.map +1 -1
  5. package/dist/core/content.d.ts.map +1 -1
  6. package/dist/core/generator.d.ts +6 -2
  7. package/dist/core/generator.d.ts.map +1 -1
  8. package/dist/core/render.d.ts +8 -6
  9. package/dist/core/render.d.ts.map +1 -1
  10. package/dist/core/structure.d.ts +5 -2
  11. package/dist/core/structure.d.ts.map +1 -1
  12. package/dist/index.js +508 -381
  13. package/dist/index.js.map +1 -1
  14. package/dist/plugin/createDocumentGenerator.d.ts +4 -0
  15. package/dist/plugin/createDocumentGenerator.d.ts.map +1 -1
  16. package/dist/plugin/example/index.js +486 -321
  17. package/dist/plugin/example/index.js.map +1 -1
  18. package/dist/plugin/types.d.ts +4 -0
  19. package/dist/plugin/types.d.ts.map +1 -1
  20. package/dist/styles/utils/colorUtils.d.ts +4 -3
  21. package/dist/styles/utils/colorUtils.d.ts.map +1 -1
  22. package/dist/styles/utils/resolveComponentTree.d.ts +3 -0
  23. package/dist/styles/utils/resolveComponentTree.d.ts.map +1 -1
  24. package/dist/templates/themes/apex.docx.theme.json +1 -6
  25. package/dist/templates/themes/corporate.docx.theme.json +7 -7
  26. package/dist/templates/themes/devportal.docx.theme.json +1 -6
  27. package/dist/templates/themes/index.d.ts +12 -0
  28. package/dist/templates/themes/index.d.ts.map +1 -1
  29. package/dist/templates/themes/minimal.docx.theme.json +1 -6
  30. package/dist/templates/themes/modern.docx.theme.json +1 -6
  31. package/dist/themes/defaults.d.ts +3 -0
  32. package/dist/themes/defaults.d.ts.map +1 -1
  33. package/dist/tsconfig.tsbuildinfo +1 -1
  34. package/dist/utils/bookmarkRegistry.d.ts +5 -2
  35. package/dist/utils/bookmarkRegistry.d.ts.map +1 -1
  36. package/dist/utils/fixFloatingImageIds.d.ts +3 -0
  37. package/dist/utils/fixFloatingImageIds.d.ts.map +1 -1
  38. package/dist/utils/generationContext.d.ts +5 -0
  39. package/dist/utils/generationContext.d.ts.map +1 -0
  40. package/dist/utils/numberingConfig.d.ts +5 -2
  41. package/dist/utils/numberingConfig.d.ts.map +1 -1
  42. package/dist/utils/packageDocument.d.ts +20 -0
  43. package/dist/utils/packageDocument.d.ts.map +1 -0
  44. package/dist/utils/placeholderProcessor.d.ts +5 -5
  45. package/dist/utils/placeholderProcessor.d.ts.map +1 -1
  46. package/dist/utils/revisionUtils.d.ts +5 -5
  47. package/dist/utils/revisionUtils.d.ts.map +1 -1
  48. package/dist/utils/textParser.d.ts +3 -3
  49. package/dist/utils/textParser.d.ts.map +1 -1
  50. package/package.json +3 -3
@@ -362,12 +362,7 @@ var init_minimal_docx_theme = __esm({
362
362
  },
363
363
  componentDefaults: {
364
364
  table: {
365
- borders: false,
366
- striped: false,
367
- headerBackground: "#fafafa",
368
- headerColor: "#000000",
369
- borderColor: "#f0f0f0",
370
- borderWidth: 0.5
365
+ borderColor: "#f0f0f0"
371
366
  },
372
367
  list: {
373
368
  format: "bullet",
@@ -450,7 +445,12 @@ var init_corporate_docx_theme = __esm({
450
445
  keepNext: true,
451
446
  alignment: "left",
452
447
  borders: {
453
- bottom: { style: "single", size: 2, color: "primary", space: 6 }
448
+ bottom: {
449
+ style: "single",
450
+ size: 2,
451
+ color: "primary",
452
+ space: 6
453
+ }
454
454
  }
455
455
  },
456
456
  heading2: {
@@ -490,12 +490,7 @@ var init_corporate_docx_theme = __esm({
490
490
  },
491
491
  componentDefaults: {
492
492
  table: {
493
- borders: true,
494
- striped: true,
495
- headerBackground: "#1a365d",
496
- headerColor: "#FFFFFF",
497
- borderColor: "#E2E8F0",
498
- borderWidth: 0.5
493
+ borderColor: "#E2E8F0"
499
494
  },
500
495
  list: {
501
496
  format: "bullet",
@@ -612,12 +607,7 @@ var init_modern_docx_theme = __esm({
612
607
  },
613
608
  componentDefaults: {
614
609
  table: {
615
- borders: true,
616
- striped: false,
617
- headerBackground: "#6D28D9",
618
- headerColor: "#FFFFFF",
619
- borderColor: "#E2E8F0",
620
- borderWidth: 0.5
610
+ borderColor: "#E2E8F0"
621
611
  },
622
612
  list: {
623
613
  format: "bullet",
@@ -718,10 +708,13 @@ function resolveColor(colorValue, theme) {
718
708
  );
719
709
  }
720
710
  const colors = getThemeColors(theme);
721
- if (colorValue in colors) {
722
- const resolvedColor = colors[colorValue];
711
+ const resolvedColor = colors[colorValue];
712
+ if (typeof resolvedColor === "string") {
723
713
  return resolveColor(resolvedColor, theme);
724
714
  }
715
+ if (/^[0-9A-Fa-f]{6}$/.test(colorValue)) {
716
+ return colorValue.toUpperCase();
717
+ }
725
718
  throw new Error(
726
719
  `Invalid color value: "${colorValue}". Must be a hex color with # prefix (e.g., "#000000") or a valid theme color name.`
727
720
  );
@@ -1613,219 +1606,11 @@ var init_docxImagePositioning = __esm({
1613
1606
  }
1614
1607
  });
1615
1608
 
1616
- // src/utils/numberingConfig.ts
1617
- var numberingConfig_exports = {};
1618
- __export(numberingConfig_exports, {
1619
- NumberingRegistry: () => NumberingRegistry,
1620
- createBulletListConfig: () => createBulletListConfig,
1621
- createNumberedListConfig: () => createNumberedListConfig,
1622
- createNumberingConfig: () => createNumberingConfig,
1623
- globalNumberingRegistry: () => globalNumberingRegistry
1624
- });
1625
- import { AlignmentType as AlignmentType3, convertInchesToTwip, LevelFormat } from "docx";
1626
- function getLevelFormat(format2) {
1627
- if (!format2) return LevelFormat.BULLET;
1628
- return LEVEL_FORMAT_MAP[format2] || LevelFormat.BULLET;
1629
- }
1630
- function getAlignment2(alignment) {
1631
- if (!alignment) return AlignmentType3.LEFT;
1632
- return ALIGNMENT_MAP[alignment] || AlignmentType3.LEFT;
1633
- }
1634
- function createDefaultLevel(level, format2 = LevelFormat.BULLET, text) {
1635
- const baseIndent = 0.5 * (level + 1);
1636
- const hangingIndent = 0.25;
1637
- return {
1638
- level,
1639
- format: format2,
1640
- text: text || (format2 === LevelFormat.BULLET ? "\u2022" : "%1."),
1641
- alignment: AlignmentType3.LEFT,
1642
- style: {
1643
- paragraph: {
1644
- indent: {
1645
- left: convertInchesToTwip(baseIndent),
1646
- hanging: convertInchesToTwip(hangingIndent)
1647
- }
1648
- }
1649
- }
1650
- };
1651
- }
1652
- function createNumberingConfig(config) {
1653
- const levels = [];
1654
- for (const levelConfig of config.levels) {
1655
- const format2 = getLevelFormat(levelConfig.format);
1656
- const alignment = getAlignment2(levelConfig.alignment);
1657
- const text = levelConfig.text || (format2 === LevelFormat.BULLET ? "\u2022" : `%${levelConfig.level + 1}.`);
1658
- const baseIndent = levelConfig.indent?.left !== void 0 ? levelConfig.indent.left / 72 : 0.5 * (levelConfig.level + 1);
1659
- const hangingIndent = levelConfig.indent?.hanging !== void 0 ? levelConfig.indent.hanging / 72 : 0.25;
1660
- const level = {
1661
- level: levelConfig.level,
1662
- format: format2,
1663
- text,
1664
- alignment,
1665
- style: {
1666
- paragraph: {
1667
- indent: {
1668
- left: convertInchesToTwip(baseIndent),
1669
- hanging: convertInchesToTwip(hangingIndent)
1670
- }
1671
- }
1672
- },
1673
- // Add start number if specified
1674
- ...levelConfig.start !== void 0 && { start: levelConfig.start }
1675
- };
1676
- levels.push(level);
1677
- }
1678
- return {
1679
- reference: config.reference,
1680
- levels
1681
- };
1682
- }
1683
- function createBulletListConfig(reference, bullet = "\u2022") {
1684
- return {
1685
- reference,
1686
- levels: [
1687
- createDefaultLevel(0, LevelFormat.BULLET, bullet),
1688
- createDefaultLevel(1, LevelFormat.BULLET, "\u25E6"),
1689
- createDefaultLevel(2, LevelFormat.BULLET, "\u25AA")
1690
- ]
1691
- };
1692
- }
1693
- function createNumberedListConfig(reference, start = 1) {
1694
- return {
1695
- reference,
1696
- levels: [
1697
- { ...createDefaultLevel(0, LevelFormat.DECIMAL, "%1."), start },
1698
- createDefaultLevel(1, LevelFormat.LOWER_LETTER, "%2."),
1699
- createDefaultLevel(2, LevelFormat.LOWER_ROMAN, "%3.")
1700
- ]
1701
- };
1702
- }
1703
- var LEVEL_FORMAT_MAP, ALIGNMENT_MAP, NumberingRegistry, globalNumberingRegistry;
1704
- var init_numberingConfig = __esm({
1705
- "src/utils/numberingConfig.ts"() {
1706
- "use strict";
1707
- LEVEL_FORMAT_MAP = {
1708
- decimal: LevelFormat.DECIMAL,
1709
- upperRoman: LevelFormat.UPPER_ROMAN,
1710
- lowerRoman: LevelFormat.LOWER_ROMAN,
1711
- upperLetter: LevelFormat.UPPER_LETTER,
1712
- lowerLetter: LevelFormat.LOWER_LETTER,
1713
- bullet: LevelFormat.BULLET,
1714
- ordinal: LevelFormat.ORDINAL,
1715
- cardinalText: LevelFormat.CARDINAL_TEXT,
1716
- ordinalText: LevelFormat.ORDINAL_TEXT,
1717
- hex: LevelFormat.HEX,
1718
- chicago: LevelFormat.CHICAGO,
1719
- ideographDigital: LevelFormat.IDEOGRAPH__DIGITAL,
1720
- japaneseCounting: LevelFormat.JAPANESE_COUNTING,
1721
- aiueo: LevelFormat.AIUEO,
1722
- iroha: LevelFormat.IROHA,
1723
- decimalFullWidth: LevelFormat.DECIMAL_FULL_WIDTH,
1724
- decimalHalfWidth: LevelFormat.DECIMAL_HALF_WIDTH,
1725
- japaneseLegal: LevelFormat.JAPANESE_LEGAL,
1726
- japaneseDigitalTenThousand: LevelFormat.JAPANESE_DIGITAL_TEN_THOUSAND,
1727
- decimalEnclosedCircle: LevelFormat.DECIMAL_ENCLOSED_CIRCLE,
1728
- decimalFullWidth2: LevelFormat.DECIMAL_FULL_WIDTH2,
1729
- aiueoFullWidth: LevelFormat.AIUEO_FULL_WIDTH,
1730
- irohaFullWidth: LevelFormat.IROHA_FULL_WIDTH,
1731
- decimalZero: LevelFormat.DECIMAL_ZERO,
1732
- ganada: LevelFormat.GANADA,
1733
- chosung: LevelFormat.CHOSUNG,
1734
- decimalEnclosedFullstop: LevelFormat.DECIMAL_ENCLOSED_FULLSTOP,
1735
- decimalEnclosedParen: LevelFormat.DECIMAL_ENCLOSED_PARENTHESES,
1736
- decimalEnclosedCircleChinese: LevelFormat.DECIMAL_ENCLOSED_CIRCLE_CHINESE,
1737
- ideographEnclosedCircle: LevelFormat.IDEOGRAPH_ENCLOSED_CIRCLE,
1738
- ideographTraditional: LevelFormat.IDEOGRAPH_TRADITIONAL,
1739
- ideographZodiac: LevelFormat.IDEOGRAPH_ZODIAC,
1740
- ideographZodiacTraditional: LevelFormat.IDEOGRAPH_ZODIAC_TRADITIONAL,
1741
- taiwaneseCounting: LevelFormat.TAIWANESE_COUNTING,
1742
- ideographLegalTraditional: LevelFormat.IDEOGRAPH_LEGAL_TRADITIONAL,
1743
- taiwaneseCountingThousand: LevelFormat.TAIWANESE_COUNTING_THOUSAND,
1744
- taiwaneseDigital: LevelFormat.TAIWANESE_DIGITAL,
1745
- chineseCounting: LevelFormat.CHINESE_COUNTING,
1746
- chineseLegalSimplified: LevelFormat.CHINESE_LEGAL_SIMPLIFIED,
1747
- chineseCountingThousand: LevelFormat.CHINESE_COUNTING_THOUSAND,
1748
- koreanDigital: LevelFormat.KOREAN_DIGITAL,
1749
- koreanCounting: LevelFormat.KOREAN_COUNTING,
1750
- koreanLegal: LevelFormat.KOREAN_LEGAL,
1751
- koreanDigital2: LevelFormat.KOREAN_DIGITAL2,
1752
- vietnameseCounting: LevelFormat.VIETNAMESE_COUNTING,
1753
- russianLower: LevelFormat.RUSSIAN_LOWER,
1754
- russianUpper: LevelFormat.RUSSIAN_UPPER,
1755
- none: LevelFormat.NONE,
1756
- numberInDash: LevelFormat.NUMBER_IN_DASH,
1757
- hebrew1: LevelFormat.HEBREW1,
1758
- hebrew2: LevelFormat.HEBREW2,
1759
- arabicAlpha: LevelFormat.ARABIC_ALPHA,
1760
- arabicAbjad: LevelFormat.ARABIC_ABJAD,
1761
- hindiVowels: LevelFormat.HINDI_VOWELS,
1762
- hindiConsonants: LevelFormat.HINDI_CONSONANTS,
1763
- hindiNumbers: LevelFormat.HINDI_NUMBERS,
1764
- hindiCounting: LevelFormat.HINDI_COUNTING,
1765
- thaiLetters: LevelFormat.THAI_LETTERS,
1766
- thaiNumbers: LevelFormat.THAI_NUMBERS,
1767
- thaiCounting: LevelFormat.THAI_COUNTING
1768
- };
1769
- ALIGNMENT_MAP = {
1770
- start: AlignmentType3.START,
1771
- end: AlignmentType3.END,
1772
- left: AlignmentType3.LEFT,
1773
- right: AlignmentType3.RIGHT,
1774
- center: AlignmentType3.CENTER
1775
- };
1776
- NumberingRegistry = class {
1777
- configs = /* @__PURE__ */ new Map();
1778
- counter = 0;
1779
- /**
1780
- * Register a numbering configuration
1781
- */
1782
- register(config) {
1783
- const reference = config.reference;
1784
- this.configs.set(reference, config);
1785
- return reference;
1786
- }
1787
- /**
1788
- * Generate a unique reference ID
1789
- */
1790
- generateReference(prefix = "list") {
1791
- return `${prefix}-${++this.counter}`;
1792
- }
1793
- /**
1794
- * Get all registered configurations as an array suitable for INumberingOptions
1795
- */
1796
- getAll() {
1797
- return Array.from(this.configs.values());
1798
- }
1799
- /**
1800
- * Clear all configurations
1801
- */
1802
- clear() {
1803
- this.configs.clear();
1804
- this.counter = 0;
1805
- }
1806
- /**
1807
- * Check if a reference exists
1808
- */
1809
- has(reference) {
1810
- return this.configs.has(reference);
1811
- }
1812
- /**
1813
- * Get a configuration by reference
1814
- */
1815
- get(reference) {
1816
- return this.configs.get(reference);
1817
- }
1818
- };
1819
- globalNumberingRegistry = new NumberingRegistry();
1820
- }
1821
- });
1822
-
1823
1609
  // src/plugin/example/index.ts
1824
1610
  import { Packer as Packer2 } from "docx";
1825
1611
 
1826
1612
  // src/plugin/createDocumentGenerator.ts
1827
1613
  init_styles();
1828
- import { Packer } from "docx";
1829
1614
  import { applyExportMode, scopedThemeName } from "@json-to-office/shared";
1830
1615
 
1831
1616
  // src/core/fontResolution.ts
@@ -2168,10 +1953,10 @@ var RESOLVER_MAP = {
2168
1953
  visual: resolveVisualProps
2169
1954
  };
2170
1955
  function resolveComponentDefaults(component, theme) {
2171
- if (!component.props) return component;
1956
+ const props = component.props ?? {};
2172
1957
  const resolver = RESOLVER_MAP[component.name];
2173
- const resolvedProps = resolver ? resolver(component.props, theme) : resolveCustomComponentProps(
2174
- component.props,
1958
+ const resolvedProps = resolver ? resolver(props, theme) : resolveCustomComponentProps(
1959
+ props,
2175
1960
  theme,
2176
1961
  component.name
2177
1962
  );
@@ -2192,8 +1977,8 @@ function resolveComponentTree(components, theme) {
2192
1977
  }
2193
1978
 
2194
1979
  // src/core/structure.ts
2195
- async function processDocument(document, theme, themeName) {
2196
- const metadata = createDocumentMetadata(document.props);
1980
+ async function processDocument(document, theme, themeName, generationDate) {
1981
+ const metadata = createDocumentMetadata(document.props, generationDate);
2197
1982
  const docDefaults = document.props.componentDefaults;
2198
1983
  const mergedComponentDefaults = docDefaults ? mergeWithDefaults2(docDefaults, theme.componentDefaults || {}) : void 0;
2199
1984
  const docNoProofWords = document.props.noProofWords;
@@ -2231,13 +2016,16 @@ async function processDocument(document, theme, themeName) {
2231
2016
  language: document.props.language
2232
2017
  };
2233
2018
  }
2234
- function createDocumentMetadata(props) {
2019
+ function createDocumentMetadata(props, generationDate = /* @__PURE__ */ new Date()) {
2235
2020
  return {
2236
2021
  title: props.metadata?.title,
2237
2022
  subtitle: props.metadata?.subtitle,
2023
+ description: props.metadata?.description,
2238
2024
  author: props.metadata?.author,
2239
2025
  company: props.metadata?.company,
2240
- date: props.metadata?.date ? new Date(props.metadata.date) : /* @__PURE__ */ new Date()
2026
+ version: props.metadata?.version,
2027
+ tags: props.metadata?.tags,
2028
+ date: props.metadata?.date ? new Date(props.metadata.date) : generationDate
2241
2029
  };
2242
2030
  }
2243
2031
  async function extractSections(components, context) {
@@ -3900,7 +3688,39 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
3900
3688
  return runs;
3901
3689
  }
3902
3690
 
3691
+ // src/utils/generationContext.ts
3692
+ import { AsyncLocalStorage } from "async_hooks";
3693
+ var generationDateStorage = new AsyncLocalStorage();
3694
+ function runWithGenerationDate(date, callback) {
3695
+ return generationDateStorage.run(date, callback);
3696
+ }
3697
+ function getGenerationDate() {
3698
+ return generationDateStorage.getStore() ?? /* @__PURE__ */ new Date();
3699
+ }
3700
+
3903
3701
  // src/utils/placeholderProcessor.ts
3702
+ function styledPlaceholderText(text, context) {
3703
+ return new TextRun2({
3704
+ text,
3705
+ font: context?.style?.font,
3706
+ size: context?.style?.size,
3707
+ color: context?.style?.color,
3708
+ bold: context?.style?.bold,
3709
+ italics: context?.style?.italics,
3710
+ underline: context?.style?.underline,
3711
+ language: context?.style?.language,
3712
+ noProof: context?.style?.noProof
3713
+ });
3714
+ }
3715
+ function placeholderDate(context) {
3716
+ return context?.date ?? getGenerationDate();
3717
+ }
3718
+ function isoDate(date) {
3719
+ return date.toISOString().slice(0, 10);
3720
+ }
3721
+ function isoDateTime(date) {
3722
+ return date.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z");
3723
+ }
3904
3724
  var PlaceholderRegistry = class {
3905
3725
  static handlers = /* @__PURE__ */ new Map();
3906
3726
  /**
@@ -3956,8 +3776,6 @@ function processTextWithPlaceholders(text, baseStyle = {}, context = {}, noProof
3956
3776
  const placeholderResult = handler({ ...context, style: baseStyle });
3957
3777
  if (Array.isArray(placeholderResult)) {
3958
3778
  result.push(...placeholderResult);
3959
- } else if (placeholderResult instanceof TextRun2) {
3960
- result.push(placeholderResult);
3961
3779
  } else if (typeof placeholderResult === "string") {
3962
3780
  result.push(
3963
3781
  ...createTextRunsWithNewlines2(
@@ -3966,6 +3784,8 @@ function processTextWithPlaceholders(text, baseStyle = {}, context = {}, noProof
3966
3784
  noProofWords
3967
3785
  )
3968
3786
  );
3787
+ } else {
3788
+ result.push(placeholderResult);
3969
3789
  }
3970
3790
  } else {
3971
3791
  result.push(
@@ -4080,59 +3900,51 @@ function initializeBuiltinPlaceholders() {
4080
3900
  underline: context?.style?.underline
4081
3901
  });
4082
3902
  });
4083
- PlaceholderRegistry.register("DATE", (context) => {
4084
- const today = /* @__PURE__ */ new Date();
4085
- const dateString = today.toLocaleDateString();
4086
- return new TextRun2({
4087
- text: dateString,
4088
- font: context?.style?.font,
4089
- size: context?.style?.size,
4090
- color: context?.style?.color,
4091
- bold: context?.style?.bold,
4092
- italics: context?.style?.italics,
4093
- underline: context?.style?.underline
4094
- });
4095
- });
4096
- PlaceholderRegistry.register("DATETIME", (context) => {
4097
- const now = /* @__PURE__ */ new Date();
4098
- const dateTimeString = now.toLocaleString();
4099
- return new TextRun2({
4100
- text: dateTimeString,
4101
- font: context?.style?.font,
4102
- size: context?.style?.size,
4103
- color: context?.style?.color,
4104
- bold: context?.style?.bold,
4105
- italics: context?.style?.italics,
4106
- underline: context?.style?.underline
4107
- });
4108
- });
4109
- PlaceholderRegistry.register("YEAR", (context) => {
4110
- const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
4111
- return new TextRun2({
4112
- text: year,
4113
- font: context?.style?.font,
4114
- size: context?.style?.size,
4115
- color: context?.style?.color,
4116
- bold: context?.style?.bold,
4117
- italics: context?.style?.italics,
4118
- underline: context?.style?.underline
4119
- });
4120
- });
3903
+ PlaceholderRegistry.register(
3904
+ "DATE",
3905
+ (context) => styledPlaceholderText(isoDate(placeholderDate(context)), context)
3906
+ );
3907
+ PlaceholderRegistry.register(
3908
+ "DATETIME",
3909
+ (context) => styledPlaceholderText(isoDateTime(placeholderDate(context)), context)
3910
+ );
3911
+ PlaceholderRegistry.register(
3912
+ "YEAR",
3913
+ (context) => styledPlaceholderText(
3914
+ String(placeholderDate(context).getUTCFullYear()),
3915
+ context
3916
+ )
3917
+ );
4121
3918
  }
4122
3919
  initializeBuiltinPlaceholders();
4123
3920
 
4124
3921
  // src/utils/revisionUtils.ts
3922
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
4125
3923
  var DEFAULT_REVISION_AUTHOR = "json-to-office";
4126
3924
  var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
4127
3925
  var RevisionIdRegistry = class {
4128
- counter = 0;
3926
+ fallbackCounter = 0;
3927
+ scopes = new AsyncLocalStorage2();
3928
+ runScoped(callback) {
3929
+ return this.scopes.run({ counter: 0 }, callback);
3930
+ }
4129
3931
  next() {
4130
- this.counter += 1;
4131
- return this.counter;
3932
+ const state = this.scopes.getStore();
3933
+ if (state) {
3934
+ state.counter += 1;
3935
+ return state.counter;
3936
+ }
3937
+ this.fallbackCounter += 1;
3938
+ return this.fallbackCounter;
4132
3939
  }
4133
3940
  /** Test-only: deterministic ids for snapshot assertions. */
4134
3941
  clear() {
4135
- this.counter = 0;
3942
+ const state = this.scopes.getStore();
3943
+ if (state) {
3944
+ state.counter = 0;
3945
+ } else {
3946
+ this.fallbackCounter = 0;
3947
+ }
4136
3948
  }
4137
3949
  };
4138
3950
  var globalRevisionIdRegistry = new RevisionIdRegistry();
@@ -4252,7 +4064,10 @@ function initializeComponentCache(cache) {
4252
4064
  }
4253
4065
  }
4254
4066
  async function renderComponentWithCache(component, theme, themeName, context, bypassCache = false) {
4255
- const forceBypassForType = component.name === "toc" || component.name === "section" || component.name === "visual" || componentHasRevision(component);
4067
+ const forceBypassForType = component.name === "toc" || component.name === "section" || component.name === "visual" || component.name === "heading" || // Both explicit lists and markdown-list paragraphs register numbering in
4068
+ // the current document scope. Cached paragraphs can otherwise reference
4069
+ // definitions that only existed in a previous render.
4070
+ component.name === "list" || component.name === "paragraph" || "id" in component || componentHasRevision(component);
4256
4071
  if (!componentCache) {
4257
4072
  initializeComponentCache();
4258
4073
  }
@@ -4262,8 +4077,9 @@ async function renderComponentWithCache(component, theme, themeName, context, by
4262
4077
  const componentProps = JSON.stringify(component.props || {});
4263
4078
  const themeHash = createThemeHash(theme);
4264
4079
  const contextKey = context?.section ? `${context.section.currentLayout}:${context.section.columnCount}` : "no-section";
4080
+ const generationDateKey = getGenerationDate().toISOString();
4265
4081
  const childrenKey = "children" in component && component.children ? `:children:${JSON.stringify(component.children)}` : "";
4266
- const cacheKey = `component:${component.name}:${themeHash}:${contextKey}:${componentProps}${childrenKey}`;
4082
+ const cacheKey = `component:${component.name}:${themeHash}:${contextKey}:${generationDateKey}:${componentProps}${childrenKey}`;
4267
4083
  const cached = await componentCache.get(cacheKey);
4268
4084
  if (cached) {
4269
4085
  return cached.result;
@@ -4311,19 +4127,27 @@ init_styles();
4311
4127
  init_defaults();
4312
4128
 
4313
4129
  // src/utils/bookmarkRegistry.ts
4130
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
4314
4131
  var BookmarkRegistry = class {
4315
- bookmarks = /* @__PURE__ */ new Map();
4316
- counter = 0;
4132
+ fallback = { bookmarks: /* @__PURE__ */ new Map() };
4133
+ scopes = new AsyncLocalStorage3();
4134
+ get state() {
4135
+ return this.scopes.getStore() ?? this.fallback;
4136
+ }
4137
+ /** Run work with an isolated registry that follows its async call chain. */
4138
+ runScoped(callback) {
4139
+ return this.scopes.run({ bookmarks: /* @__PURE__ */ new Map() }, callback);
4140
+ }
4317
4141
  /**
4318
4142
  * Register a bookmark
4319
4143
  */
4320
4144
  register(id, title, type) {
4321
- if (this.bookmarks.has(id)) {
4145
+ if (this.state.bookmarks.has(id)) {
4322
4146
  console.warn(
4323
4147
  `Duplicate bookmark ID: ${id}. Using the latest registration.`
4324
4148
  );
4325
4149
  }
4326
- this.bookmarks.set(id, { id, title, type });
4150
+ this.state.bookmarks.set(id, { id, title, type });
4327
4151
  }
4328
4152
  /**
4329
4153
  * Generate a unique bookmark ID from text
@@ -4333,7 +4157,7 @@ var BookmarkRegistry = class {
4333
4157
  const baseId = text.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").substring(0, 40);
4334
4158
  let id = baseId;
4335
4159
  let attempt = 0;
4336
- while (this.bookmarks.has(id) && attempt < 100) {
4160
+ while (this.state.bookmarks.has(id) && attempt < 100) {
4337
4161
  id = `${baseId}-${++attempt}`;
4338
4162
  }
4339
4163
  return id;
@@ -4342,26 +4166,25 @@ var BookmarkRegistry = class {
4342
4166
  * Check if a bookmark exists
4343
4167
  */
4344
4168
  exists(id) {
4345
- return this.bookmarks.has(id);
4169
+ return this.state.bookmarks.has(id);
4346
4170
  }
4347
4171
  /**
4348
4172
  * Get bookmark info by ID
4349
4173
  */
4350
4174
  get(id) {
4351
- return this.bookmarks.get(id);
4175
+ return this.state.bookmarks.get(id);
4352
4176
  }
4353
4177
  /**
4354
4178
  * Get all registered bookmarks
4355
4179
  */
4356
4180
  getAll() {
4357
- return Array.from(this.bookmarks.values());
4181
+ return Array.from(this.state.bookmarks.values());
4358
4182
  }
4359
4183
  /**
4360
4184
  * Clear all bookmarks
4361
4185
  */
4362
4186
  clear() {
4363
- this.bookmarks.clear();
4364
- this.counter = 0;
4187
+ this.state.bookmarks.clear();
4365
4188
  }
4366
4189
  /**
4367
4190
  * Validate that all internal hyperlink references exist
@@ -4866,6 +4689,32 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
4866
4689
  borderColor: "000000",
4867
4690
  borderSize: 1
4868
4691
  });
4692
+ const warnedCellColors = /* @__PURE__ */ new Set();
4693
+ const warnCellColor = (code, message) => {
4694
+ if (warnedCellColors.has(message)) return;
4695
+ warnedCellColors.add(message);
4696
+ console.warn(`[json-to-docx] ${code}: ${message}`);
4697
+ };
4698
+ const resolveCellColor = (value, prop) => {
4699
+ if (value === void 0 || value === "auto") return value;
4700
+ if (value === "transparent") {
4701
+ if (prop === "backgroundColor") return value;
4702
+ warnCellColor(
4703
+ "TABLE_CELL_COLOR_INVALID",
4704
+ `"transparent" is not a valid table cell "color"; ignoring it and using the table style color. It only applies to "backgroundColor".`
4705
+ );
4706
+ return void 0;
4707
+ }
4708
+ if (/^[0-9A-Fa-f]{6}$/.test(value)) return value.toUpperCase();
4709
+ try {
4710
+ return resolveColor(value, theme);
4711
+ } catch {
4712
+ const allowed = prop === "backgroundColor" ? '"auto", or "transparent" for no shading' : 'or "auto"';
4713
+ throw new Error(
4714
+ `Invalid table cell ${prop}: "${value}". Must be a hex color with # prefix (e.g. "#000000"), a theme color name, ${allowed}.`
4715
+ );
4716
+ }
4717
+ };
4869
4718
  const normalizeBorderColor = (border) => {
4870
4719
  if (border === void 0) return void 0;
4871
4720
  if (typeof border === "string") {
@@ -5002,8 +4851,14 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
5002
4851
  tableDef?.padding
5003
4852
  );
5004
4853
  return {
5005
- color: cellDef?.color ?? columnDef?.color ?? tableDef?.color ?? defaults.color,
5006
- backgroundColor: cellDef?.backgroundColor ?? columnDef?.backgroundColor ?? tableDef?.backgroundColor ?? defaults.backgroundColor,
4854
+ color: resolveCellColor(
4855
+ cellDef?.color ?? columnDef?.color ?? tableDef?.color ?? defaults.color,
4856
+ "color"
4857
+ ),
4858
+ backgroundColor: resolveCellColor(
4859
+ cellDef?.backgroundColor ?? columnDef?.backgroundColor ?? tableDef?.backgroundColor ?? defaults.backgroundColor,
4860
+ "backgroundColor"
4861
+ ),
5007
4862
  horizontalAlignment: cellDef?.horizontalAlignment ?? columnDef?.horizontalAlignment ?? tableDef?.horizontalAlignment ?? defaults.horizontalAlignment,
5008
4863
  verticalAlignment: cellDef?.verticalAlignment ?? columnDef?.verticalAlignment ?? tableDef?.verticalAlignment ?? defaults.verticalAlignment,
5009
4864
  font: mergedFont,
@@ -5056,8 +4911,14 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
5056
4911
  tableDef?.padding
5057
4912
  );
5058
4913
  return {
5059
- color: headerDef?.color ?? headerTableDef?.color ?? columnDef?.color ?? tableDef?.color ?? defaults.color,
5060
- backgroundColor: headerDef?.backgroundColor ?? headerTableDef?.backgroundColor ?? columnDef?.backgroundColor ?? tableDef?.backgroundColor ?? defaults.backgroundColor,
4914
+ color: resolveCellColor(
4915
+ headerDef?.color ?? headerTableDef?.color ?? columnDef?.color ?? tableDef?.color ?? defaults.color,
4916
+ "color"
4917
+ ),
4918
+ backgroundColor: resolveCellColor(
4919
+ headerDef?.backgroundColor ?? headerTableDef?.backgroundColor ?? columnDef?.backgroundColor ?? tableDef?.backgroundColor ?? defaults.backgroundColor,
4920
+ "backgroundColor"
4921
+ ),
5061
4922
  horizontalAlignment: headerDef?.horizontalAlignment ?? headerTableDef?.horizontalAlignment ?? columnDef?.horizontalAlignment ?? tableDef?.horizontalAlignment ?? defaults.horizontalAlignment,
5062
4923
  verticalAlignment: headerDef?.verticalAlignment ?? headerTableDef?.verticalAlignment ?? columnDef?.verticalAlignment ?? tableDef?.verticalAlignment ?? defaults.verticalAlignment,
5063
4924
  font: mergedFont,
@@ -5279,7 +5140,8 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
5279
5140
  void 0
5280
5141
  );
5281
5142
  const headerRow = new TableRow({
5282
- tableHeader: tableConfig.repeatHeaderOnPageBreak,
5143
+ // Headers repeat across page breaks unless explicitly disabled
5144
+ tableHeader: tableConfig.repeatHeaderOnPageBreak ?? true,
5283
5145
  height: headerHeight !== void 0 ? { value: headerHeight * 20, rule: "atLeast" } : void 0,
5284
5146
  children: await Promise.all(
5285
5147
  columns.map(async (column, colIndex) => {
@@ -5649,8 +5511,173 @@ function renderHeadingComponent(component, theme, themeName) {
5649
5511
  return [header];
5650
5512
  }
5651
5513
 
5514
+ // src/utils/numberingConfig.ts
5515
+ import { AlignmentType as AlignmentType3, convertInchesToTwip, LevelFormat } from "docx";
5516
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
5517
+ var LEVEL_FORMAT_MAP = {
5518
+ decimal: LevelFormat.DECIMAL,
5519
+ upperRoman: LevelFormat.UPPER_ROMAN,
5520
+ lowerRoman: LevelFormat.LOWER_ROMAN,
5521
+ upperLetter: LevelFormat.UPPER_LETTER,
5522
+ lowerLetter: LevelFormat.LOWER_LETTER,
5523
+ bullet: LevelFormat.BULLET,
5524
+ ordinal: LevelFormat.ORDINAL,
5525
+ cardinalText: LevelFormat.CARDINAL_TEXT,
5526
+ ordinalText: LevelFormat.ORDINAL_TEXT,
5527
+ hex: LevelFormat.HEX,
5528
+ chicago: LevelFormat.CHICAGO,
5529
+ ideographDigital: LevelFormat.IDEOGRAPH__DIGITAL,
5530
+ japaneseCounting: LevelFormat.JAPANESE_COUNTING,
5531
+ aiueo: LevelFormat.AIUEO,
5532
+ iroha: LevelFormat.IROHA,
5533
+ decimalFullWidth: LevelFormat.DECIMAL_FULL_WIDTH,
5534
+ decimalHalfWidth: LevelFormat.DECIMAL_HALF_WIDTH,
5535
+ japaneseLegal: LevelFormat.JAPANESE_LEGAL,
5536
+ japaneseDigitalTenThousand: LevelFormat.JAPANESE_DIGITAL_TEN_THOUSAND,
5537
+ decimalEnclosedCircle: LevelFormat.DECIMAL_ENCLOSED_CIRCLE,
5538
+ decimalFullWidth2: LevelFormat.DECIMAL_FULL_WIDTH2,
5539
+ aiueoFullWidth: LevelFormat.AIUEO_FULL_WIDTH,
5540
+ irohaFullWidth: LevelFormat.IROHA_FULL_WIDTH,
5541
+ decimalZero: LevelFormat.DECIMAL_ZERO,
5542
+ ganada: LevelFormat.GANADA,
5543
+ chosung: LevelFormat.CHOSUNG,
5544
+ decimalEnclosedFullstop: LevelFormat.DECIMAL_ENCLOSED_FULLSTOP,
5545
+ decimalEnclosedParen: LevelFormat.DECIMAL_ENCLOSED_PARENTHESES,
5546
+ decimalEnclosedCircleChinese: LevelFormat.DECIMAL_ENCLOSED_CIRCLE_CHINESE,
5547
+ ideographEnclosedCircle: LevelFormat.IDEOGRAPH_ENCLOSED_CIRCLE,
5548
+ ideographTraditional: LevelFormat.IDEOGRAPH_TRADITIONAL,
5549
+ ideographZodiac: LevelFormat.IDEOGRAPH_ZODIAC,
5550
+ ideographZodiacTraditional: LevelFormat.IDEOGRAPH_ZODIAC_TRADITIONAL,
5551
+ taiwaneseCounting: LevelFormat.TAIWANESE_COUNTING,
5552
+ ideographLegalTraditional: LevelFormat.IDEOGRAPH_LEGAL_TRADITIONAL,
5553
+ taiwaneseCountingThousand: LevelFormat.TAIWANESE_COUNTING_THOUSAND,
5554
+ taiwaneseDigital: LevelFormat.TAIWANESE_DIGITAL,
5555
+ chineseCounting: LevelFormat.CHINESE_COUNTING,
5556
+ chineseLegalSimplified: LevelFormat.CHINESE_LEGAL_SIMPLIFIED,
5557
+ chineseCountingThousand: LevelFormat.CHINESE_COUNTING_THOUSAND,
5558
+ koreanDigital: LevelFormat.KOREAN_DIGITAL,
5559
+ koreanCounting: LevelFormat.KOREAN_COUNTING,
5560
+ koreanLegal: LevelFormat.KOREAN_LEGAL,
5561
+ koreanDigital2: LevelFormat.KOREAN_DIGITAL2,
5562
+ vietnameseCounting: LevelFormat.VIETNAMESE_COUNTING,
5563
+ russianLower: LevelFormat.RUSSIAN_LOWER,
5564
+ russianUpper: LevelFormat.RUSSIAN_UPPER,
5565
+ none: LevelFormat.NONE,
5566
+ numberInDash: LevelFormat.NUMBER_IN_DASH,
5567
+ hebrew1: LevelFormat.HEBREW1,
5568
+ hebrew2: LevelFormat.HEBREW2,
5569
+ arabicAlpha: LevelFormat.ARABIC_ALPHA,
5570
+ arabicAbjad: LevelFormat.ARABIC_ABJAD,
5571
+ hindiVowels: LevelFormat.HINDI_VOWELS,
5572
+ hindiConsonants: LevelFormat.HINDI_CONSONANTS,
5573
+ hindiNumbers: LevelFormat.HINDI_NUMBERS,
5574
+ hindiCounting: LevelFormat.HINDI_COUNTING,
5575
+ thaiLetters: LevelFormat.THAI_LETTERS,
5576
+ thaiNumbers: LevelFormat.THAI_NUMBERS,
5577
+ thaiCounting: LevelFormat.THAI_COUNTING
5578
+ };
5579
+ var ALIGNMENT_MAP = {
5580
+ start: AlignmentType3.START,
5581
+ end: AlignmentType3.END,
5582
+ left: AlignmentType3.LEFT,
5583
+ right: AlignmentType3.RIGHT,
5584
+ center: AlignmentType3.CENTER
5585
+ };
5586
+ function getLevelFormat(format2) {
5587
+ if (!format2) return LevelFormat.BULLET;
5588
+ return LEVEL_FORMAT_MAP[format2] || LevelFormat.BULLET;
5589
+ }
5590
+ function getAlignment2(alignment) {
5591
+ if (!alignment) return AlignmentType3.LEFT;
5592
+ return ALIGNMENT_MAP[alignment] || AlignmentType3.LEFT;
5593
+ }
5594
+ function createNumberingConfig(config) {
5595
+ const levels = [];
5596
+ for (const levelConfig of config.levels) {
5597
+ const format2 = getLevelFormat(levelConfig.format);
5598
+ const alignment = getAlignment2(levelConfig.alignment);
5599
+ const text = levelConfig.text || (format2 === LevelFormat.BULLET ? "\u2022" : `%${levelConfig.level + 1}.`);
5600
+ const baseIndent = levelConfig.indent?.left !== void 0 ? levelConfig.indent.left / 72 : 0.5 * (levelConfig.level + 1);
5601
+ const hangingIndent = levelConfig.indent?.hanging !== void 0 ? levelConfig.indent.hanging / 72 : 0.25;
5602
+ const level = {
5603
+ level: levelConfig.level,
5604
+ format: format2,
5605
+ text,
5606
+ alignment,
5607
+ style: {
5608
+ paragraph: {
5609
+ indent: {
5610
+ left: convertInchesToTwip(baseIndent),
5611
+ hanging: convertInchesToTwip(hangingIndent)
5612
+ }
5613
+ }
5614
+ },
5615
+ // Add start number if specified
5616
+ ...levelConfig.start !== void 0 && { start: levelConfig.start }
5617
+ };
5618
+ levels.push(level);
5619
+ }
5620
+ return {
5621
+ reference: config.reference,
5622
+ levels
5623
+ };
5624
+ }
5625
+ var NumberingRegistry = class {
5626
+ fallback = {
5627
+ configs: /* @__PURE__ */ new Map(),
5628
+ counter: 0
5629
+ };
5630
+ scopes = new AsyncLocalStorage4();
5631
+ get state() {
5632
+ return this.scopes.getStore() ?? this.fallback;
5633
+ }
5634
+ /** Run work with an isolated registry that follows its async call chain. */
5635
+ runScoped(callback) {
5636
+ return this.scopes.run({ configs: /* @__PURE__ */ new Map(), counter: 0 }, callback);
5637
+ }
5638
+ /**
5639
+ * Register a numbering configuration
5640
+ */
5641
+ register(config) {
5642
+ const reference = config.reference;
5643
+ this.state.configs.set(reference, config);
5644
+ return reference;
5645
+ }
5646
+ /**
5647
+ * Generate a unique reference ID
5648
+ */
5649
+ generateReference(prefix = "list") {
5650
+ return `${prefix}-${++this.state.counter}`;
5651
+ }
5652
+ /**
5653
+ * Get all registered configurations as an array suitable for INumberingOptions
5654
+ */
5655
+ getAll() {
5656
+ return Array.from(this.state.configs.values());
5657
+ }
5658
+ /**
5659
+ * Clear all configurations
5660
+ */
5661
+ clear() {
5662
+ this.state.configs.clear();
5663
+ this.state.counter = 0;
5664
+ }
5665
+ /**
5666
+ * Check if a reference exists
5667
+ */
5668
+ has(reference) {
5669
+ return this.state.configs.has(reference);
5670
+ }
5671
+ /**
5672
+ * Get a configuration by reference
5673
+ */
5674
+ get(reference) {
5675
+ return this.state.configs.get(reference);
5676
+ }
5677
+ };
5678
+ var globalNumberingRegistry = new NumberingRegistry();
5679
+
5652
5680
  // src/components/paragraph.ts
5653
- init_numberingConfig();
5654
5681
  function parseMarkdownList(text) {
5655
5682
  const lines = text.split("\n");
5656
5683
  const items = [];
@@ -5776,7 +5803,6 @@ function renderParagraphComponent(component, theme, themeName) {
5776
5803
  }
5777
5804
 
5778
5805
  // src/components/list.ts
5779
- init_numberingConfig();
5780
5806
  function createLevelsFromSimplifiedProps(props) {
5781
5807
  const levels = [];
5782
5808
  let format2;
@@ -6200,17 +6226,22 @@ async function renderTableComponent(component, theme, themeName) {
6200
6226
 
6201
6227
  // src/components/section.ts
6202
6228
  import { Paragraph as Paragraph4, BookmarkStart, BookmarkEnd } from "docx";
6203
- function generateSectionBookmarkId() {
6204
- const linkId = Math.floor(Math.random() * 1e6);
6229
+ function generateSectionBookmarkId(context) {
6230
+ const custom = context.custom ??= {};
6231
+ const state = custom.sectionBookmarks ??= {
6232
+ next: 1
6233
+ };
6234
+ const ordinal = state.next++;
6235
+ const linkId = 1e6 + ordinal;
6205
6236
  return {
6206
- id: `_Section_${linkId}_${Date.now()}`,
6237
+ id: `_NestedSection_${ordinal}`,
6207
6238
  linkId
6208
6239
  };
6209
6240
  }
6210
6241
  async function renderSectionComponent(component, theme, themeName, context) {
6211
6242
  if (!isSectionComponent(component)) return [];
6212
6243
  const elements = [];
6213
- const { id: sectionBookmarkId, linkId: bookmarkLinkId } = generateSectionBookmarkId();
6244
+ const { id: sectionBookmarkId, linkId: bookmarkLinkId } = generateSectionBookmarkId(context);
6214
6245
  elements.push(
6215
6246
  new Paragraph4({
6216
6247
  children: [new BookmarkStart(sectionBookmarkId, bookmarkLinkId)],
@@ -6441,6 +6472,11 @@ function renderTocComponent(component, theme, context) {
6441
6472
  pageNumbersStart = pageNumbersRange.from;
6442
6473
  pageNumbersEnd = pageNumbersRange.to;
6443
6474
  }
6475
+ if (componentProps.numberingStyle !== void 0) {
6476
+ console.warn(
6477
+ `TOC numberingStyle "${componentProps.numberingStyle}" is ignored: Word's table-of-contents field has no numbering switch. TOC entries inherit numbering from the heading styles they reference.`
6478
+ );
6479
+ }
6444
6480
  const includePageNumbers = componentProps.includePageNumbers !== false;
6445
6481
  const scope = componentProps.scope ?? "auto";
6446
6482
  const effectiveScope = scope === "auto" ? context?.section?.sectionBookmarkId ? "section" : "document" : scope;
@@ -6530,6 +6566,9 @@ function renderTocComponent(component, theme, context) {
6530
6566
  return paragraphs;
6531
6567
  }
6532
6568
 
6569
+ // src/components/highcharts.ts
6570
+ init_colorUtils();
6571
+
6533
6572
  // src/utils/environment.ts
6534
6573
  function isNodeEnvironment() {
6535
6574
  return typeof process !== "undefined" && process.versions != null && process.versions.node != null && typeof process.versions.node === "string";
@@ -6579,6 +6618,7 @@ async function postJsonToService(opts) {
6579
6618
  }
6580
6619
 
6581
6620
  // src/components/highcharts.ts
6621
+ import { DEFAULT_CHART_THEME_COLORS } from "@json-to-office/shared";
6582
6622
  var DEFAULT_EXPORT_SERVER_URL = "http://localhost:7801";
6583
6623
  async function generateChart(config, servicesConfig) {
6584
6624
  if (!isNodeEnvironment()) {
@@ -6619,14 +6659,24 @@ Cause: ${cause}`
6619
6659
  height
6620
6660
  };
6621
6661
  }
6662
+ function toChartColor(value, theme) {
6663
+ if (/^#?[0-9A-Fa-f]{6}$/.test(value)) {
6664
+ return value.startsWith("#") ? value : `#${value}`;
6665
+ }
6666
+ try {
6667
+ return `#${resolveColor(value, theme)}`;
6668
+ } catch {
6669
+ return void 0;
6670
+ }
6671
+ }
6622
6672
  function withThemeColors(config, theme) {
6623
6673
  const options = config.options;
6624
6674
  if (!options || options.colors || !theme?.colors) return config;
6625
- const palette = [
6626
- theme.colors.primary,
6627
- theme.colors.secondary,
6628
- theme.colors.accent
6629
- ].filter((c) => typeof c === "string" && c.length > 0).map((c) => c.startsWith("#") ? c : `#${c}`);
6675
+ const themeColors = theme.colors;
6676
+ const palette = DEFAULT_CHART_THEME_COLORS.map((token) => {
6677
+ const value = themeColors[token];
6678
+ return typeof value === "string" && value.length > 0 ? toChartColor(value, theme) : void 0;
6679
+ }).filter((c) => c !== void 0);
6630
6680
  if (palette.length === 0) return config;
6631
6681
  return {
6632
6682
  ...config,
@@ -6824,14 +6874,40 @@ function getAlignment3(alignment) {
6824
6874
  return AlignmentType5.LEFT;
6825
6875
  }
6826
6876
  }
6877
+ function coreProperties(metadata) {
6878
+ const { title, subtitle, description, author, company, version, tags } = metadata;
6879
+ const customProperties = [
6880
+ ...company ? [{ name: "Company", value: company }] : [],
6881
+ ...version ? [{ name: "Version", value: version }] : []
6882
+ ];
6883
+ return {
6884
+ ...title && { title },
6885
+ ...subtitle && { subject: subtitle },
6886
+ ...description && { description },
6887
+ // Word surfaces both names; author is the only person the document knows.
6888
+ ...author && { creator: author, lastModifiedBy: author },
6889
+ ...tags && tags.length > 0 && { keywords: tags.join(", ") },
6890
+ ...customProperties.length > 0 && { customProperties }
6891
+ };
6892
+ }
6827
6893
  async function renderDocument(structure, layout, options) {
6894
+ return runWithGenerationDate(
6895
+ structure.metadata.date,
6896
+ () => globalBookmarkRegistry.runScoped(
6897
+ () => globalRevisionIdRegistry.runScoped(
6898
+ () => globalNumberingRegistry.runScoped(
6899
+ () => renderDocumentScoped(structure, layout, options)
6900
+ )
6901
+ )
6902
+ )
6903
+ );
6904
+ }
6905
+ async function renderDocumentScoped(structure, layout, options) {
6828
6906
  if (options?.cache) {
6829
6907
  initializeComponentCache(options.cache);
6830
6908
  } else if (!options?.bypassCache) {
6831
6909
  initializeComponentCache();
6832
6910
  }
6833
- const { globalNumberingRegistry: globalNumberingRegistry2 } = await Promise.resolve().then(() => (init_numberingConfig(), numberingConfig_exports));
6834
- globalNumberingRegistry2.clear();
6835
6911
  const sections = [];
6836
6912
  const context = createRenderContext(
6837
6913
  structure,
@@ -6888,7 +6964,8 @@ async function renderDocument(structure, layout, options) {
6888
6964
  structure.themeName,
6889
6965
  context,
6890
6966
  sectionOrdinal,
6891
- closeBookmark
6967
+ closeBookmark,
6968
+ options?.bypassCache === true
6892
6969
  );
6893
6970
  if (layoutSection.isUserSection) {
6894
6971
  sectionBookmarkCounter++;
@@ -6897,10 +6974,11 @@ async function renderDocument(structure, layout, options) {
6897
6974
  sections.push(rendered);
6898
6975
  }
6899
6976
  }
6900
- const numberingConfigs = globalNumberingRegistry2.getAll();
6977
+ const numberingConfigs = globalNumberingRegistry.getAll();
6901
6978
  return new Document({
6902
6979
  styles: createWordStyles(structure.theme, structure.language),
6903
6980
  sections,
6981
+ ...coreProperties(structure.metadata),
6904
6982
  features: {
6905
6983
  updateFields: true,
6906
6984
  // Required for TOC fields to update correctly
@@ -7065,7 +7143,7 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
7065
7143
  }
7066
7144
  return elements;
7067
7145
  }
7068
- async function renderSection(section, theme, themeName, context, sectionOrdinal, closeBookmark) {
7146
+ async function renderSection(section, theme, themeName, context, sectionOrdinal, closeBookmark, bypassCache = false) {
7069
7147
  const elements = [];
7070
7148
  const isFirstLayoutOfUserSection = section.isUserSection;
7071
7149
  const sharedLinkId = section.belongsToUserSection && sectionOrdinal ? sectionOrdinal : void 0;
@@ -7103,8 +7181,7 @@ async function renderSection(section, theme, themeName, context, sectionOrdinal,
7103
7181
  theme,
7104
7182
  themeName,
7105
7183
  sectionContext,
7106
- false
7107
- // Don't bypass cache
7184
+ bypassCache
7108
7185
  );
7109
7186
  elements.push(...rendered);
7110
7187
  }
@@ -7273,6 +7350,75 @@ function normalizeDocument(document) {
7273
7350
  return [normalized];
7274
7351
  }
7275
7352
 
7353
+ // src/utils/packageDocument.ts
7354
+ import AdmZip2 from "adm-zip";
7355
+ import { Packer } from "docx";
7356
+
7357
+ // src/utils/fixFloatingImageIds.ts
7358
+ import AdmZip from "adm-zip";
7359
+ function fixFloatingImageIdsInBuffer(buffer) {
7360
+ const zip = new AdmZip(buffer);
7361
+ const documentEntry = zip.getEntry("word/document.xml");
7362
+ if (!documentEntry) {
7363
+ throw new Error("document.xml not found in DOCX");
7364
+ }
7365
+ let idCounter = 1;
7366
+ const documentXml = documentEntry.getData().toString("utf8").replace(/<wp:docPr\s+id="(\d+)"/g, () => {
7367
+ const newId = idCounter++;
7368
+ return `<wp:docPr id="${newId}"`;
7369
+ });
7370
+ zip.updateFile(documentEntry, Buffer.from(documentXml, "utf8"));
7371
+ return zip.toBuffer();
7372
+ }
7373
+
7374
+ // src/utils/packageDocument.ts
7375
+ var DEFAULT_GENERATION_DATE = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
7376
+ function resolveGenerationDate(options) {
7377
+ if (options?.generatedAt !== void 0) {
7378
+ const date = new Date(options.generatedAt);
7379
+ if (Number.isNaN(date.getTime())) {
7380
+ throw new RangeError("generatedAt must be a valid date");
7381
+ }
7382
+ if (date.getUTCFullYear() < 1980) {
7383
+ throw new RangeError(
7384
+ "generatedAt must be on or after 1980-01-01 for ZIP compatibility"
7385
+ );
7386
+ }
7387
+ return date;
7388
+ }
7389
+ return options?.deterministic === false ? /* @__PURE__ */ new Date() : new Date(DEFAULT_GENERATION_DATE);
7390
+ }
7391
+ function toDosTime(date) {
7392
+ const dosDate = (date.getUTCFullYear() - 1980 & 127) << 9 | date.getUTCMonth() + 1 << 5 | date.getUTCDate();
7393
+ const dosTime = date.getUTCHours() << 11 | date.getUTCMinutes() << 5 | date.getUTCSeconds() >> 1;
7394
+ return (dosDate << 16 | dosTime) >>> 0;
7395
+ }
7396
+ function canonicalizeDocxBuffer(buffer, generatedAt = DEFAULT_GENERATION_DATE) {
7397
+ const zip = new AdmZip2(buffer);
7398
+ const isoTimestamp = generatedAt.toISOString();
7399
+ const coreProperties2 = zip.getEntry("docProps/core.xml");
7400
+ if (coreProperties2) {
7401
+ const normalized = coreProperties2.getData().toString("utf8").replace(
7402
+ /(<dcterms:(?:created|modified)\b[^>]*>)[^<]*(<\/dcterms:(?:created|modified)>)/g,
7403
+ `$1${isoTimestamp}$2`
7404
+ );
7405
+ zip.updateFile(coreProperties2, Buffer.from(normalized, "utf8"));
7406
+ }
7407
+ const zipTimestamp = toDosTime(generatedAt);
7408
+ for (const entry of zip.getEntries()) {
7409
+ entry.header.timeval = zipTimestamp;
7410
+ }
7411
+ return zip.toBuffer();
7412
+ }
7413
+ async function packageDocument(document, options) {
7414
+ const packed = await Packer.toBuffer(document);
7415
+ const fixed = fixFloatingImageIdsInBuffer(packed);
7416
+ if (options?.deterministic === false) {
7417
+ return fixed;
7418
+ }
7419
+ return canonicalizeDocxBuffer(fixed, resolveGenerationDate(options));
7420
+ }
7421
+
7276
7422
  // src/plugin/createDocumentGenerator.ts
7277
7423
  function createBuilderImpl(state) {
7278
7424
  const componentMap = new Map(state.components.map((c) => [c.name, c]));
@@ -7428,7 +7574,10 @@ function createBuilderImpl(state) {
7428
7574
  debug: state.debug,
7429
7575
  enableCache: state.enableCache,
7430
7576
  services: state.services,
7431
- fonts: state.fonts
7577
+ fonts: state.fonts,
7578
+ validation: state.validation,
7579
+ deterministic: state.deterministic,
7580
+ generatedAt: state.generatedAt
7432
7581
  };
7433
7582
  return createBuilderImpl(
7434
7583
  newState
@@ -7452,7 +7601,8 @@ function createBuilderImpl(state) {
7452
7601
  async function generate(document, options) {
7453
7602
  try {
7454
7603
  const preserveSet = resolvePreserveSet(options);
7455
- const internalDocument = document;
7604
+ const rootIn = document;
7605
+ const internalDocument = rootIn.props === void 0 ? { ...rootIn, props: {} } : rootIn;
7456
7606
  const vOpts = {
7457
7607
  ...state.validation,
7458
7608
  ...options?.validation
@@ -7520,10 +7670,20 @@ function createBuilderImpl(state) {
7520
7670
  };
7521
7671
  const [modedDoc] = normalizeDocument(processedDocument);
7522
7672
  await resolveDocumentFonts(modedDoc, modedTheme, state.fonts, warnings);
7523
- const structure = await processDocument(modedDoc, modedTheme, themeName);
7673
+ const packageOptions = {
7674
+ deterministic: options?.deterministic ?? state.deterministic,
7675
+ generatedAt: options?.generatedAt ?? state.generatedAt
7676
+ };
7677
+ const structure = await processDocument(
7678
+ modedDoc,
7679
+ modedTheme,
7680
+ themeName,
7681
+ resolveGenerationDate(packageOptions)
7682
+ );
7524
7683
  const layout = applyLayout(structure.sections, modedTheme, themeName);
7525
7684
  const generatedDocument = await renderDocument(structure, layout, {
7526
- services: state.services
7685
+ services: state.services,
7686
+ bypassCache: !state.enableCache
7527
7687
  });
7528
7688
  const preservedDefinition = preserveSet ? {
7529
7689
  ...mode.doc,
@@ -7549,7 +7709,10 @@ function createBuilderImpl(state) {
7549
7709
  standardDefinition,
7550
7710
  preservedDefinition
7551
7711
  } = await generate(document, options);
7552
- const buffer = await Packer.toBuffer(doc);
7712
+ const buffer = await packageDocument(doc, {
7713
+ deterministic: options?.deterministic ?? state.deterministic,
7714
+ generatedAt: options?.generatedAt ?? state.generatedAt
7715
+ });
7553
7716
  return { buffer, warnings, standardDefinition, preservedDefinition };
7554
7717
  }
7555
7718
  async function generateFile(document, outputPath, options) {
@@ -7648,7 +7811,9 @@ function createDocumentGenerator(options) {
7648
7811
  enableCache: options.enableCache ?? false,
7649
7812
  services: options.services,
7650
7813
  fonts: options.fonts,
7651
- validation: options.validation
7814
+ validation: options.validation,
7815
+ deterministic: options.deterministic ?? true,
7816
+ generatedAt: options.generatedAt
7652
7817
  };
7653
7818
  return createBuilderImpl(initialState);
7654
7819
  }