@json-to-office/core-docx 0.20.0 → 0.21.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 (35) hide show
  1. package/dist/components/section.d.ts.map +1 -1
  2. package/dist/core/cached-render.d.ts.map +1 -1
  3. package/dist/core/content.d.ts.map +1 -1
  4. package/dist/core/generator.d.ts +6 -2
  5. package/dist/core/generator.d.ts.map +1 -1
  6. package/dist/core/render.d.ts +8 -6
  7. package/dist/core/render.d.ts.map +1 -1
  8. package/dist/core/structure.d.ts +2 -2
  9. package/dist/core/structure.d.ts.map +1 -1
  10. package/dist/index.js +399 -344
  11. package/dist/index.js.map +1 -1
  12. package/dist/plugin/createDocumentGenerator.d.ts +4 -0
  13. package/dist/plugin/createDocumentGenerator.d.ts.map +1 -1
  14. package/dist/plugin/example/index.js +379 -286
  15. package/dist/plugin/example/index.js.map +1 -1
  16. package/dist/plugin/types.d.ts +4 -0
  17. package/dist/plugin/types.d.ts.map +1 -1
  18. package/dist/tsconfig.tsbuildinfo +1 -1
  19. package/dist/utils/bookmarkRegistry.d.ts +5 -2
  20. package/dist/utils/bookmarkRegistry.d.ts.map +1 -1
  21. package/dist/utils/fixFloatingImageIds.d.ts +3 -0
  22. package/dist/utils/fixFloatingImageIds.d.ts.map +1 -1
  23. package/dist/utils/generationContext.d.ts +5 -0
  24. package/dist/utils/generationContext.d.ts.map +1 -0
  25. package/dist/utils/numberingConfig.d.ts +5 -2
  26. package/dist/utils/numberingConfig.d.ts.map +1 -1
  27. package/dist/utils/packageDocument.d.ts +20 -0
  28. package/dist/utils/packageDocument.d.ts.map +1 -0
  29. package/dist/utils/placeholderProcessor.d.ts +5 -5
  30. package/dist/utils/placeholderProcessor.d.ts.map +1 -1
  31. package/dist/utils/revisionUtils.d.ts +5 -5
  32. package/dist/utils/revisionUtils.d.ts.map +1 -1
  33. package/dist/utils/textParser.d.ts +3 -3
  34. package/dist/utils/textParser.d.ts.map +1 -1
  35. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1692,253 +1692,7 @@ var init_docxImagePositioning = __esm({
1692
1692
  }
1693
1693
  });
1694
1694
 
1695
- // src/utils/numberingConfig.ts
1696
- var numberingConfig_exports = {};
1697
- __export(numberingConfig_exports, {
1698
- NumberingRegistry: () => NumberingRegistry,
1699
- createBulletListConfig: () => createBulletListConfig,
1700
- createNumberedListConfig: () => createNumberedListConfig,
1701
- createNumberingConfig: () => createNumberingConfig,
1702
- globalNumberingRegistry: () => globalNumberingRegistry
1703
- });
1704
- import { AlignmentType as AlignmentType3, convertInchesToTwip, LevelFormat } from "docx";
1705
- function getLevelFormat(format2) {
1706
- if (!format2) return LevelFormat.BULLET;
1707
- return LEVEL_FORMAT_MAP[format2] || LevelFormat.BULLET;
1708
- }
1709
- function getAlignment2(alignment) {
1710
- if (!alignment) return AlignmentType3.LEFT;
1711
- return ALIGNMENT_MAP[alignment] || AlignmentType3.LEFT;
1712
- }
1713
- function createDefaultLevel(level, format2 = LevelFormat.BULLET, text) {
1714
- const baseIndent = 0.5 * (level + 1);
1715
- const hangingIndent = 0.25;
1716
- return {
1717
- level,
1718
- format: format2,
1719
- text: text || (format2 === LevelFormat.BULLET ? "\u2022" : "%1."),
1720
- alignment: AlignmentType3.LEFT,
1721
- style: {
1722
- paragraph: {
1723
- indent: {
1724
- left: convertInchesToTwip(baseIndent),
1725
- hanging: convertInchesToTwip(hangingIndent)
1726
- }
1727
- }
1728
- }
1729
- };
1730
- }
1731
- function createNumberingConfig(config) {
1732
- const levels = [];
1733
- for (const levelConfig of config.levels) {
1734
- const format2 = getLevelFormat(levelConfig.format);
1735
- const alignment = getAlignment2(levelConfig.alignment);
1736
- const text = levelConfig.text || (format2 === LevelFormat.BULLET ? "\u2022" : `%${levelConfig.level + 1}.`);
1737
- const baseIndent = levelConfig.indent?.left !== void 0 ? levelConfig.indent.left / 72 : 0.5 * (levelConfig.level + 1);
1738
- const hangingIndent = levelConfig.indent?.hanging !== void 0 ? levelConfig.indent.hanging / 72 : 0.25;
1739
- const level = {
1740
- level: levelConfig.level,
1741
- format: format2,
1742
- text,
1743
- alignment,
1744
- style: {
1745
- paragraph: {
1746
- indent: {
1747
- left: convertInchesToTwip(baseIndent),
1748
- hanging: convertInchesToTwip(hangingIndent)
1749
- }
1750
- }
1751
- },
1752
- // Add start number if specified
1753
- ...levelConfig.start !== void 0 && { start: levelConfig.start }
1754
- };
1755
- levels.push(level);
1756
- }
1757
- return {
1758
- reference: config.reference,
1759
- levels
1760
- };
1761
- }
1762
- function createBulletListConfig(reference, bullet = "\u2022") {
1763
- return {
1764
- reference,
1765
- levels: [
1766
- createDefaultLevel(0, LevelFormat.BULLET, bullet),
1767
- createDefaultLevel(1, LevelFormat.BULLET, "\u25E6"),
1768
- createDefaultLevel(2, LevelFormat.BULLET, "\u25AA")
1769
- ]
1770
- };
1771
- }
1772
- function createNumberedListConfig(reference, start = 1) {
1773
- return {
1774
- reference,
1775
- levels: [
1776
- { ...createDefaultLevel(0, LevelFormat.DECIMAL, "%1."), start },
1777
- createDefaultLevel(1, LevelFormat.LOWER_LETTER, "%2."),
1778
- createDefaultLevel(2, LevelFormat.LOWER_ROMAN, "%3.")
1779
- ]
1780
- };
1781
- }
1782
- var LEVEL_FORMAT_MAP, ALIGNMENT_MAP, NumberingRegistry, globalNumberingRegistry;
1783
- var init_numberingConfig = __esm({
1784
- "src/utils/numberingConfig.ts"() {
1785
- "use strict";
1786
- LEVEL_FORMAT_MAP = {
1787
- decimal: LevelFormat.DECIMAL,
1788
- upperRoman: LevelFormat.UPPER_ROMAN,
1789
- lowerRoman: LevelFormat.LOWER_ROMAN,
1790
- upperLetter: LevelFormat.UPPER_LETTER,
1791
- lowerLetter: LevelFormat.LOWER_LETTER,
1792
- bullet: LevelFormat.BULLET,
1793
- ordinal: LevelFormat.ORDINAL,
1794
- cardinalText: LevelFormat.CARDINAL_TEXT,
1795
- ordinalText: LevelFormat.ORDINAL_TEXT,
1796
- hex: LevelFormat.HEX,
1797
- chicago: LevelFormat.CHICAGO,
1798
- ideographDigital: LevelFormat.IDEOGRAPH__DIGITAL,
1799
- japaneseCounting: LevelFormat.JAPANESE_COUNTING,
1800
- aiueo: LevelFormat.AIUEO,
1801
- iroha: LevelFormat.IROHA,
1802
- decimalFullWidth: LevelFormat.DECIMAL_FULL_WIDTH,
1803
- decimalHalfWidth: LevelFormat.DECIMAL_HALF_WIDTH,
1804
- japaneseLegal: LevelFormat.JAPANESE_LEGAL,
1805
- japaneseDigitalTenThousand: LevelFormat.JAPANESE_DIGITAL_TEN_THOUSAND,
1806
- decimalEnclosedCircle: LevelFormat.DECIMAL_ENCLOSED_CIRCLE,
1807
- decimalFullWidth2: LevelFormat.DECIMAL_FULL_WIDTH2,
1808
- aiueoFullWidth: LevelFormat.AIUEO_FULL_WIDTH,
1809
- irohaFullWidth: LevelFormat.IROHA_FULL_WIDTH,
1810
- decimalZero: LevelFormat.DECIMAL_ZERO,
1811
- ganada: LevelFormat.GANADA,
1812
- chosung: LevelFormat.CHOSUNG,
1813
- decimalEnclosedFullstop: LevelFormat.DECIMAL_ENCLOSED_FULLSTOP,
1814
- decimalEnclosedParen: LevelFormat.DECIMAL_ENCLOSED_PARENTHESES,
1815
- decimalEnclosedCircleChinese: LevelFormat.DECIMAL_ENCLOSED_CIRCLE_CHINESE,
1816
- ideographEnclosedCircle: LevelFormat.IDEOGRAPH_ENCLOSED_CIRCLE,
1817
- ideographTraditional: LevelFormat.IDEOGRAPH_TRADITIONAL,
1818
- ideographZodiac: LevelFormat.IDEOGRAPH_ZODIAC,
1819
- ideographZodiacTraditional: LevelFormat.IDEOGRAPH_ZODIAC_TRADITIONAL,
1820
- taiwaneseCounting: LevelFormat.TAIWANESE_COUNTING,
1821
- ideographLegalTraditional: LevelFormat.IDEOGRAPH_LEGAL_TRADITIONAL,
1822
- taiwaneseCountingThousand: LevelFormat.TAIWANESE_COUNTING_THOUSAND,
1823
- taiwaneseDigital: LevelFormat.TAIWANESE_DIGITAL,
1824
- chineseCounting: LevelFormat.CHINESE_COUNTING,
1825
- chineseLegalSimplified: LevelFormat.CHINESE_LEGAL_SIMPLIFIED,
1826
- chineseCountingThousand: LevelFormat.CHINESE_COUNTING_THOUSAND,
1827
- koreanDigital: LevelFormat.KOREAN_DIGITAL,
1828
- koreanCounting: LevelFormat.KOREAN_COUNTING,
1829
- koreanLegal: LevelFormat.KOREAN_LEGAL,
1830
- koreanDigital2: LevelFormat.KOREAN_DIGITAL2,
1831
- vietnameseCounting: LevelFormat.VIETNAMESE_COUNTING,
1832
- russianLower: LevelFormat.RUSSIAN_LOWER,
1833
- russianUpper: LevelFormat.RUSSIAN_UPPER,
1834
- none: LevelFormat.NONE,
1835
- numberInDash: LevelFormat.NUMBER_IN_DASH,
1836
- hebrew1: LevelFormat.HEBREW1,
1837
- hebrew2: LevelFormat.HEBREW2,
1838
- arabicAlpha: LevelFormat.ARABIC_ALPHA,
1839
- arabicAbjad: LevelFormat.ARABIC_ABJAD,
1840
- hindiVowels: LevelFormat.HINDI_VOWELS,
1841
- hindiConsonants: LevelFormat.HINDI_CONSONANTS,
1842
- hindiNumbers: LevelFormat.HINDI_NUMBERS,
1843
- hindiCounting: LevelFormat.HINDI_COUNTING,
1844
- thaiLetters: LevelFormat.THAI_LETTERS,
1845
- thaiNumbers: LevelFormat.THAI_NUMBERS,
1846
- thaiCounting: LevelFormat.THAI_COUNTING
1847
- };
1848
- ALIGNMENT_MAP = {
1849
- start: AlignmentType3.START,
1850
- end: AlignmentType3.END,
1851
- left: AlignmentType3.LEFT,
1852
- right: AlignmentType3.RIGHT,
1853
- center: AlignmentType3.CENTER
1854
- };
1855
- NumberingRegistry = class {
1856
- configs = /* @__PURE__ */ new Map();
1857
- counter = 0;
1858
- /**
1859
- * Register a numbering configuration
1860
- */
1861
- register(config) {
1862
- const reference = config.reference;
1863
- this.configs.set(reference, config);
1864
- return reference;
1865
- }
1866
- /**
1867
- * Generate a unique reference ID
1868
- */
1869
- generateReference(prefix = "list") {
1870
- return `${prefix}-${++this.counter}`;
1871
- }
1872
- /**
1873
- * Get all registered configurations as an array suitable for INumberingOptions
1874
- */
1875
- getAll() {
1876
- return Array.from(this.configs.values());
1877
- }
1878
- /**
1879
- * Clear all configurations
1880
- */
1881
- clear() {
1882
- this.configs.clear();
1883
- this.counter = 0;
1884
- }
1885
- /**
1886
- * Check if a reference exists
1887
- */
1888
- has(reference) {
1889
- return this.configs.has(reference);
1890
- }
1891
- /**
1892
- * Get a configuration by reference
1893
- */
1894
- get(reference) {
1895
- return this.configs.get(reference);
1896
- }
1897
- };
1898
- globalNumberingRegistry = new NumberingRegistry();
1899
- }
1900
- });
1901
-
1902
- // src/utils/fixFloatingImageIds.ts
1903
- var fixFloatingImageIds_exports = {};
1904
- __export(fixFloatingImageIds_exports, {
1905
- fixFloatingImageIds: () => fixFloatingImageIds
1906
- });
1907
- import AdmZip from "adm-zip";
1908
- async function fixFloatingImageIds(docxPath) {
1909
- try {
1910
- const zip = new AdmZip(docxPath);
1911
- const documentEntry = zip.getEntry("word/document.xml");
1912
- if (!documentEntry) {
1913
- throw new Error("document.xml not found in DOCX");
1914
- }
1915
- let documentXml = documentEntry.getData().toString("utf8");
1916
- let idCounter = 1;
1917
- documentXml = documentXml.replace(
1918
- /<wp:docPr\s+id="(\d+)"/g,
1919
- (_match) => {
1920
- const newId = idCounter++;
1921
- return `<wp:docPr id="${newId}"`;
1922
- }
1923
- );
1924
- zip.updateFile("word/document.xml", Buffer.from(documentXml, "utf8"));
1925
- zip.writeZip(docxPath);
1926
- console.log(
1927
- `Fixed ${idCounter - 1} duplicate floating image docPr IDs in ${docxPath}`
1928
- );
1929
- } catch (error) {
1930
- console.error("Failed to fix floating image issues:", error);
1931
- throw error;
1932
- }
1933
- }
1934
- var init_fixFloatingImageIds = __esm({
1935
- "src/utils/fixFloatingImageIds.ts"() {
1936
- "use strict";
1937
- }
1938
- });
1939
-
1940
1695
  // src/core/generator.ts
1941
- import { Packer } from "docx";
1942
1696
  import { writeFileSync } from "fs";
1943
1697
 
1944
1698
  // src/types/index.ts
@@ -2111,8 +1865,8 @@ function resolveComponentTree(components, theme) {
2111
1865
  }
2112
1866
 
2113
1867
  // src/core/structure.ts
2114
- async function processDocument(document, theme, themeName) {
2115
- const metadata = createDocumentMetadata(document.props);
1868
+ async function processDocument(document, theme, themeName, generationDate) {
1869
+ const metadata = createDocumentMetadata(document.props, generationDate);
2116
1870
  const docDefaults = document.props.componentDefaults;
2117
1871
  const mergedComponentDefaults = docDefaults ? mergeWithDefaults2(docDefaults, theme.componentDefaults || {}) : void 0;
2118
1872
  const docNoProofWords = document.props.noProofWords;
@@ -2150,13 +1904,13 @@ async function processDocument(document, theme, themeName) {
2150
1904
  language: document.props.language
2151
1905
  };
2152
1906
  }
2153
- function createDocumentMetadata(props) {
1907
+ function createDocumentMetadata(props, generationDate = /* @__PURE__ */ new Date()) {
2154
1908
  return {
2155
1909
  title: props.metadata?.title,
2156
1910
  subtitle: props.metadata?.subtitle,
2157
1911
  author: props.metadata?.author,
2158
1912
  company: props.metadata?.company,
2159
- date: props.metadata?.date ? new Date(props.metadata.date) : /* @__PURE__ */ new Date()
1913
+ date: props.metadata?.date ? new Date(props.metadata.date) : generationDate
2160
1914
  };
2161
1915
  }
2162
1916
  async function extractSections(components, context) {
@@ -3819,7 +3573,39 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
3819
3573
  return runs;
3820
3574
  }
3821
3575
 
3576
+ // src/utils/generationContext.ts
3577
+ import { AsyncLocalStorage } from "async_hooks";
3578
+ var generationDateStorage = new AsyncLocalStorage();
3579
+ function runWithGenerationDate(date, callback) {
3580
+ return generationDateStorage.run(date, callback);
3581
+ }
3582
+ function getGenerationDate() {
3583
+ return generationDateStorage.getStore() ?? /* @__PURE__ */ new Date();
3584
+ }
3585
+
3822
3586
  // src/utils/placeholderProcessor.ts
3587
+ function styledPlaceholderText(text, context) {
3588
+ return new TextRun2({
3589
+ text,
3590
+ font: context?.style?.font,
3591
+ size: context?.style?.size,
3592
+ color: context?.style?.color,
3593
+ bold: context?.style?.bold,
3594
+ italics: context?.style?.italics,
3595
+ underline: context?.style?.underline,
3596
+ language: context?.style?.language,
3597
+ noProof: context?.style?.noProof
3598
+ });
3599
+ }
3600
+ function placeholderDate(context) {
3601
+ return context?.date ?? getGenerationDate();
3602
+ }
3603
+ function isoDate(date) {
3604
+ return date.toISOString().slice(0, 10);
3605
+ }
3606
+ function isoDateTime(date) {
3607
+ return date.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z");
3608
+ }
3823
3609
  var PlaceholderRegistry = class {
3824
3610
  static handlers = /* @__PURE__ */ new Map();
3825
3611
  /**
@@ -3875,8 +3661,6 @@ function processTextWithPlaceholders(text, baseStyle = {}, context = {}, noProof
3875
3661
  const placeholderResult = handler({ ...context, style: baseStyle });
3876
3662
  if (Array.isArray(placeholderResult)) {
3877
3663
  result.push(...placeholderResult);
3878
- } else if (placeholderResult instanceof TextRun2) {
3879
- result.push(placeholderResult);
3880
3664
  } else if (typeof placeholderResult === "string") {
3881
3665
  result.push(
3882
3666
  ...createTextRunsWithNewlines2(
@@ -3885,6 +3669,8 @@ function processTextWithPlaceholders(text, baseStyle = {}, context = {}, noProof
3885
3669
  noProofWords
3886
3670
  )
3887
3671
  );
3672
+ } else {
3673
+ result.push(placeholderResult);
3888
3674
  }
3889
3675
  } else {
3890
3676
  result.push(
@@ -3999,59 +3785,51 @@ function initializeBuiltinPlaceholders() {
3999
3785
  underline: context?.style?.underline
4000
3786
  });
4001
3787
  });
4002
- PlaceholderRegistry.register("DATE", (context) => {
4003
- const today = /* @__PURE__ */ new Date();
4004
- const dateString = today.toLocaleDateString();
4005
- return new TextRun2({
4006
- text: dateString,
4007
- font: context?.style?.font,
4008
- size: context?.style?.size,
4009
- color: context?.style?.color,
4010
- bold: context?.style?.bold,
4011
- italics: context?.style?.italics,
4012
- underline: context?.style?.underline
4013
- });
4014
- });
4015
- PlaceholderRegistry.register("DATETIME", (context) => {
4016
- const now = /* @__PURE__ */ new Date();
4017
- const dateTimeString = now.toLocaleString();
4018
- return new TextRun2({
4019
- text: dateTimeString,
4020
- font: context?.style?.font,
4021
- size: context?.style?.size,
4022
- color: context?.style?.color,
4023
- bold: context?.style?.bold,
4024
- italics: context?.style?.italics,
4025
- underline: context?.style?.underline
4026
- });
4027
- });
4028
- PlaceholderRegistry.register("YEAR", (context) => {
4029
- const year = (/* @__PURE__ */ new Date()).getFullYear().toString();
4030
- return new TextRun2({
4031
- text: year,
4032
- font: context?.style?.font,
4033
- size: context?.style?.size,
4034
- color: context?.style?.color,
4035
- bold: context?.style?.bold,
4036
- italics: context?.style?.italics,
4037
- underline: context?.style?.underline
4038
- });
4039
- });
3788
+ PlaceholderRegistry.register(
3789
+ "DATE",
3790
+ (context) => styledPlaceholderText(isoDate(placeholderDate(context)), context)
3791
+ );
3792
+ PlaceholderRegistry.register(
3793
+ "DATETIME",
3794
+ (context) => styledPlaceholderText(isoDateTime(placeholderDate(context)), context)
3795
+ );
3796
+ PlaceholderRegistry.register(
3797
+ "YEAR",
3798
+ (context) => styledPlaceholderText(
3799
+ String(placeholderDate(context).getUTCFullYear()),
3800
+ context
3801
+ )
3802
+ );
4040
3803
  }
4041
3804
  initializeBuiltinPlaceholders();
4042
3805
 
4043
3806
  // src/utils/revisionUtils.ts
3807
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
4044
3808
  var DEFAULT_REVISION_AUTHOR = "json-to-office";
4045
3809
  var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
4046
3810
  var RevisionIdRegistry = class {
4047
- counter = 0;
3811
+ fallbackCounter = 0;
3812
+ scopes = new AsyncLocalStorage2();
3813
+ runScoped(callback) {
3814
+ return this.scopes.run({ counter: 0 }, callback);
3815
+ }
4048
3816
  next() {
4049
- this.counter += 1;
4050
- return this.counter;
3817
+ const state = this.scopes.getStore();
3818
+ if (state) {
3819
+ state.counter += 1;
3820
+ return state.counter;
3821
+ }
3822
+ this.fallbackCounter += 1;
3823
+ return this.fallbackCounter;
4051
3824
  }
4052
3825
  /** Test-only: deterministic ids for snapshot assertions. */
4053
3826
  clear() {
4054
- this.counter = 0;
3827
+ const state = this.scopes.getStore();
3828
+ if (state) {
3829
+ state.counter = 0;
3830
+ } else {
3831
+ this.fallbackCounter = 0;
3832
+ }
4055
3833
  }
4056
3834
  };
4057
3835
  var globalRevisionIdRegistry = new RevisionIdRegistry();
@@ -4179,7 +3957,10 @@ async function clearComponentCache() {
4179
3957
  }
4180
3958
  }
4181
3959
  async function renderComponentWithCache(component, theme, themeName, context, bypassCache = false) {
4182
- const forceBypassForType = component.name === "toc" || component.name === "section" || component.name === "visual" || componentHasRevision(component);
3960
+ const forceBypassForType = component.name === "toc" || component.name === "section" || component.name === "visual" || component.name === "heading" || // Both explicit lists and markdown-list paragraphs register numbering in
3961
+ // the current document scope. Cached paragraphs can otherwise reference
3962
+ // definitions that only existed in a previous render.
3963
+ component.name === "list" || component.name === "paragraph" || "id" in component || componentHasRevision(component);
4183
3964
  if (!componentCache) {
4184
3965
  initializeComponentCache();
4185
3966
  }
@@ -4189,8 +3970,9 @@ async function renderComponentWithCache(component, theme, themeName, context, by
4189
3970
  const componentProps = JSON.stringify(component.props || {});
4190
3971
  const themeHash = createThemeHash(theme);
4191
3972
  const contextKey = context?.section ? `${context.section.currentLayout}:${context.section.columnCount}` : "no-section";
3973
+ const generationDateKey = getGenerationDate().toISOString();
4192
3974
  const childrenKey = "children" in component && component.children ? `:children:${JSON.stringify(component.children)}` : "";
4193
- const cacheKey = `component:${component.name}:${themeHash}:${contextKey}:${componentProps}${childrenKey}`;
3975
+ const cacheKey = `component:${component.name}:${themeHash}:${contextKey}:${generationDateKey}:${componentProps}${childrenKey}`;
4194
3976
  const cached = await componentCache.get(cacheKey);
4195
3977
  if (cached) {
4196
3978
  return cached.result;
@@ -4261,19 +4043,27 @@ init_styles();
4261
4043
  init_defaults();
4262
4044
 
4263
4045
  // src/utils/bookmarkRegistry.ts
4046
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
4264
4047
  var BookmarkRegistry = class {
4265
- bookmarks = /* @__PURE__ */ new Map();
4266
- counter = 0;
4048
+ fallback = { bookmarks: /* @__PURE__ */ new Map() };
4049
+ scopes = new AsyncLocalStorage3();
4050
+ get state() {
4051
+ return this.scopes.getStore() ?? this.fallback;
4052
+ }
4053
+ /** Run work with an isolated registry that follows its async call chain. */
4054
+ runScoped(callback) {
4055
+ return this.scopes.run({ bookmarks: /* @__PURE__ */ new Map() }, callback);
4056
+ }
4267
4057
  /**
4268
4058
  * Register a bookmark
4269
4059
  */
4270
4060
  register(id, title, type) {
4271
- if (this.bookmarks.has(id)) {
4061
+ if (this.state.bookmarks.has(id)) {
4272
4062
  console.warn(
4273
4063
  `Duplicate bookmark ID: ${id}. Using the latest registration.`
4274
4064
  );
4275
4065
  }
4276
- this.bookmarks.set(id, { id, title, type });
4066
+ this.state.bookmarks.set(id, { id, title, type });
4277
4067
  }
4278
4068
  /**
4279
4069
  * Generate a unique bookmark ID from text
@@ -4283,7 +4073,7 @@ var BookmarkRegistry = class {
4283
4073
  const baseId = text.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").substring(0, 40);
4284
4074
  let id = baseId;
4285
4075
  let attempt = 0;
4286
- while (this.bookmarks.has(id) && attempt < 100) {
4076
+ while (this.state.bookmarks.has(id) && attempt < 100) {
4287
4077
  id = `${baseId}-${++attempt}`;
4288
4078
  }
4289
4079
  return id;
@@ -4292,26 +4082,25 @@ var BookmarkRegistry = class {
4292
4082
  * Check if a bookmark exists
4293
4083
  */
4294
4084
  exists(id) {
4295
- return this.bookmarks.has(id);
4085
+ return this.state.bookmarks.has(id);
4296
4086
  }
4297
4087
  /**
4298
4088
  * Get bookmark info by ID
4299
4089
  */
4300
4090
  get(id) {
4301
- return this.bookmarks.get(id);
4091
+ return this.state.bookmarks.get(id);
4302
4092
  }
4303
4093
  /**
4304
4094
  * Get all registered bookmarks
4305
4095
  */
4306
4096
  getAll() {
4307
- return Array.from(this.bookmarks.values());
4097
+ return Array.from(this.state.bookmarks.values());
4308
4098
  }
4309
4099
  /**
4310
4100
  * Clear all bookmarks
4311
4101
  */
4312
4102
  clear() {
4313
- this.bookmarks.clear();
4314
- this.counter = 0;
4103
+ this.state.bookmarks.clear();
4315
4104
  }
4316
4105
  /**
4317
4106
  * Validate that all internal hyperlink references exist
@@ -5599,8 +5388,173 @@ function renderHeadingComponent(component, theme, themeName) {
5599
5388
  return [header];
5600
5389
  }
5601
5390
 
5391
+ // src/utils/numberingConfig.ts
5392
+ import { AlignmentType as AlignmentType3, convertInchesToTwip, LevelFormat } from "docx";
5393
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
5394
+ var LEVEL_FORMAT_MAP = {
5395
+ decimal: LevelFormat.DECIMAL,
5396
+ upperRoman: LevelFormat.UPPER_ROMAN,
5397
+ lowerRoman: LevelFormat.LOWER_ROMAN,
5398
+ upperLetter: LevelFormat.UPPER_LETTER,
5399
+ lowerLetter: LevelFormat.LOWER_LETTER,
5400
+ bullet: LevelFormat.BULLET,
5401
+ ordinal: LevelFormat.ORDINAL,
5402
+ cardinalText: LevelFormat.CARDINAL_TEXT,
5403
+ ordinalText: LevelFormat.ORDINAL_TEXT,
5404
+ hex: LevelFormat.HEX,
5405
+ chicago: LevelFormat.CHICAGO,
5406
+ ideographDigital: LevelFormat.IDEOGRAPH__DIGITAL,
5407
+ japaneseCounting: LevelFormat.JAPANESE_COUNTING,
5408
+ aiueo: LevelFormat.AIUEO,
5409
+ iroha: LevelFormat.IROHA,
5410
+ decimalFullWidth: LevelFormat.DECIMAL_FULL_WIDTH,
5411
+ decimalHalfWidth: LevelFormat.DECIMAL_HALF_WIDTH,
5412
+ japaneseLegal: LevelFormat.JAPANESE_LEGAL,
5413
+ japaneseDigitalTenThousand: LevelFormat.JAPANESE_DIGITAL_TEN_THOUSAND,
5414
+ decimalEnclosedCircle: LevelFormat.DECIMAL_ENCLOSED_CIRCLE,
5415
+ decimalFullWidth2: LevelFormat.DECIMAL_FULL_WIDTH2,
5416
+ aiueoFullWidth: LevelFormat.AIUEO_FULL_WIDTH,
5417
+ irohaFullWidth: LevelFormat.IROHA_FULL_WIDTH,
5418
+ decimalZero: LevelFormat.DECIMAL_ZERO,
5419
+ ganada: LevelFormat.GANADA,
5420
+ chosung: LevelFormat.CHOSUNG,
5421
+ decimalEnclosedFullstop: LevelFormat.DECIMAL_ENCLOSED_FULLSTOP,
5422
+ decimalEnclosedParen: LevelFormat.DECIMAL_ENCLOSED_PARENTHESES,
5423
+ decimalEnclosedCircleChinese: LevelFormat.DECIMAL_ENCLOSED_CIRCLE_CHINESE,
5424
+ ideographEnclosedCircle: LevelFormat.IDEOGRAPH_ENCLOSED_CIRCLE,
5425
+ ideographTraditional: LevelFormat.IDEOGRAPH_TRADITIONAL,
5426
+ ideographZodiac: LevelFormat.IDEOGRAPH_ZODIAC,
5427
+ ideographZodiacTraditional: LevelFormat.IDEOGRAPH_ZODIAC_TRADITIONAL,
5428
+ taiwaneseCounting: LevelFormat.TAIWANESE_COUNTING,
5429
+ ideographLegalTraditional: LevelFormat.IDEOGRAPH_LEGAL_TRADITIONAL,
5430
+ taiwaneseCountingThousand: LevelFormat.TAIWANESE_COUNTING_THOUSAND,
5431
+ taiwaneseDigital: LevelFormat.TAIWANESE_DIGITAL,
5432
+ chineseCounting: LevelFormat.CHINESE_COUNTING,
5433
+ chineseLegalSimplified: LevelFormat.CHINESE_LEGAL_SIMPLIFIED,
5434
+ chineseCountingThousand: LevelFormat.CHINESE_COUNTING_THOUSAND,
5435
+ koreanDigital: LevelFormat.KOREAN_DIGITAL,
5436
+ koreanCounting: LevelFormat.KOREAN_COUNTING,
5437
+ koreanLegal: LevelFormat.KOREAN_LEGAL,
5438
+ koreanDigital2: LevelFormat.KOREAN_DIGITAL2,
5439
+ vietnameseCounting: LevelFormat.VIETNAMESE_COUNTING,
5440
+ russianLower: LevelFormat.RUSSIAN_LOWER,
5441
+ russianUpper: LevelFormat.RUSSIAN_UPPER,
5442
+ none: LevelFormat.NONE,
5443
+ numberInDash: LevelFormat.NUMBER_IN_DASH,
5444
+ hebrew1: LevelFormat.HEBREW1,
5445
+ hebrew2: LevelFormat.HEBREW2,
5446
+ arabicAlpha: LevelFormat.ARABIC_ALPHA,
5447
+ arabicAbjad: LevelFormat.ARABIC_ABJAD,
5448
+ hindiVowels: LevelFormat.HINDI_VOWELS,
5449
+ hindiConsonants: LevelFormat.HINDI_CONSONANTS,
5450
+ hindiNumbers: LevelFormat.HINDI_NUMBERS,
5451
+ hindiCounting: LevelFormat.HINDI_COUNTING,
5452
+ thaiLetters: LevelFormat.THAI_LETTERS,
5453
+ thaiNumbers: LevelFormat.THAI_NUMBERS,
5454
+ thaiCounting: LevelFormat.THAI_COUNTING
5455
+ };
5456
+ var ALIGNMENT_MAP = {
5457
+ start: AlignmentType3.START,
5458
+ end: AlignmentType3.END,
5459
+ left: AlignmentType3.LEFT,
5460
+ right: AlignmentType3.RIGHT,
5461
+ center: AlignmentType3.CENTER
5462
+ };
5463
+ function getLevelFormat(format2) {
5464
+ if (!format2) return LevelFormat.BULLET;
5465
+ return LEVEL_FORMAT_MAP[format2] || LevelFormat.BULLET;
5466
+ }
5467
+ function getAlignment2(alignment) {
5468
+ if (!alignment) return AlignmentType3.LEFT;
5469
+ return ALIGNMENT_MAP[alignment] || AlignmentType3.LEFT;
5470
+ }
5471
+ function createNumberingConfig(config) {
5472
+ const levels = [];
5473
+ for (const levelConfig of config.levels) {
5474
+ const format2 = getLevelFormat(levelConfig.format);
5475
+ const alignment = getAlignment2(levelConfig.alignment);
5476
+ const text = levelConfig.text || (format2 === LevelFormat.BULLET ? "\u2022" : `%${levelConfig.level + 1}.`);
5477
+ const baseIndent = levelConfig.indent?.left !== void 0 ? levelConfig.indent.left / 72 : 0.5 * (levelConfig.level + 1);
5478
+ const hangingIndent = levelConfig.indent?.hanging !== void 0 ? levelConfig.indent.hanging / 72 : 0.25;
5479
+ const level = {
5480
+ level: levelConfig.level,
5481
+ format: format2,
5482
+ text,
5483
+ alignment,
5484
+ style: {
5485
+ paragraph: {
5486
+ indent: {
5487
+ left: convertInchesToTwip(baseIndent),
5488
+ hanging: convertInchesToTwip(hangingIndent)
5489
+ }
5490
+ }
5491
+ },
5492
+ // Add start number if specified
5493
+ ...levelConfig.start !== void 0 && { start: levelConfig.start }
5494
+ };
5495
+ levels.push(level);
5496
+ }
5497
+ return {
5498
+ reference: config.reference,
5499
+ levels
5500
+ };
5501
+ }
5502
+ var NumberingRegistry = class {
5503
+ fallback = {
5504
+ configs: /* @__PURE__ */ new Map(),
5505
+ counter: 0
5506
+ };
5507
+ scopes = new AsyncLocalStorage4();
5508
+ get state() {
5509
+ return this.scopes.getStore() ?? this.fallback;
5510
+ }
5511
+ /** Run work with an isolated registry that follows its async call chain. */
5512
+ runScoped(callback) {
5513
+ return this.scopes.run({ configs: /* @__PURE__ */ new Map(), counter: 0 }, callback);
5514
+ }
5515
+ /**
5516
+ * Register a numbering configuration
5517
+ */
5518
+ register(config) {
5519
+ const reference = config.reference;
5520
+ this.state.configs.set(reference, config);
5521
+ return reference;
5522
+ }
5523
+ /**
5524
+ * Generate a unique reference ID
5525
+ */
5526
+ generateReference(prefix = "list") {
5527
+ return `${prefix}-${++this.state.counter}`;
5528
+ }
5529
+ /**
5530
+ * Get all registered configurations as an array suitable for INumberingOptions
5531
+ */
5532
+ getAll() {
5533
+ return Array.from(this.state.configs.values());
5534
+ }
5535
+ /**
5536
+ * Clear all configurations
5537
+ */
5538
+ clear() {
5539
+ this.state.configs.clear();
5540
+ this.state.counter = 0;
5541
+ }
5542
+ /**
5543
+ * Check if a reference exists
5544
+ */
5545
+ has(reference) {
5546
+ return this.state.configs.has(reference);
5547
+ }
5548
+ /**
5549
+ * Get a configuration by reference
5550
+ */
5551
+ get(reference) {
5552
+ return this.state.configs.get(reference);
5553
+ }
5554
+ };
5555
+ var globalNumberingRegistry = new NumberingRegistry();
5556
+
5602
5557
  // src/components/paragraph.ts
5603
- init_numberingConfig();
5604
5558
  function parseMarkdownList(text) {
5605
5559
  const lines = text.split("\n");
5606
5560
  const items = [];
@@ -5726,7 +5680,6 @@ function renderParagraphComponent(component, theme, themeName) {
5726
5680
  }
5727
5681
 
5728
5682
  // src/components/list.ts
5729
- init_numberingConfig();
5730
5683
  function createLevelsFromSimplifiedProps(props) {
5731
5684
  const levels = [];
5732
5685
  let format2;
@@ -6150,17 +6103,22 @@ async function renderTableComponent(component, theme, themeName) {
6150
6103
 
6151
6104
  // src/components/section.ts
6152
6105
  import { Paragraph as Paragraph4, BookmarkStart, BookmarkEnd } from "docx";
6153
- function generateSectionBookmarkId() {
6154
- const linkId = Math.floor(Math.random() * 1e6);
6106
+ function generateSectionBookmarkId(context) {
6107
+ const custom = context.custom ??= {};
6108
+ const state = custom.sectionBookmarks ??= {
6109
+ next: 1
6110
+ };
6111
+ const ordinal = state.next++;
6112
+ const linkId = 1e6 + ordinal;
6155
6113
  return {
6156
- id: `_Section_${linkId}_${Date.now()}`,
6114
+ id: `_NestedSection_${ordinal}`,
6157
6115
  linkId
6158
6116
  };
6159
6117
  }
6160
6118
  async function renderSectionComponent(component, theme, themeName, context) {
6161
6119
  if (!isSectionComponent(component)) return [];
6162
6120
  const elements = [];
6163
- const { id: sectionBookmarkId, linkId: bookmarkLinkId } = generateSectionBookmarkId();
6121
+ const { id: sectionBookmarkId, linkId: bookmarkLinkId } = generateSectionBookmarkId(context);
6164
6122
  elements.push(
6165
6123
  new Paragraph4({
6166
6124
  children: [new BookmarkStart(sectionBookmarkId, bookmarkLinkId)],
@@ -6789,13 +6747,23 @@ function getAlignment3(alignment) {
6789
6747
  }
6790
6748
  }
6791
6749
  async function renderDocument(structure, layout, options) {
6750
+ return runWithGenerationDate(
6751
+ structure.metadata.date,
6752
+ () => globalBookmarkRegistry.runScoped(
6753
+ () => globalRevisionIdRegistry.runScoped(
6754
+ () => globalNumberingRegistry.runScoped(
6755
+ () => renderDocumentScoped(structure, layout, options)
6756
+ )
6757
+ )
6758
+ )
6759
+ );
6760
+ }
6761
+ async function renderDocumentScoped(structure, layout, options) {
6792
6762
  if (options?.cache) {
6793
6763
  initializeComponentCache(options.cache);
6794
6764
  } else if (!options?.bypassCache) {
6795
6765
  initializeComponentCache();
6796
6766
  }
6797
- const { globalNumberingRegistry: globalNumberingRegistry2 } = await Promise.resolve().then(() => (init_numberingConfig(), numberingConfig_exports));
6798
- globalNumberingRegistry2.clear();
6799
6767
  const sections = [];
6800
6768
  const context = createRenderContext(
6801
6769
  structure,
@@ -6852,7 +6820,8 @@ async function renderDocument(structure, layout, options) {
6852
6820
  structure.themeName,
6853
6821
  context,
6854
6822
  sectionOrdinal,
6855
- closeBookmark
6823
+ closeBookmark,
6824
+ options?.bypassCache === true
6856
6825
  );
6857
6826
  if (layoutSection.isUserSection) {
6858
6827
  sectionBookmarkCounter++;
@@ -6861,7 +6830,7 @@ async function renderDocument(structure, layout, options) {
6861
6830
  sections.push(rendered);
6862
6831
  }
6863
6832
  }
6864
- const numberingConfigs = globalNumberingRegistry2.getAll();
6833
+ const numberingConfigs = globalNumberingRegistry.getAll();
6865
6834
  return new Document({
6866
6835
  styles: createWordStyles(structure.theme, structure.language),
6867
6836
  sections,
@@ -7029,7 +6998,7 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
7029
6998
  }
7030
6999
  return elements;
7031
7000
  }
7032
- async function renderSection(section, theme, themeName, context, sectionOrdinal, closeBookmark) {
7001
+ async function renderSection(section, theme, themeName, context, sectionOrdinal, closeBookmark, bypassCache = false) {
7033
7002
  const elements = [];
7034
7003
  const isFirstLayoutOfUserSection = section.isUserSection;
7035
7004
  const sharedLinkId = section.belongsToUserSection && sectionOrdinal ? sectionOrdinal : void 0;
@@ -7067,8 +7036,7 @@ async function renderSection(section, theme, themeName, context, sectionOrdinal,
7067
7036
  theme,
7068
7037
  themeName,
7069
7038
  sectionContext,
7070
- false
7071
- // Don't bypass cache
7039
+ bypassCache
7072
7040
  );
7073
7041
  elements.push(...rendered);
7074
7042
  }
@@ -7218,6 +7186,75 @@ async function resolveDocumentFonts(document, theme, fonts, warnings) {
7218
7186
  // src/core/generator.ts
7219
7187
  import { applyExportMode, scopedThemeName } from "@json-to-office/shared";
7220
7188
 
7189
+ // src/utils/packageDocument.ts
7190
+ import AdmZip2 from "adm-zip";
7191
+ import { Packer } from "docx";
7192
+
7193
+ // src/utils/fixFloatingImageIds.ts
7194
+ import AdmZip from "adm-zip";
7195
+ function fixFloatingImageIdsInBuffer(buffer) {
7196
+ const zip = new AdmZip(buffer);
7197
+ const documentEntry = zip.getEntry("word/document.xml");
7198
+ if (!documentEntry) {
7199
+ throw new Error("document.xml not found in DOCX");
7200
+ }
7201
+ let idCounter = 1;
7202
+ const documentXml = documentEntry.getData().toString("utf8").replace(/<wp:docPr\s+id="(\d+)"/g, () => {
7203
+ const newId = idCounter++;
7204
+ return `<wp:docPr id="${newId}"`;
7205
+ });
7206
+ zip.updateFile(documentEntry, Buffer.from(documentXml, "utf8"));
7207
+ return zip.toBuffer();
7208
+ }
7209
+
7210
+ // src/utils/packageDocument.ts
7211
+ var DEFAULT_GENERATION_DATE = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
7212
+ function resolveGenerationDate(options) {
7213
+ if (options?.generatedAt !== void 0) {
7214
+ const date = new Date(options.generatedAt);
7215
+ if (Number.isNaN(date.getTime())) {
7216
+ throw new RangeError("generatedAt must be a valid date");
7217
+ }
7218
+ if (date.getUTCFullYear() < 1980) {
7219
+ throw new RangeError(
7220
+ "generatedAt must be on or after 1980-01-01 for ZIP compatibility"
7221
+ );
7222
+ }
7223
+ return date;
7224
+ }
7225
+ return options?.deterministic === false ? /* @__PURE__ */ new Date() : new Date(DEFAULT_GENERATION_DATE);
7226
+ }
7227
+ function toDosTime(date) {
7228
+ const dosDate = (date.getUTCFullYear() - 1980 & 127) << 9 | date.getUTCMonth() + 1 << 5 | date.getUTCDate();
7229
+ const dosTime = date.getUTCHours() << 11 | date.getUTCMinutes() << 5 | date.getUTCSeconds() >> 1;
7230
+ return (dosDate << 16 | dosTime) >>> 0;
7231
+ }
7232
+ function canonicalizeDocxBuffer(buffer, generatedAt = DEFAULT_GENERATION_DATE) {
7233
+ const zip = new AdmZip2(buffer);
7234
+ const isoTimestamp = generatedAt.toISOString();
7235
+ const coreProperties = zip.getEntry("docProps/core.xml");
7236
+ if (coreProperties) {
7237
+ const normalized = coreProperties.getData().toString("utf8").replace(
7238
+ /(<dcterms:(?:created|modified)\b[^>]*>)[^<]*(<\/dcterms:(?:created|modified)>)/g,
7239
+ `$1${isoTimestamp}$2`
7240
+ );
7241
+ zip.updateFile(coreProperties, Buffer.from(normalized, "utf8"));
7242
+ }
7243
+ const zipTimestamp = toDosTime(generatedAt);
7244
+ for (const entry of zip.getEntries()) {
7245
+ entry.header.timeval = zipTimestamp;
7246
+ }
7247
+ return zip.toBuffer();
7248
+ }
7249
+ async function packageDocument(document, options) {
7250
+ const packed = await Packer.toBuffer(document);
7251
+ const fixed = fixFloatingImageIdsInBuffer(packed);
7252
+ if (options?.deterministic === false) {
7253
+ return fixed;
7254
+ }
7255
+ return canonicalizeDocxBuffer(fixed, resolveGenerationDate(options));
7256
+ }
7257
+
7221
7258
  // src/json/parser.ts
7222
7259
  import {
7223
7260
  JsonDocumentParser,
@@ -7389,7 +7426,8 @@ async function generateDocument(document, options) {
7389
7426
  options?.customThemes,
7390
7427
  options?.services,
7391
7428
  options?.fonts,
7392
- options?.warnings
7429
+ options?.warnings,
7430
+ resolveGenerationDate(options)
7393
7431
  );
7394
7432
  }
7395
7433
  async function generateFromConfig(props, components, options) {
@@ -7400,7 +7438,7 @@ async function generateFromConfig(props, components, options) {
7400
7438
  };
7401
7439
  return await generateDocument(reportComponent, options);
7402
7440
  }
7403
- async function generateDocumentWithCustomThemes(documentIn, customThemes, services, fonts, warnings) {
7441
+ async function generateDocumentWithCustomThemes(documentIn, customThemes, services, fonts, warnings, generationDate) {
7404
7442
  let document = documentIn;
7405
7443
  let themeName = document.props.theme || "minimal";
7406
7444
  let theme;
@@ -7438,7 +7476,12 @@ async function generateDocumentWithCustomThemes(documentIn, customThemes, servic
7438
7476
  }
7439
7477
  }
7440
7478
  await resolveDocumentFonts(document, theme, fonts, warnings);
7441
- const structure = await processDocument(document, theme, themeName);
7479
+ const structure = await processDocument(
7480
+ document,
7481
+ theme,
7482
+ themeName,
7483
+ generationDate
7484
+ );
7442
7485
  const layout = applyLayout(structure.sections, theme, themeName);
7443
7486
  const renderedDocument = await renderDocument(structure, layout, {
7444
7487
  bypassCache: false,
@@ -7486,7 +7529,8 @@ async function generateDocumentFromJson(jsonConfig, options) {
7486
7529
  options?.customThemes,
7487
7530
  options?.services,
7488
7531
  options?.fonts,
7489
- options?.warnings
7532
+ options?.warnings,
7533
+ resolveGenerationDate(options)
7490
7534
  );
7491
7535
  }
7492
7536
  function validateJsonSchema(jsonConfig) {
@@ -7494,11 +7538,11 @@ function validateJsonSchema(jsonConfig) {
7494
7538
  }
7495
7539
  async function generateBufferFromJson(jsonConfig, options) {
7496
7540
  const document = await generateDocumentFromJson(jsonConfig, options);
7497
- return await Packer.toBuffer(document);
7541
+ return packageDocument(document, options);
7498
7542
  }
7499
7543
  async function generateAndSaveFromJson(jsonConfig, filename, options) {
7500
7544
  const document = await generateDocumentFromJson(jsonConfig, options);
7501
- await saveDocument(document, filename);
7545
+ await saveDocument(document, filename, options);
7502
7546
  }
7503
7547
  async function generateDocumentFromFile(filePath, options) {
7504
7548
  const jsonDefinition = await loadJsonDefinition(filePath);
@@ -7506,25 +7550,19 @@ async function generateDocumentFromFile(filePath, options) {
7506
7550
  }
7507
7551
  async function generateBufferFromFile(filePath, options) {
7508
7552
  const document = await generateDocumentFromFile(filePath, options);
7509
- return await Packer.toBuffer(document);
7553
+ return packageDocument(document, options);
7510
7554
  }
7511
7555
  async function generateAndSaveFromFile(inputFilePath, outputFilePath, options) {
7512
7556
  const document = await generateDocumentFromFile(inputFilePath, options);
7513
- await saveDocument(document, outputFilePath);
7557
+ await saveDocument(document, outputFilePath, options);
7514
7558
  }
7515
- async function saveDocument(document, filename) {
7516
- const buffer = await Packer.toBuffer(document);
7559
+ async function saveDocument(document, filename, options) {
7560
+ const buffer = await packageDocument(document, options);
7517
7561
  writeFileSync(filename, buffer);
7518
- try {
7519
- const { fixFloatingImageIds: fixFloatingImageIds2 } = await Promise.resolve().then(() => (init_fixFloatingImageIds(), fixFloatingImageIds_exports));
7520
- await fixFloatingImageIds2(filename);
7521
- } catch (error) {
7522
- console.warn("Failed to fix floating image IDs (non-critical):", error);
7523
- }
7524
7562
  }
7525
- async function generateAndSave(document, filename) {
7526
- const generatedDocument = await generateDocument(document);
7527
- await saveDocument(generatedDocument, filename);
7563
+ async function generateAndSave(document, filename, options) {
7564
+ const generatedDocument = await generateDocument(document, options);
7565
+ await saveDocument(generatedDocument, filename, options);
7528
7566
  }
7529
7567
  var DocumentGenerator = {
7530
7568
  generate: generateDocument,
@@ -7854,7 +7892,6 @@ async function runExample(example, options = {}) {
7854
7892
 
7855
7893
  // src/plugin/createDocumentGenerator.ts
7856
7894
  init_styles();
7857
- import { Packer as Packer2 } from "docx";
7858
7895
  import { applyExportMode as applyExportMode2, scopedThemeName as scopedThemeName2 } from "@json-to-office/shared";
7859
7896
 
7860
7897
  // src/plugin/version-resolver.ts
@@ -8251,7 +8288,10 @@ function createBuilderImpl(state) {
8251
8288
  debug: state.debug,
8252
8289
  enableCache: state.enableCache,
8253
8290
  services: state.services,
8254
- fonts: state.fonts
8291
+ fonts: state.fonts,
8292
+ validation: state.validation,
8293
+ deterministic: state.deterministic,
8294
+ generatedAt: state.generatedAt
8255
8295
  };
8256
8296
  return createBuilderImpl(
8257
8297
  newState
@@ -8343,10 +8383,20 @@ function createBuilderImpl(state) {
8343
8383
  };
8344
8384
  const [modedDoc] = normalizeDocument(processedDocument);
8345
8385
  await resolveDocumentFonts(modedDoc, modedTheme, state.fonts, warnings);
8346
- const structure = await processDocument(modedDoc, modedTheme, themeName);
8386
+ const packageOptions = {
8387
+ deterministic: options?.deterministic ?? state.deterministic,
8388
+ generatedAt: options?.generatedAt ?? state.generatedAt
8389
+ };
8390
+ const structure = await processDocument(
8391
+ modedDoc,
8392
+ modedTheme,
8393
+ themeName,
8394
+ resolveGenerationDate(packageOptions)
8395
+ );
8347
8396
  const layout = applyLayout(structure.sections, modedTheme, themeName);
8348
8397
  const generatedDocument = await renderDocument(structure, layout, {
8349
- services: state.services
8398
+ services: state.services,
8399
+ bypassCache: !state.enableCache
8350
8400
  });
8351
8401
  const preservedDefinition = preserveSet ? {
8352
8402
  ...mode.doc,
@@ -8372,7 +8422,10 @@ function createBuilderImpl(state) {
8372
8422
  standardDefinition,
8373
8423
  preservedDefinition
8374
8424
  } = await generate(document, options);
8375
- const buffer = await Packer2.toBuffer(doc);
8425
+ const buffer = await packageDocument(doc, {
8426
+ deterministic: options?.deterministic ?? state.deterministic,
8427
+ generatedAt: options?.generatedAt ?? state.generatedAt
8428
+ });
8376
8429
  return { buffer, warnings, standardDefinition, preservedDefinition };
8377
8430
  }
8378
8431
  async function generateFile(document, outputPath, options) {
@@ -8471,7 +8524,9 @@ function createDocumentGenerator(options) {
8471
8524
  enableCache: options.enableCache ?? false,
8472
8525
  services: options.services,
8473
8526
  fonts: options.fonts,
8474
- validation: options.validation
8527
+ validation: options.validation,
8528
+ deterministic: options.deterministic ?? true,
8529
+ generatedAt: options.generatedAt
8475
8530
  };
8476
8531
  return createBuilderImpl(initialState);
8477
8532
  }